From d393a109948678a8fff9d8b3a801dad6bb4b9334 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Mon, 11 May 2026 13:11:52 +0200 Subject: [PATCH] confd: skip neighbor/address flush for interfaces in container netns When an interface has been handed off to a container it lives in another netns, so `ip neigh/addr flush dev FOO` fails on the host. The failure aborts dagger, and since interfaces_change() runs before containers_change() in change_cb(), the container delete path is never reached -- the stale container keeps the interface trapped in its netns, breaking the next reconfiguration. Guard both the neighbor and address flush exit scripts with `if_nametoindex(ifname)` -- true exactly when the interface is in the host netns, false for both "in a container" and "already gone". This replaces the pre-existing `!cni_find(ifname) && if_nametoindex( ifname)` guard at the addr site: cni_find() added no information for this check and would popen(container find) for nothing when the interface had been deleted entirely. Also harden wrap() in /usr/sbin/container so a stale setup pidfile doesn't short-circuit Finit's stop attempt -- kill the setup PID and still ask podman to stop the container. Fixes #1493 Signed-off-by: Joachim Wiberg --- board/common/rootfs/usr/sbin/container | 7 ++++--- src/confd/src/ip.c | 26 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/board/common/rootfs/usr/sbin/container b/board/common/rootfs/usr/sbin/container index 4bc99d9a..f79353d7 100755 --- a/board/common/rootfs/usr/sbin/container +++ b/board/common/rootfs/usr/sbin/container @@ -652,7 +652,9 @@ wrap() if [ "$cmd" = "stop" ]; then # The setup phase may run forever in the background trying to fetch - # the image. It saves its PID in /run/containers/${name}.pid + # the image. It saves its PID in /run/containers/${name}.pid. Kill + # any in-flight setup, then fall through to podman stop -- a stale + # pidfile is not proof the container isn't running. if [ -f "$pidfile" ]; then pid=$(cat "$pidfile") @@ -663,10 +665,9 @@ wrap() fi rm -f "$pidfile" - return 0 fi - # Only the 'podman stop' command takes -i and --timeout + # Only the 'podman stop' command takes -i (ignore missing) and --timeout args="-i --timeout $timeout" fi diff --git a/src/confd/src/ip.c b/src/confd/src/ip.c index a83c1017..463b3b1e 100644 --- a/src/confd/src/ip.c +++ b/src/confd/src/ip.c @@ -295,11 +295,18 @@ int netdag_gen_ip_neighs(struct dagger *net, FILE *ip, const char *proto, int err = 0; if (!ipconf || !lydx_is_enabled(ipconf, "enabled")) { - FILE *fp = dagger_fopen_net_exit(net, ifname, NETDAG_EXIT_PRE, "flush-neigh.sh"); + FILE *fp; + + /* Skip if interface is currently in another netns (container) see #1493 */ + if (!if_nametoindex(ifname)) + return 0; + + fp = dagger_fopen_net_exit(net, ifname, NETDAG_EXIT_PRE, "flush-neigh.sh"); if (fp) { fprintf(fp, "ip -%c neigh flush dev %s nud permanent\n", proto[3], ifname); fclose(fp); } + return 0; } @@ -323,15 +330,18 @@ int netdag_gen_ip_addrs(struct dagger *net, FILE *ip, const char *proto, const char *ifname = lydx_get_cattr(dif, "name"); if (!ipconf || !lydx_is_enabled(ipconf, "enabled")) { - if (!cni_find(ifname) && if_nametoindex(ifname)) { - FILE *fp; + FILE *fp; - fp = dagger_fopen_net_exit(net, ifname, NETDAG_EXIT_PRE, "flush.sh"); - if (fp) { - fprintf(fp, "ip -%c addr flush dev %s\n", proto[3], ifname); - fclose(fp); - } + /* Skip if interface is currently in another netns (container) see #1493 */ + if (!if_nametoindex(ifname)) + return 0; + + fp = dagger_fopen_net_exit(net, ifname, NETDAG_EXIT_PRE, "flush.sh"); + if (fp) { + fprintf(fp, "ip -%c addr flush dev %s\n", proto[3], ifname); + fclose(fp); } + return 0; }