diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2022-07-22 15:31:13 +1000 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2022-07-30 21:57:50 +0200 |
commit | 06abfcf6d95762976d37aa5721c16802c649efd4 (patch) | |
tree | 38b2b7936c0a107015706dd3feadc2021edab13a /netlink.c | |
parent | 3eaf9f532021326a47f70046b05854d8b1819825 (diff) | |
download | passt-06abfcf6d95762976d37aa5721c16802c649efd4.tar passt-06abfcf6d95762976d37aa5721c16802c649efd4.tar.gz passt-06abfcf6d95762976d37aa5721c16802c649efd4.tar.bz2 passt-06abfcf6d95762976d37aa5721c16802c649efd4.tar.lz passt-06abfcf6d95762976d37aa5721c16802c649efd4.tar.xz passt-06abfcf6d95762976d37aa5721c16802c649efd4.tar.zst passt-06abfcf6d95762976d37aa5721c16802c649efd4.zip |
Separately locate external interfaces for IPv4 and IPv6
Now that the back end allows passt/pasta to use different external
interfaces for IPv4 and IPv6, use that to do the right thing in the case
that the host has IPv4 and IPv6 connectivity via different interfaces.
If the user hasn't explicitly chosen an interface, separately search for
a suitable external interface for each protocol.
As a bonus, this substantially simplifies the external interface probe. It
also eliminates a subtle confusing case where in some circumstances we
would pick the first interface in interface index order, and sometimes in
order of routes returned from netlink. On some network configurations that
could cause tests to fail, because the logic in the tests was subtly
different (it always used route order).
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'netlink.c')
-rw-r--r-- | netlink.c | 79 |
1 files changed, 7 insertions, 72 deletions
@@ -126,13 +126,13 @@ static int nl_req(int ns, char *buf, const void *req, ssize_t len) } /** - * nl_get_ext_if() - Get interface index supporting IP versions being probed - * @v4: Probe IPv4 support, set to ENABLED or DISABLED on return - * @v6: Probe IPv4 support, set to ENABLED or DISABLED on return + * nl_get_ext_if() - Get interface index supporting IP version being probed + * @af: Address family (AF_INET or AF_INET6) to look for connectivity + * for. * * Return: interface index, 0 if not found */ -unsigned int nl_get_ext_if(int *v4, int *v6) +unsigned int nl_get_ext_if(sa_family_t af) { struct { struct nlmsghdr nlh; struct rtmsg rtm; } req = { .nlh.nlmsg_type = RTM_GETROUTE, @@ -143,32 +143,14 @@ unsigned int nl_get_ext_if(int *v4, int *v6) .rtm.rtm_table = RT_TABLE_MAIN, .rtm.rtm_scope = RT_SCOPE_UNIVERSE, .rtm.rtm_type = RTN_UNICAST, + .rtm.rtm_family = af, }; - unsigned int i, first_v4 = 0, first_v6 = 0; - uint8_t has_v4[PAGE_SIZE * 8 / 8] = { 0 }; /* See __dev_alloc_name() */ - uint8_t has_v6[PAGE_SIZE * 8 / 8] = { 0 }; /* in kernel */ struct nlmsghdr *nh; struct rtattr *rta; struct rtmsg *rtm; char buf[BUFSIZ]; - long *word, tmp; - uint8_t *vmap; ssize_t n; size_t na; - int *v; - - if (*v4 == IP_VERSION_PROBE) { - v = v4; - req.rtm.rtm_family = AF_INET; - vmap = has_v4; - } else if (*v6 == IP_VERSION_PROBE) { -v6: - v = v6; - req.rtm.rtm_family = AF_INET6; - vmap = has_v6; - } else { - return 0; - } if ((n = nl_req(0, buf, &req, sizeof(req))) < 0) return 0; @@ -178,7 +160,7 @@ v6: for ( ; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) { rtm = (struct rtmsg *)NLMSG_DATA(nh); - if (rtm->rtm_dst_len || rtm->rtm_family != req.rtm.rtm_family) + if (rtm->rtm_dst_len || rtm->rtm_family != af) continue; for (rta = RTM_RTA(rtm), na = RTM_PAYLOAD(nh); RTA_OK(rta, na); @@ -190,57 +172,10 @@ v6: ifi = *(unsigned int *)RTA_DATA(rta); - if (*v4 == IP_VERSION_DISABLED || - *v6 == IP_VERSION_DISABLED) { - *v = IP_VERSION_ENABLED; - return ifi; - } - - if (v == v4 && !first_v4) - first_v4 = ifi; - - if (v == v6 && !first_v6) - first_v6 = ifi; - - bitmap_set(vmap, ifi); + return ifi; } } - if (v == v4 && *v6 == IP_VERSION_PROBE) { - req.nlh.nlmsg_seq = nl_seq++; - goto v6; - } - - word = (long *)has_v4; - for (i = 0; i < ARRAY_SIZE(has_v4) / sizeof(long); i++, word++) { - tmp = *word; - while ((n = ffsl(tmp))) { - int ifi = i * sizeof(long) * 8 + n - 1; - - if (!first_v4) - first_v4 = ifi; - - tmp &= ~(1UL << (n - 1)); - if (bitmap_isset(has_v6, ifi)) { - *v4 = *v6 = IP_VERSION_ENABLED; - return ifi; - } - } - } - - if (first_v4) { - *v4 = IP_VERSION_ENABLED; - *v6 = IP_VERSION_DISABLED; - return first_v4; - } - - if (first_v6) { - *v4 = IP_VERSION_DISABLED; - *v6 = IP_VERSION_ENABLED; - return first_v6; - } - - err("No external routable interface for any IP protocol"); return 0; } |