On Thu, Aug 15, 2024 at 12:54:27AM +0200, Stefano Brivio wrote: > As soon as we bring up the interface, the Linux kernel will set up a > link-local address for it, so we can fetch it and start using right > away, if we need a link-local address to communicate to the container > before we see any traffic coming from it. > > Signed-off-by: Stefano Brivio > --- > netlink.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ > netlink.h | 1 + > pasta.c | 7 +++++++ > 3 files changed, 55 insertions(+) > > diff --git a/netlink.c b/netlink.c > index 4b49de1..3b37087 100644 > --- a/netlink.c > +++ b/netlink.c > @@ -836,6 +836,53 @@ int nl_addr_get(int s, unsigned int ifi, sa_family_t af, > return status; > } > > +/** > + * nl_addr_get_ll() - Get first IPv6 link-local address for a given interface > + * @s: Netlink socket > + * @ifi: Interface index in outer network namespace > + * @addr: Link-local address to fill > + * > + * Return: 0 on success, negative error code on failure > + */ > +int nl_addr_get_ll(int s, unsigned int ifi, void *addr) Given this is explicitly for IPv6, I don't see a reason not to use (struct in6_addr *addr) for greater type safety. > +{ > + struct req_t { > + struct nlmsghdr nlh; > + struct ifaddrmsg ifa; > + } req = { > + .ifa.ifa_family = AF_INET6, > + .ifa.ifa_index = ifi, > + }; > + struct nlmsghdr *nh; > + bool found = false; > + char buf[NLBUFSIZ]; > + ssize_t status; > + uint32_t seq; > + > + seq = nl_send(s, &req, RTM_GETADDR, NLM_F_DUMP, sizeof(req)); > + nl_foreach_oftype(nh, status, s, buf, seq, RTM_NEWADDR) { > + struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nh); > + struct rtattr *rta; > + size_t na; > + > + if (ifa->ifa_index != ifi || ifa->ifa_scope != RT_SCOPE_LINK || > + found) > + continue; > + > + for (rta = IFA_RTA(ifa), na = IFA_PAYLOAD(nh); RTA_OK(rta, na); > + rta = RTA_NEXT(rta, na)) { > + if (rta->rta_type != IFA_ADDRESS) > + continue; > + > + if (!found) { > + memcpy(addr, RTA_DATA(rta), RTA_PAYLOAD(rta)); > + found = true; > + } > + } > + } > + return status; > +} > + > /** > * nl_add_set() - Set IP addresses for given interface and address family > * @s: Netlink socket > diff --git a/netlink.h b/netlink.h > index 66a44ad..bdfdef0 100644 > --- a/netlink.h > +++ b/netlink.h > @@ -19,6 +19,7 @@ int nl_addr_get(int s, unsigned int ifi, sa_family_t af, > void *addr, int *prefix_len, void *addr_l); > int nl_addr_set(int s, unsigned int ifi, sa_family_t af, > const void *addr, int prefix_len); > +int nl_addr_get_ll(int s, unsigned int ifi, void *addr); > int nl_addr_set_ll_nodad(int s, unsigned int ifi); > int nl_addr_dup(int s_src, unsigned int ifi_src, > int s_dst, unsigned int ifi_dst, sa_family_t af); > diff --git a/pasta.c b/pasta.c > index 838bbb3..cebf54f 100644 > --- a/pasta.c > +++ b/pasta.c > @@ -340,6 +340,13 @@ void pasta_ns_conf(struct ctx *c) > } > > if (c->ifi6) { > + rc = nl_addr_get_ll(nl_sock_ns, c->pasta_ifi, > + &c->ip6.addr_ll_seen); > + if (rc < 0) { > + die("Can't fetch LL address from namespace: %s", > + strerror(-rc)); Again, we can generally cope with not having an addr_ll_seen initially, so I think a warn() would make more sense. > + } > + > rc = nl_addr_set_ll_nodad(nl_sock_ns, c->pasta_ifi); > if (rc < 0) { > die("Can't disable DAD for LL in namespace: %s", -- 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