netlink, pasta: Fetch link-local address from namespace interface once it's up

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 <sbrivio@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Stefano Brivio 2024-08-15 00:33:24 +02:00
parent 74e508cf79
commit d6f0220731
3 changed files with 55 additions and 0 deletions

View file

@ -796,6 +796,53 @@ int nl_addr_get(int s, unsigned int ifi, sa_family_t af,
return status; 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, struct in6_addr *addr)
{
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 * nl_add_set() - Set IP addresses for given interface and address family
* @s: Netlink socket * @s: Netlink socket

View file

@ -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); void *addr, int *prefix_len, void *addr_l);
int nl_addr_set(int s, unsigned int ifi, sa_family_t af, int nl_addr_set(int s, unsigned int ifi, sa_family_t af,
const void *addr, int prefix_len); const void *addr, int prefix_len);
int nl_addr_get_ll(int s, unsigned int ifi, struct in6_addr *addr);
int nl_addr_set_ll_nodad(int s, unsigned int ifi); int nl_addr_set_ll_nodad(int s, unsigned int ifi);
int nl_addr_dup(int s_src, unsigned int ifi_src, int nl_addr_dup(int s_src, unsigned int ifi_src,
int s_dst, unsigned int ifi_dst, sa_family_t af); int s_dst, unsigned int ifi_dst, sa_family_t af);

View file

@ -340,6 +340,13 @@ void pasta_ns_conf(struct ctx *c)
} }
if (c->ifi6) { if (c->ifi6) {
rc = nl_addr_get_ll(nl_sock_ns, c->pasta_ifi,
&c->ip6.addr_ll_seen);
if (rc < 0) {
warn("Can't get LL address from namespace: %s",
strerror(-rc));
}
rc = nl_addr_set_ll_nodad(nl_sock_ns, c->pasta_ifi); rc = nl_addr_set_ll_nodad(nl_sock_ns, c->pasta_ifi);
if (rc < 0) { if (rc < 0) {
warn("Can't set nodad for LL in namespace: %s", warn("Can't set nodad for LL in namespace: %s",