diff --git a/conf.c b/conf.c index 943526d..cc08de3 100644 --- a/conf.c +++ b/conf.c @@ -630,8 +630,23 @@ static void conf_ip(struct ctx *c) v4 = v6 = IP_VERSION_PROBE; } - if (!c->ifi4 && !c->ifi6) - c->ifi4 = c->ifi6 = nl_get_ext_if(&v4, &v6); + if (v4 != IP_VERSION_DISABLED) { + if (!c->ifi4) + c->ifi4 = nl_get_ext_if(AF_INET); + if (!c->ifi4) { + warn("No external routable interface for IPv4"); + v4 = IP_VERSION_DISABLED; + } + } + + if (v6 != IP_VERSION_DISABLED) { + if (!c->ifi6) + c->ifi6 = nl_get_ext_if(AF_INET6); + if (!c->ifi6) { + warn("No external routable interface for IPv6"); + v6 = IP_VERSION_DISABLED; + } + } if (v4 != IP_VERSION_DISABLED) { if (!c->gw4) diff --git a/netlink.c b/netlink.c index 66a95e4..8ad6a0c 100644 --- a/netlink.c +++ b/netlink.c @@ -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; } diff --git a/netlink.h b/netlink.h index 261904e..5ce5037 100644 --- a/netlink.h +++ b/netlink.h @@ -7,7 +7,7 @@ #define NETLINK_H int nl_sock_init(const struct ctx *c); -unsigned int nl_get_ext_if(int *v4, int *v6); +unsigned int nl_get_ext_if(sa_family_t af); void nl_route(int ns, unsigned int ifi, sa_family_t af, void *gw); void nl_addr(int ns, unsigned int ifi, sa_family_t af, void *addr, int *prefix_len, void *addr_l); diff --git a/test/dhcp/passt b/test/dhcp/passt index f45227a..11e0eb3 100644 --- a/test/dhcp/passt +++ b/test/dhcp/passt @@ -17,6 +17,7 @@ htools ip jq sed tr head test Interface name gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' check [ -n "__IFNAME__" ] test DHCP: address @@ -49,7 +50,7 @@ check [ "__SEARCH__" = "__HOST_SEARCH__" ] test DHCPv6: address guest /sbin/dhclient -6 __IFNAME__ gout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[] | select(.scope == "global").local' +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' check [ "__ADDR6__" = "__HOST_ADDR6__" ] test DHCPv6: route diff --git a/test/dhcp/pasta b/test/dhcp/pasta index 65b1d42..076ec8d 100644 --- a/test/dhcp/pasta +++ b/test/dhcp/pasta @@ -35,8 +35,9 @@ check [ __MTU__ = 65520 ] test DHCPv6: address ns /sbin/dhclient -6 --no-pid __IFNAME__ +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local' +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' check [ __ADDR6__ = __HOST_ADDR6__ ] test DHCPv6: route diff --git a/test/ndp/passt b/test/ndp/passt index d6b4c40..8ef15e7 100644 --- a/test/ndp/passt +++ b/test/ndp/passt @@ -17,13 +17,13 @@ htools ip jq sipcalc grep cut test Interface name gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' guest ip link set dev __IFNAME__ up && sleep 2 -hout HOST_IFNAME ip -j -4 route show|jq -rM '.[] | select(.dst == "default").dev' +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").dev' check [ -n "__IFNAME__" ] test SLAAC: prefix gout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local' gout PREFIX6 sipcalc __ADDR6__/64 | grep prefix | cut -d' ' -f4 -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[] | select(.scope == "global").local' +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4 check [ "__PREFIX6__" = "__HOST_PREFIX6__" ] diff --git a/test/two_guests/basic b/test/two_guests/basic index f7c016d..e226178 100644 --- a/test/two_guests/basic +++ b/test/two_guests/basic @@ -19,6 +19,7 @@ test Interface names g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' g2out IFNAME2 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' check [ -n "__IFNAME1__" ] check [ -n "__IFNAME2__" ] @@ -40,7 +41,7 @@ guest1 /sbin/dhclient -6 __IFNAME1__ guest2 /sbin/dhclient -6 __IFNAME2__ g1out ADDR1_6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local' g2out ADDR2_6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME2__").addr_info[] | select(.prefixlen == 128).local' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[] | select(.scope == "global").local' +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] check [ "__ADDR2_6__" = "__HOST_ADDR6__" ]