Skip to content

feat(vm): add IPAM for additional network interfaces#2612

Open
hardcoretime wants to merge 9 commits into
mainfrom
feat/vm/additional-network-ipam
Open

feat(vm): add IPAM for additional network interfaces#2612
hardcoretime wants to merge 9 commits into
mainfrom
feat/vm/additional-network-ipam

Conversation

@hardcoretime

@hardcoretime hardcoretime commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Description

Add IPAM (IP Address Management) for virtual machine additional network interfaces, integrating with the SDN module's IPAM capabilities (address pools, IPAddress resources, DHCP delivery).

Two allocation modes are supported for additional networks that have an IPAM pool (spec.ipam.ipAddressPoolRef):

  1. Automatic (DHCP): when ipAddressName is not set in .spec.networks[], the VM controller creates an SDN IPAddress (type Auto) bound to the VM via ownerReferences and passes it to SDN. SDN allocates an address from the pool and delivers it to the guest OS via DHCP. The address is stable across VM restarts and migrations (bound to the VM, not the ephemeral pod).

  2. Static: when ipAddressName is set, the controller uses a user-provided IPAddress resource (type Static). The address is determined by the user.

If an additional network does not have an IPAM pool, the feature is not enabled — the interface operates in L2-only mode with manual IP configuration in the guest OS (as before).

The allocated IP address is reflected in status.networks[].ipAddress.

Why do we need it, and what problem does it solve?

Previously, additional network interfaces operated at L2 only — IP addresses had to be configured manually inside the guest OS (e.g., via Cloud-Init). This led to:

  • Address conflicts between manually configured IPs and SDN-allocated addresses on the same interface.
  • No declarative way to request a specific IP for an additional network (unlike Main network via VirtualMachineIPAddress).
  • No IP visibility in VM status for additional interfaces.
  • VMs hanging in Starting when network configuration was invalid — CNI d8-sdn fails hard on missing IPAddress, blocking pod creation.

This PR solves these by having the VM controller manage IPAddress resources for additional networks (analogous to VirtualMachineIPAddress for the Main network), with resilient startup (skip problematic interfaces) and reactive reconciliation (watch IPAddress to provision interfaces when addresses become available).

What is the expected result?

  • A VM with an additional network that has an IPAM pool receives an IP automatically via DHCP (auto mode) or uses a user-specified static IP (ipAddressName).
  • The IP is visible in status.networks[].ipAddress.
  • The IP is stable across VM restarts and live migrations.
  • If an additional network is misconfigured (e.g., ipAddressName references a non-existent IPAddress, or the network has no pool), the VM starts without that interface and reports the error in the NetworkReady condition.
  • Changing ipAddressName (add/remove/switch auto↔static) is applied live without pod recreation or VM restart.
  • Creating an IPAddress after VM start triggers reconciliation via watcher — the interface is attached automatically (hotplug).

Checklist

  • The code is covered by unit tests.
  • e2e tests passed.
  • Documentation updated according to the changes.
  • Changes were tested in the Kubernetes cluster manually.

Changelog entries

section: vm
type: feature
summary: "Add IPAM for additional network interfaces: automatic (DHCP) and static IP allocation via SDN IPAddress resources."

@hardcoretime hardcoretime added this to the v1.10.0 milestone Jul 8, 2026
@hardcoretime hardcoretime force-pushed the feat/vm/additional-network-ipam branch from 920d0e4 to d5acfb3 Compare July 9, 2026 01:01
@hardcoretime hardcoretime added the e2e/run Run e2e test on cluster of PR author label Jul 9, 2026
@deckhouse-BOaTswain

deckhouse-BOaTswain commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Workflow has started.
Follow the progress here: Workflow Run

The target step completed with status: failure.

@deckhouse-BOaTswain deckhouse-BOaTswain removed the e2e/run Run e2e test on cluster of PR author label Jul 9, 2026
@hardcoretime hardcoretime force-pushed the feat/vm/additional-network-ipam branch from d5acfb3 to bc615b4 Compare July 9, 2026 08:13
Roman Sysoev and others added 9 commits July 10, 2026 19:31
…network IPAM

Add the `ipAddressName` field to `NetworksSpec` to enable static IP
address assignment for additional network interfaces via user-provided
`IPAddress` resources (SDN module). When empty, the controller uses
automatic mode (DHCP).

Add the `ipAddress` field to `NetworksStatus` to reflect the actual IP
address allocated for each additional network interface by SDN.

Update CRD manifests (EN and RU) with the new fields and descriptions.

Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
…richment

Add ipaddress.go with helpers for SDN IPAddress lifecycle management:
EnsureSDNIPAddress (create Auto with ownerRef on VM, idempotent),
FindSDNIPAddress (by VM label + networkRef), GetSDNIPAddressStatus
(address, phase, Allocated/NoFreeAddress), SDNIPAddressExists, and
IsIPAddressNameUsedByAnotherVM (conflict detection).

Add HasIPAM to check if a network has an IPAM pool configured.

Add EnrichWithIPAM: for each additional interface with a pool, resolve
ipAddressNames (auto: find controller-created IPAddress; static:
validate user IPAddress exists, is allocated, and not used by another
VM), set ipAssignmentMode=DHCP, and skip problematic interfaces.

Add WillProvisionInterface to determine if an interface will be
included in networks-spec (mirrors skip logic for NetworkReady).

Update CreateNetworkSpec to propagate IPAddressNames from vm.spec.

Add unit tests for all new helpers.

Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
Add IPAddressHandler: creates auto-IPAddress (Auto, ownerRef on VM,
label virtual-machine-uid) for additional networks with an IPAM pool
when ipAddressName is not set. Garbage-collects auto-IPAddress when
a network is removed from spec. Classifies transient vs configuration
errors (transient: return error; configuration: skip interface).

Update NetworkInterfaceHandler:
- collectIPAMErrors: aggregate IPAM errors (static without pool,
  static IPAddress missing/not allocated/conflicting, auto IPAddress
  not allocated) into NetworkReady with IPAddress phase and reason.
- WillProvisionInterface: filter desired networks to skip problematic
  interfaces, avoiding misleading "waiting for SDN" messages.
- extractIPAddressesFromPods: parse ipAddressConfigs from
  networks-status into status.networks[].ipAddress.

Update SyncKvvmHandler: call EnrichWithIPAM in both MakeKVVMFromVMSpec
(KVVM template) and patchPodNetworkAnnotation (pod patch).

Update NetworkWatcher: watch SDN IPAddress by ownerRef (auto) and by
name reference in vm.spec.networks[].ipAddressName (static) to enqueue
VM when Allocated condition changes.

Fix isOnlyNetworkIDAutofillChange to include IPAddressName comparison
so changing ipAddressName is treated as a hotpluggable network change.

Register IPAddressHandler in vm_controller.go after MACHandler.

Add unit and integration tests for IPAM controller logic.

Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
Add get/list/watch/create/update/patch/delete permissions for
ipaddresses.network.deckhouse.io to the virtualization-controller
ClusterRole. Required for IPAddressHandler to manage SDN IPAddress
resources for VM additional networks.

Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
Add ClusterIPAddressPool (e2e-ipam-pool, 192.168.200.0/24) and bind it
to cn-4006-for-e2e-test via spec.ipam.ipAddressPoolRef in both nightly
and release e2e pipelines.

Update SDN precheck to verify that cn-4006 has an IPAM pool configured.
If the pool is missing, the precheck fails with a command to create it.

Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
Add helpers in util/sdn.go for SDN IPAddress CRUD via dynamic client:
CreateSDNIPAddress, GetSDNIPAddress, GetSDNIPAddressAddress,
DeleteSDNIPAddress, ListSDNIPAddresses, DeleteAllSDNIPAddresses.

Add ipam_additional_networks.go with 7 test cases:
- Auto (DHCP): IP allocated from pool, delivered via DHCP to guest OS,
  stable across VM restart
- Static (ipAddressName): user-provided IPAddress, stable across restart
- Skip problematic: VM with missing IPAddress on network without pool
  starts without the interface, error in NetworkReady
- Skip to working via watcher: IPAddress created after VM start triggers
  reconciliation via watcher, interface attached without restart
- Hotplug static to auto: switch modes without pod recreation
- Hotplug auto to static: switch modes without pod recreation
- Live migration: auto IP preserved across migration

Each test verifies no AwaitingRestartToApplyConfiguration condition and
pod UID stability for hotplug scenarios.

Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
Update vmop/restore.go to use cn-4006 (with pool) with auto (DHCP)
cloud-init instead of static IP. CheckAdditionalNetworkInterface now
reads the IP from status.networks[].ipAddress and verifies it is
present in the guest OS. Add CheckIPAMAfterRestore to verify the
auto-IPAddress is recreated after VM restore.

Switch additional_network_interfaces.go to use cn-4007 (no pool) for
tests with manual IP configuration, since cn-4006 now has an IPAM
pool. Remove redundant NoPrecheck label.

Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
Add a new section "IPAM for additional network interfaces" to both
USER_GUIDE.md (EN) and USER_GUIDE.ru.md (RU). Describe:

- Two modes: automatic (DHCP, controller-managed IPAddress with
  ownerRef on VM) and static (user-provided IPAddress via
  ipAddressName)
- How the mode is determined by the ipAddressName field
- Examples of VM spec with auto and static configuration
- Example of creating a static IPAddress resource
- Updated status example showing ipAddress for additional interfaces
- Warning about avoiding manual static IP config when IPAM is enabled
- Warning about hotplugged interfaces requiring guest OS configuration
  (NetworkManager or udev rule) to automatically bring up new
  interfaces and request DHCP
- Note about skipped interfaces when pool is exhausted or IPAddress
  is not yet allocated

Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
Signed-off-by: Vladislav Panfilov <vladislav.panfilov@flant.com>
@hardcoretime hardcoretime force-pushed the feat/vm/additional-network-ipam branch from c5ed5e8 to 6fa53cb Compare July 10, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants