Skip to content

incus/dhcp: default routes and multiple DHCP clients for OCI containers#2414

Merged
stgraber merged 1 commit intolxc:mainfrom
xzkutor:main
Aug 22, 2025
Merged

incus/dhcp: default routes and multiple DHCP clients for OCI containers#2414
stgraber merged 1 commit intolxc:mainfrom
xzkutor:main

Conversation

@xzkutor
Copy link
Copy Markdown

@xzkutor xzkutor commented Aug 21, 2025

Problem

When multiple DHCP clients attempt to install an IPv4 default route into the main table, netlink.RouteAdd can fail with EEXIST. This leads to noisy errors and nondeterministic behavior regarding which interface "owns" the default route.

Summary of changes

  1. internal/server/ip:
  • Made Route.List device-optional: when DevName is empty or unresolved, the OIF filter is cleared and routes across all devices are returned.
  • Introduced a single builder netlinkRoute(mode) to construct netlink.Route for both apply (add/replace/delete) and query (list) paths.
  1. incus/dhcp (DHCPv4 path in main_forknet.go):
  • Introduce a policy to keep a single default route in the main table, owned by the lexicographically smallest interface name among candidates.
  • Inspect current main table routes using ip.Route.List to find the current default route owner.
  • If the new interface name sorts before the current owner (or there is no owner), install/replace the default route via ip.Route.Replace. Otherwise, skip installing the default route for this interface.
  • Mark installed routes with Proto="dhcp".
  • Use Replace rather than Add to make route installation idempotent across renewals and avoid EEXIST.

Behavioral impact

  • Route.List now returns routes across all devices when DevName is empty (previously, it always filtered by device).
  • Add, Replace, Delete, and Flush continue to require a valid device and behave as before.

This PR resolves #2403

* Problem

  When multiple DHCP clients attempt to install an IPv4 default route into the main table,
netlink.RouteAdd can fail with EEXIST. This leads to noisy errors and nondeterministic
behavior regarding which interface "owns" the default route.

* Summary of changes

1. internal/server/ip:
  - Made Route.List device-optional: when DevName is empty or unresolved, the OIF filter
    is cleared and routes across all devices are returned.
  - Introduced a single builder netlinkRoute(mode) to construct netlink.Route for both
    apply (add/replace/delete) and query (list) paths.
2. incus/dhcp (DHCPv4 path in main_forknet.go):
  - Introduce a policy to keep a single default route in the main table, owned by the
    lexicographically smallest interface name among candidates.
  - Inspect current main table routes using ip.Route.List to find the current default
    route owner.
  - If the new interface name sorts before the current owner (or there is no owner),
    install/replace the default route via ip.Route.Replace. Otherwise, skip installing
    the default route for this interface.
  - Mark installed routes with Proto="dhcp".
  - Use Replace rather than Add to make route installation idempotent across renewals
    and avoid EEXIST.

* Behavioral impact:

  - Route.List now returns routes across all devices when DevName is empty (previously, it
    always filtered by device).
  - Add, Replace, Delete, and Flush continue to require a valid device and behave as before.

Signed-off-by: Andrey Mozharovsky <[email protected]>
@stgraber stgraber merged commit 5e171b4 into lxc:main Aug 22, 2025
34 of 38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Default routes and multiple DHCP clients for OCI containers

2 participants