Every cloud provider reserves IPs from each subnet. AWS takes 5. Azure takes 5. GCP takes 4. OCI takes 3. We do the math correctly so your capacity plans actually deploy.
Every cloud reserves a different number of IPs per subnet: AWS and Azure reserve 5, GCP reserves 4, OCI reserves 3. Here is a tiny helper, in six languages, that returns real usable-host capacity for any prefix on any provider. Example shown: a /26 on each of the four major clouds.
RESERVED = {"AWS": 5, "Azure": 5, "GCP": 4, "OCI": 3}
def usable(prefix, provider):
total = 1 << (32 - prefix)
return max(0, total - RESERVED[provider])
prefix = 26
print(f"Usable hosts in a /{prefix} by provider:")
for p in ["AWS", "Azure", "GCP", "OCI"]:
print(f" {p+':':<7} {usable(prefix, p)}")package main
import "fmt"
var reserved = map[string]int{
"AWS": 5, "Azure": 5, "GCP": 4, "OCI": 3,
}
func usable(prefix int, provider string) int {
total := 1 << (32 - prefix)
u := total - reserved[provider]
if u < 0 {
u = 0
}
return u
}
func main() {
prefix := 26
fmt.Printf("Usable hosts in a /%d by provider:\n", prefix)
for _, p := range []string{"AWS", "Azure", "GCP", "OCI"} {
fmt.Printf(" %-7s %d\n", p+":", usable(prefix, p))
}
}const RESERVED = { AWS: 5, Azure: 5, GCP: 4, OCI: 3 };
function usable(prefix, provider) {
const total = 2 ** (32 - prefix);
return Math.max(0, total - RESERVED[provider]);
}
const prefix = 26;
console.log(`Usable hosts in a /${prefix} by provider:`);
for (const p of ['AWS', 'Azure', 'GCP', 'OCI']) {
console.log(` ${(p + ':').padEnd(7)} ${usable(prefix, p)}`);
}#!/usr/bin/env bash
# Usable hosts per cloud provider for a given prefix.
declare -A RESERVED=( [AWS]=5 [Azure]=5 [GCP]=4 [OCI]=3 )
PREFIX=26
TOTAL=$(( 1 << (32 - PREFIX) ))
echo "Usable hosts in a /${PREFIX} by provider:"
for P in AWS Azure GCP OCI; do
u=$(( TOTAL - RESERVED[$P] ))
(( u < 0 )) && u=0
printf " %-7s %d\n" "${P}:" "$u"
doneimport java.util.LinkedHashMap;
import java.util.Map;
public class CloudHosts {
static final Map<String, Integer> RESERVED = new LinkedHashMap<>() {{
put("AWS", 5); put("Azure", 5); put("GCP", 4); put("OCI", 3);
}};
static long usable(int prefix, String provider) {
long total = 1L << (32 - prefix);
return Math.max(0, total - RESERVED.get(provider));
}
public static void main(String[] args) {
int prefix = 26;
System.out.printf("Usable hosts in a /%d by provider:%n", prefix);
for (String p : RESERVED.keySet()) {
System.out.printf(" %-7s %d%n", p + ":", usable(prefix, p));
}
}
}#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef struct { const char *name; int reserved; } provider_t;
int main(void) {
provider_t providers[] = {
{"AWS", 5}, {"Azure", 5}, {"GCP", 4}, {"OCI", 3}
};
int prefix = 26;
uint64_t total = 1ULL << (32 - prefix);
printf("Usable hosts in a /%d by provider:\n", prefix);
for (int i = 0; i < 4; i++) {
long long u = (long long)total - providers[i].reserved;
if (u < 0) u = 0;
char label[16];
snprintf(label, sizeof(label), "%s:", providers[i].name);
printf(" %-7s %lld\n", label, u);
}
return 0;
}Usable hosts in a /26 by provider: AWS: 59 Azure: 59 GCP: 60 OCI: 61
AWS reserves the network address, the VPC router, the DNS server, one future-use IP, and the broadcast address. That's 5 IPs gone from every subnet you create. The minimum subnet size in AWS is /28 (16 addresses, 11 usable after the reservation).
Azure also reserves 5 IPs per subnet, but the breakdown differs: network, default gateway, two DNS servers, and broadcast. Azure's minimum subnet size depends on the service: most allow /29, but specialty subnets (App Gateway, Bastion) require larger sizes (/27 or larger).
Yes. GCP reserves 4 IPs per subnet: network, default gateway, second-to-last address, and broadcast. Minimum subnet size is /29. The smaller overhead matters in dense subnet designs.
OCI reserves only 3 IPs (network, gateway, broadcast) — the most efficient of the major clouds for small subnets. Kubernetes pod CIDRs don't have a fixed reservation pattern; pods receive IPs from the cluster CIDR via the CNI plugin, with the network and broadcast typically off-limits.