Skip to content

Commit

Permalink
netlink, pasta: Disable DAD for link-local addresses on namespace int…
Browse files Browse the repository at this point in the history
…erface

It makes no sense for a container or a guest to try and perform
duplicate address detection for their link-local address, as we'll
anyway not relay neighbour solicitations with an unspecified source
address.

While they perform duplicate address detection, the link-local address
is not usable, which prevents us from bringing up especially
containers and communicate with them right away via IPv6.

This is not enough to prevent DAD and reach the container right away:
we'll need a couple more patches.

As we send NLM_F_REPLACE requests right away, while we still have to
read out other addresses on the same socket, we can't use nl_do():
keep track of the last sequence we sent (last address we changed), and
deal with the answers to those NLM_F_REPLACE requests in a separate
loop, later.

Link: containers/podman#23561 (comment)
Signed-off-by: Stefano Brivio <[email protected]>
Reviewed-by: David Gibson <[email protected]>
  • Loading branch information
sbrivio-rh committed Aug 17, 2024
1 parent 0c74068 commit 74e508c
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
57 changes: 57 additions & 0 deletions netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,63 @@ int nl_route_dup(int s_src, unsigned int ifi_src,
return 0;
}

/**
* nl_addr_set_ll_nodad() - Set IFA_F_NODAD on IPv6 link-local addresses
* @s: Netlink socket
* @ifi: Interface index in target namespace
*
* Return: 0 on success, negative error code on failure
*/
int nl_addr_set_ll_nodad(int s, unsigned int ifi)
{
struct req_t {
struct nlmsghdr nlh;
struct ifaddrmsg ifa;
} req = {
.ifa.ifa_family = AF_INET6,
.ifa.ifa_index = ifi,
};
uint32_t seq, last_seq = 0;
ssize_t status, ret = 0;
struct nlmsghdr *nh;
char buf[NLBUFSIZ];

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)
continue;

ifa->ifa_flags |= IFA_F_NODAD;

for (rta = IFA_RTA(ifa), na = IFA_PAYLOAD(nh); RTA_OK(rta, na);
rta = RTA_NEXT(rta, na)) {
/* If 32-bit flags are used, add IFA_F_NODAD there */
if (rta->rta_type == IFA_FLAGS)
*(uint32_t *)RTA_DATA(rta) |= IFA_F_NODAD;
}

last_seq = nl_send(s, nh, RTM_NEWADDR, NLM_F_REPLACE,
nh->nlmsg_len);
}

if (status < 0)
ret = status;

for (seq = seq + 1; seq <= last_seq; seq++) {
nl_foreach(nh, status, s, buf, seq)
warn("netlink: Unexpected response message");

if (!ret && status < 0)
ret = status;
}

return ret;
}

/**
* nl_addr_get() - Get most specific global address, given interface and family
* @s: Netlink socket
Expand Down
1 change: 1 addition & 0 deletions netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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);
int nl_link_get_mac(int s, unsigned int ifi, void *mac);
Expand Down
6 changes: 6 additions & 0 deletions pasta.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,12 @@ void pasta_ns_conf(struct ctx *c)
}

if (c->ifi6) {
rc = nl_addr_set_ll_nodad(nl_sock_ns, c->pasta_ifi);
if (rc < 0) {
warn("Can't set nodad for LL in namespace: %s",
strerror(-rc));
}

if (c->ip6.no_copy_addrs) {
rc = nl_addr_set(nl_sock_ns, c->pasta_ifi,
AF_INET6, &c->ip6.addr, 64);
Expand Down

0 comments on commit 74e508c

Please sign in to comment.