Skip to main content
Infrahub provides a full-featured IPAM system for managing IP addresses, prefixes, and namespaces with automatic hierarchy reconciliation.

IPAM Hierarchy

Infrahub IPAM uses a parent-child hierarchy:
Namespace: default
├── 10.0.0.0/8 (parent)
│   ├── 10.0.0.0/16 (child)
│   │   ├── 10.0.1.0/24 (child)
│   │   │   ├── 10.0.1.1/32 (IP address)
│   │   │   ├── 10.0.1.2/32 (IP address)
│   │   │   └── 10.0.1.3/32 (IP address)
│   │   └── 10.0.2.0/24 (child)
│   └── 10.1.0.0/16 (child)
The IPAM reconciler automatically maintains this hierarchy when you create, update, or delete prefixes.

IP Namespaces

Namespaces provide isolation for overlapping IP space (e.g., multi-tenant, VRFs, environments).

Creating a Namespace

  1. Navigate to IPAMNamespaces
  2. Click Add Namespace
  3. Set Name and Description
  4. Click Save
The default namespace is created automatically during Infrahub initialization.

IP Prefixes

Prefixes represent network subnets (e.g., 10.0.1.0/24, 2001:db8::/32).

Creating a Prefix

  1. Navigate to IPAMPrefixes
  2. Click Add Prefix
  3. Set:
    • Prefix: CIDR notation (e.g., 10.0.1.0/24)
    • IP Namespace: Select namespace
    • Status: Active, reserved, deprecated, etc.
    • Member Type: Prefix or pool
    • Description: Purpose of the prefix
  4. Click Save
The IPAM reconciler automatically sets the parent-child relationships.

IPAM Reconciliation

The IpamReconciler automatically maintains the parent-child hierarchy:
from infrahub.core.ipam.reconciler import IpamReconciler
import ipaddress

reconciler = IpamReconciler(db=db, branch=branch)

# Reconcile after creating/updating a prefix
await reconciler.reconcile(
    ip_value=ipaddress.ip_network("10.0.1.0/24"),
    namespace=namespace_id,
    node_uuid=prefix_id
)
Reconciliation:
  1. Finds the closest parent prefix (longest prefix match)
  2. Sets the parent relationship
  3. Updates is_top_level flag
  4. Moves orphaned children to the new parent
  5. Updates children and ip_addresses relationships

Prefix Queries

Find prefixes by various criteria:
query {
  IpamIPPrefix(
    prefix__value: "10.0.1.0/24"
    ip_namespace: { name: { value: "default" } }
  ) {
    edges {
      node {
        id
        prefix { value }
        parent {
          id
          prefix { value }
        }
        children {
          edges {
            node {
              prefix { value }
            }
          }
        }
        ip_addresses {
          edges {
            node {
              address { value }
            }
          }
        }
      }
    }
  }
}

IP Addresses

IP addresses are specific IPs within prefixes (e.g., 10.0.1.5/32).

Creating an IP Address

  1. Navigate to IPAMIP Addresses
  2. Click Add IP Address
  3. Set:
    • Address: IP with prefix length (e.g., 10.0.1.5/32)
    • IP Namespace: Select namespace
    • Status: Active, reserved, etc.
    • Description: What uses this IP
  4. Click Save
The IPAM reconciler automatically links the IP to its parent prefix.

Assigning IPs to Interfaces

Link IP addresses to device interfaces:
mutation {
  IpamIPAddressUpdate(
    data: {
      id: "<ip-address-uuid>"
      interface: { id: "<interface-uuid>" }
    }
  ) {
    ok
  }
}
Or create the IP with the interface:
mutation {
  IpamIPAddressCreate(
    data: {
      address: { value: "10.0.1.5/32" }
      ip_namespace: { hfid: ["default"] }
      interface: { id: "<interface-uuid>" }
    }
  ) {
    ok
    object {
      id
    }
  }
}

Resource Allocator

The IPAMResourceAllocator finds the next available prefix or IP address.

Allocating Prefixes

from infrahub.core.ipam.resource_allocator import IPAMResourceAllocator
import ipaddress

allocator = IPAMResourceAllocator(
    db=db,
    namespace=namespace,
    branch=branch,
    branch_agnostic=True  # Search across all branches
)

# Get next available /24 from 10.0.0.0/16
parent_prefix = ipaddress.ip_network("10.0.0.0/16")
next_prefix = await allocator.get_next_prefix(
    ip_prefix=parent_prefix,
    target_prefix_length=24
)

print(f"Next available /24: {next_prefix}")
# Output: 10.0.1.0/24 (if 10.0.0.0/24 is already used)
The allocator:
  1. Queries all child prefixes using IPPrefixSubnetFetchFree
  2. Calculates gaps in the address space
  3. Returns the first available prefix of the requested length

Allocating IP Addresses

from infrahub.core.ipam.resource_allocator import IPAMResourceAllocator
import ipaddress

allocator = IPAMResourceAllocator(db=db, namespace=namespace, branch=branch)

# Get next available IP from 10.0.1.0/24
prefix = ipaddress.ip_network("10.0.1.0/24")
next_ip = await allocator.get_next_address(ip_prefix=prefix)

print(f"Next available IP: {next_ip}")
# Output: 10.0.1.1 (skips network address 10.0.1.0)
By default, the allocator skips:
  • Network address (first IP)
  • Broadcast address (last IP)
For pools where these are usable:
next_ip = await allocator.get_next_address(
    ip_prefix=prefix,
    is_pool=True  # Allow network and broadcast
)

IPv6 Support

The allocator handles IPv6’s 128-bit address space using binary string operations:
import ipaddress

# Allocate IPv6 prefix
parent = ipaddress.ip_network("2001:db8::/32")
next_prefix = await allocator.get_next_prefix(
    ip_prefix=parent,
    target_prefix_length=48
)

# Allocate IPv6 address
prefix = ipaddress.ip_network("2001:db8:1::/64")
next_ip = await allocator.get_next_address(ip_prefix=prefix)

Prefix Utilization

Query prefix utilization to monitor capacity:
query {
  IpamIPPrefix(prefix__value: "10.0.0.0/16") {
    edges {
      node {
        prefix { value }
        utilization
        children {
          count
        }
        ip_addresses {
          count
        }
      }
    }
  }
}
Or use the utilization API:
from infrahub.core.ipam.utilization import get_prefix_utilization

util = await get_prefix_utilization(
    db=db,
    prefix_id=prefix_id,
    branch=branch
)

print(f"Utilization: {util.percentage:.1f}%")
print(f"Used: {util.used} / {util.total}")

IPAM with Resource Manager

Combine IPAM with Resource Manager for automatic allocation (see Resource Manager guide):
# Create IP Prefix Pool
pool = await client.create(
    kind="CoreIPPrefixPool",
    name="Site Subnets",
    ip_namespace=namespace.id,
    default_prefix_length=24,
    resources=[parent_prefix.id]
)
await pool.save()

# Allocate from pool
prefix = await pool.get_resource(
    db=db,
    branch=branch,
    identifier="site-atl1",
    prefixlen=24
)
This creates the prefix and reconciles the IPAM hierarchy automatically.

Best Practices

  1. Use namespaces: Isolate IP space by tenant, environment, or VRF
  2. Let reconciliation work: Don’t manually set parent relationships
  3. Allocate top-down: Create large prefixes first, then subdivide
  4. Track assignments: Link IPs to interfaces for visibility
  5. Monitor utilization: Set alerts at 80% capacity
  6. Use pools: Automate allocation with Resource Manager pools
  7. Reserve network IPs: Mark .0 and .255 as reserved
  8. Document prefixes: Use description to explain purpose

Common Patterns

Hierarchical Allocation

# 1. Create regional prefix
regional = await client.create(
    kind="IpamIPPrefix",
    prefix="10.0.0.0/16",
    description="US East region"
)

# 2. Create site prefixes
site1 = await client.create(
    kind="IpamIPPrefix",
    prefix="10.0.1.0/24",
    description="Atlanta site"
)

# 3. Allocate IPs for devices
ip1 = await client.create(
    kind="IpamIPAddress",
    address="10.0.1.1/32",
    description="Gateway"
)
The reconciler automatically links: regional → site1 → ip1

Multi-Tenant IPAM

# Create namespace per tenant
for tenant in ["acme", "globex", "initech"]:
    ns = await client.create(
        kind="IpamNamespace",
        name=tenant
    )
    await ns.save()

    # Each tenant can use the same IP space
    prefix = await client.create(
        kind="IpamIPPrefix",
        prefix="10.0.0.0/16",
        ip_namespace=ns.id
    )
    await prefix.save()

Next Steps

Build docs developers (and LLMs) love