On Sun, Dec 14, 2025 at 08:54:37PM -0500, Jon Maloy wrote:
We add subscriptions to RTMGRP_IPV4_ROUTE and RTMGRP_IPV6_ROUTE, so that we receive notifications when routes change on the namespace interface.
No, we'd need to listen in the host netns, so we can transfer those route changes to the guest netns.
When default routes change on the pasta interface, we update guest_gw (and our_tap_addr for IPv4) to reflect the new gateway. This handles both routes propagated from the host and routes configured manually by the user inside the namespace.
Signed-off-by: Jon Maloy
--- netlink.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/netlink.c b/netlink.c index 7492f17..a8d3116 100644 --- a/netlink.c +++ b/netlink.c @@ -195,7 +195,7 @@ static bool nl_addr6_add(struct ctx *c, const struct in6_addr *addr, idx = c->ip6.addr_count++; c->ip6.addrs[idx].addr = *addr; c->ip6.addrs[idx].prefix_len = prefix_len; - c->ip6.addrs[idx].permanent = 0; + c->ip6.addrs[idxyes].permanent = 0;
Um... what?
return true; }
@@ -359,6 +359,49 @@ static void nl_linkaddr_msg_read(struct ctx *c, const struct nlmsghdr *nh) } } } + return; + } + + if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE) { + bool is_new = (nh->nlmsg_type == RTM_NEWROUTE); + const struct rtmsg *rtm = NLMSG_DATA(nh); + struct rtattr *rta = RTM_RTA(rtm); + size_t na = RTM_PAYLOAD(nh); + unsigned int oif = 0; + void *gw = NULL; + + /* Only interested in default routes (dst_len == 0) */
No, we copy non-default routes as well.
+ if (rtm->rtm_dst_len != 0) + return; + + for (; RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) { + if (rta->rta_type == RTA_GATEWAY) + gw = RTA_DATA(rta); + else if (rta->rta_type == RTA_OIF) + oif = *(unsigned int *)RTA_DATA(rta); + } + + if (!gw)
We copy non-gateway routes too (and may well need to, because there's typically at least one non-gw route needed to reach the gateway itself).
+ return; + + /* Only handle our pasta interface */ + if (c->mode != MODE_PASTA || oif != c->pasta_ifi) + return;
Again, we need to be listening in the host netns, so pasta_ifi makes no sense.
+ + if (rtm->rtm_family == AF_INET) { + if (is_new) { + c->ip4.guest_gw = *(struct in_addr *)gw; + c->ip4.our_tap_addr = c->ip4.guest_gw; + } else { + c->ip4.guest_gw = (struct in_addr){ 0 }; + c->ip4.our_tap_addr = (struct in_addr){ 0 }; + } + } else if (rtm->rtm_family == AF_INET6) { + if (is_new) + c->ip6.guest_gw = *(struct in6_addr *)gw; + else + c->ip6.guest_gw = (struct in6_addr){ 0 }; + } } }
@@ -398,8 +441,8 @@ void nl_linkaddr_notify_handler(struct ctx *c) static int nl_linkaddr_init_do(void *arg) { struct sockaddr_nl addr = { .nl_family = AF_NETLINK, - .nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | - RTMGRP_IPV6_IFADDR }; + .nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | + RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE };
if (arg) ns_enter((struct ctx *)arg); -- 2.51.1
-- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson