VPCRouter Resource Kind
A VPCRouter is the gateway of one VPC: a network namespace on a gateway node with a veth into the VPC’s bridge and a veth into the uplink bridge, forwarding between them and masquerading outbound traffic. Public addresses for VMs in the VPC are bound to it with ExternalIP objects.
Routing is centralized on gateway nodes rather than distributed across compute hosts: public addresses only ever need announcing from the gateway, and a VM migration never moves a public IP — only the router’s DNAT target changes. Two routers on one node with the same private CIDR do not collide; each namespace keeps its own routes and its own nftables rule set.
Example Manifest
Section titled “Example Manifest”apiVersion: pivirt.hu/v1kind: VPCRoutermetadata: name: vpc-10042spec: inside: bridge: br-vpc-10042 # the VPC segment's bridge on this node address: 10.42.0.1/16 # this router's address — the VPC's gateway uplink: bridge: br-ext # the bridge carrying the public network address: 198.51.100.7/24 # the router's public address gateway: 198.51.100.1 masquerade: true mtu: 1450 # optional; 1450 when the inside is a VXLANSpecification Reference (spec)
Section titled “Specification Reference (spec)”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
netns |
string |
No | object name | Network namespace name |
inside.bridge |
string |
Yes | Host bridge the VPC-facing veth is enslaved to | |
inside.address |
string |
Yes | The router’s address on the VPC, in prefix notation; the VPC’s gateway | |
uplink.bridge |
string |
Yes | Host bridge the public-facing veth is enslaved to; must differ from inside.bridge |
|
uplink.address |
string |
Yes | The router’s public address, in prefix notation | |
uplink.gateway |
string |
No | Next hop for the default route; must be inside uplink.address’s prefix |
|
masquerade |
bool |
No | false |
Rewrite outbound source addresses to the uplink address |
mtu |
int |
No | MTU for both veth ends |
Inside the namespace the interfaces are always named inside and uplink, so ExternalIP and operator tooling know where to look.
Behaviour
Section titled “Behaviour”- Observe before write. Re-applying an unchanged router, or restoring it at boot, issues no mutating command: the namespace, both veth pairs, the addresses, forwarding, the default route and the masquerade rule are each checked first.
- Removal deletes the namespace — every interface, route and nftables rule inside it goes with it — and sweeps any stray host-side veth end.
- Bindings first. A router that still has
ExternalIPobjects naming its namespace refuses to be deleted; remove the bindings, or let the cascade do it. - Adoption. Namespaces on the host that no
VPCRouterdeclares are reported bypivirtctl get routersas adoptable and never touched.
CLI Examples
Section titled “CLI Examples”pivirtctl apply -f vpc-router.yamlpivirtctl get routerspivirtctl describe router vpc-10042pivirtctl delete router vpc-10042