Multi-Tenancy, VPCs & Isolation
How pools, subnets and floating IPs fit together, and what the director compiles them into on the hosts: concepts/multi-tenancy.
Address management in PiVirt has two tiers:
IPAMPool, IPAllocation) — which addresses exist, and who holds each one. Every VM interface in a VPC, every floating IP, every VPC router uplink and every host’s own address on a subnet is one IPAllocation. This page.NetworkSegment, DHCPLease) — how a guest learns the address it was given. See NetworkSegment and DHCPLease.# Operator-owned, cluster-scoped (no namespace). Floating IPs and VPC# router uplinks are claimed from it; gateway is the routers' next hop.apiVersion: pivirt.hu/v1kind: IPAMPoolmetadata: name: public-zone-aspec: cidr: 203.0.113.0/24 kind: public gateway: 203.0.113.1 exclude: [203.0.113.2, 203.0.113.3] zone: zone-a# Created by the director for every VPC ("vpc-<name>"), owned by it and# removed with it. Subnets carve ranges out of it; you never apply one.apiVersion: pivirt.hu/v1kind: IPAMPoolmetadata: name: vpc-main namespace: acme/prod ownerRefs: [{ kind: VPC, uid: <vpc uid>, controller: true }]spec: cidr: 10.42.0.0/16 kind: private# Named "<pool>-<a-b-c-d>" in the pool's namespace: the unique# (kind, namespace, name) index makes claiming an address atomic.apiVersion: pivirt.hu/v1kind: IPAllocationmetadata: name: vpc-main-10-42-1-7 namespace: acme/prod labels: { pivirt.hu/managed-by: director }spec: pool: vpc-main address: 10.42.1.7 owner: { kind: VirtualMachine, uid: <vm uuid>, name: web-01/0 }spec)| Field | Type | Required | Description |
|---|---|---|---|
cidr |
string |
Yes | IPv4 prefix the pool hands out |
kind |
string |
Yes | public (cluster-scoped, operator-made) or private (a VPC’s own range, in the tenant namespace) |
gateway |
string |
No | Never allocated; for public pools, the VPC routers’ default route |
exclude |
list[string] |
No | Addresses never handed out |
zone |
string |
No | Where a public pool is routable (recorded for placement, V7) |
Candidates are every host address of the prefix except the network and broadcast addresses, the gateway and the excludes, in order.
| Field | Type | Required | Description |
|---|---|---|---|
pool |
string |
Yes | Pool name; the allocation lives in the pool’s namespace |
address |
string |
Yes | The address held |
owner |
ObjectReference |
Yes | What holds it: VirtualMachine (name <hostname>/<nic index>), FloatingIP, VPC (name router) or Node (name <subnet>, the host’s own segment address) |
Allocations are never applied by hand: the director’s Allocate claims them, Release frees them, and an owner asking twice gets its existing address back.
flowchart TD
Req["Allocate(pool, within: subnet cidr, reserved: [gateway], owner)"] --> Skip["skip: taken, reserved, subnet network + broadcast"]
Skip --> Try["insert IPAllocation <pool>-<addr> (CreateOnly)"]
Try -->|created| Done["address is yours"]
Try -->|ErrObjectExists: lost the race| Next["next candidate"] --> Try
Try -->|no candidate left| Exhausted["ErrPoolExhausted"]
No counters, no locks: the store’s unique index is the arbiter, so two directors or two concurrent requests cannot hand out the same address, and a crash halfway leaves at most an allocation whose owner will ask again and get it back.
Multi-Tenancy, VPCs & Isolation
How pools, subnets and floating IPs fit together, and what the director compiles them into on the hosts: concepts/multi-tenancy.
GraphQL API
createVpc, createSubnet, claimFloatingIp, createPublicPool in the director’s GraphQL.
DHCPLease Reference
Host-level DHCP leases and static reservations in the DHCPLease Guide.
NetworkSegment Reference
Per-host segment addresses and delegated ranges in the NetworkSegment Guide.