ExternalIP (IPPool) Resource Kind
The ExternalIP resource (also addressed via the alias IPPool) binds public or external IP addresses, 1:1 NAT mappings, and granular port-forwarding rules from physical interfaces to guest virtual machines on private subnets.
With namespace set, the binding lives inside that VPCRouter’s network namespace — the address goes on the router’s uplink interface and the NAT rules into the router’s own nftables table — so two VPCs with the same private CIDR keep their bindings apart. Without it, the binding is in the host namespace: the single-host form. The director realizes a tenant’s FloatingIP as an ExternalIP on the VPC’s router.
Accepted Kind Aliases
Section titled “Accepted Kind Aliases”In pivirtctl commands, any of the following aliases are recognized:
ExternalIP, externalip, externalips, external-ip, external-ips, ippool, ippools, ip-pool, ip-pools, extip, extips, ip, ips.
Example Manifests
Section titled “Example Manifests”apiVersion: pivirt.hu/v1kind: ExternalIPmetadata: name: web-ingress-ip labels: role: ingress service: frontendspec: address: "203.0.113.50" prefixLen: 24 interface: eth0 internalIP: "192.168.100.10" portForwards: - protocol: tcp externalPort: 80 internalPort: 80 - protocol: tcp externalPort: 443 internalPort: 443apiVersion: pivirt.hu/v1kind: ExternalIPmetadata: name: web-01-publicspec: address: "203.0.113.51" internalIP: "10.42.1.10" namespace: vpc-10042 # the VPCRouter's netns; interface defaults to "uplink"Specification Reference (spec)
Section titled “Specification Reference (spec)”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
address |
string |
Yes | Public/external IPv4 address (pivirtd’s NAT table is IPv4; IPv6 prefixes are routed, not translated) | |
prefixLen |
int |
No | 32 |
Prefix length the address is configured with on the interface |
interface |
string |
Outside a namespace | uplink inside a router |
Interface to bind the address to |
internalIP |
string |
Yes | Target VM private IPv4 address | |
namespace |
string |
No | The VPCRouter network namespace holding the NAT table |
|
portForwards |
list |
No | [] |
Forward only these ports instead of the whole address |
portForwards[].protocol |
string |
No | tcp |
Transport protocol: tcp or udp |
portForwards[].externalPort |
int |
Yes | Port number on the external IP address | |
portForwards[].internalPort |
int |
Yes | Destination port number on the guest private IP |
Behaviour
Section titled “Behaviour”- 1:1 mode (no
portForwards): DNATaddress → internalIPinprerouting, SNATinternalIP → addressinpostrouting, and a forward accept for the guest. The guest’s outbound traffic leaves with the public address. - Port-forward mode: one DNAT and one forward accept per entry, plus the SNAT — only the listed ports reach the guest.
- Re-apply is honest. Rule comments carry a fingerprint of the spec: an unchanged binding is recognised as installed and issues nothing; a changed
internalIPdrops the old rules, installs the new ones, and flushes conntrack for the address so existing flows stop following the old target. - Removal deletes exactly this binding’s rules (by comment prefix), the address, and its conntrack entries — nothing else in the table is touched.
- A binding in a namespace fails with a clear message until that
VPCRouterexists on the host.
CLI Management Examples
Section titled “CLI Management Examples”# Apply external IP manifestpivirtctl apply -f external-ip.yaml
# List all external IPs (using IPPool alias)pivirtctl get ippools
# List using multi-word kind aliaspivirtctl get ip pools
# Inspect bindings and forward statuspivirtctl describe ippool web-ingress-ip
# Delete external IP (removes the address, its nftables rules and conntrack entries)pivirtctl delete ippool web-ingress-ip