netlink: Ignore routes to link-local addresses for selecting interface

Since f919dc7a4b ("conf, netlink: Don't require a default route to
start"), and since 639fdf06ed ("netlink: Fix selection of template
interface") less buggily, we haven't required a default route on the host
in order to operate.  Instead, if we lack a default route we'll pick an
interface with any route, as long as there's only one such interface.  If
there's more than one, we don't have a good criterion to pick, so we give
up with an informational message.

Paul Holzinger pointed out that this code considers it ambiguous even if
all but one of the interfaces has only routes to link-local addresses
(fe80::/10).  A route to link-local addresses isn't really useful from
pasta's point of view, so ignore them instead.  This removes a misleading
message in many cases, and a spurious failure in some cases.

Suggested-by: Paul Holzinger <pholzing@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2024-03-21 15:04:49 +11:00 committed by Stefano Brivio
parent 67a6258918
commit 97e8b33f87
2 changed files with 23 additions and 1 deletions

9
ip.h
View file

@ -24,6 +24,11 @@
#define IN4ADDR_ANY_INIT \ #define IN4ADDR_ANY_INIT \
{ .s_addr = htonl_constant(INADDR_ANY) } { .s_addr = htonl_constant(INADDR_ANY) }
#define IN4_IS_ADDR_LINKLOCAL(a) \
((ntohl(((struct in_addr *)(a))->s_addr) >> 16) == 0xa9fe)
#define IN4_IS_PREFIX_LINKLOCAL(a, len) \
((len) >= 16 && IN4_IS_ADDR_LINKLOCAL(a))
#define L2_BUF_IP4_INIT(proto) \ #define L2_BUF_IP4_INIT(proto) \
{ \ { \
.version = 4, \ .version = 4, \
@ -40,6 +45,10 @@
#define L2_BUF_IP4_PSUM(proto) ((uint32_t)htons_constant(0x4500) + \ #define L2_BUF_IP4_PSUM(proto) ((uint32_t)htons_constant(0x4500) + \
(uint32_t)htons(0xff00 | (proto))) (uint32_t)htons(0xff00 | (proto)))
#define IN6_IS_PREFIX_LINKLOCAL(a, len) \
((len) >= 10 && IN6_IS_ADDR_LINKLOCAL(a))
#define L2_BUF_IP6_INIT(proto) \ #define L2_BUF_IP6_INIT(proto) \
{ \ { \
.priority = 0, \ .priority = 0, \

View file

@ -33,6 +33,7 @@
#include "util.h" #include "util.h"
#include "passt.h" #include "passt.h"
#include "log.h" #include "log.h"
#include "ip.h"
#include "netlink.h" #include "netlink.h"
/* Netlink expects a buffer of at least 8kiB or the system page size, /* Netlink expects a buffer of at least 8kiB or the system page size,
@ -270,6 +271,7 @@ unsigned int nl_get_ext_if(int s, sa_family_t af)
seq = nl_send(s, &req, RTM_GETROUTE, NLM_F_DUMP, sizeof(req)); seq = nl_send(s, &req, RTM_GETROUTE, NLM_F_DUMP, sizeof(req));
nl_foreach_oftype(nh, status, s, buf, seq, RTM_NEWROUTE) { nl_foreach_oftype(nh, status, s, buf, seq, RTM_NEWROUTE) {
struct rtmsg *rtm = (struct rtmsg *)NLMSG_DATA(nh); struct rtmsg *rtm = (struct rtmsg *)NLMSG_DATA(nh);
const void *dst = NULL;
unsigned thisifi = 0; unsigned thisifi = 0;
if (rtm->rtm_family != af) if (rtm->rtm_family != af)
@ -284,12 +286,23 @@ unsigned int nl_get_ext_if(int s, sa_family_t af)
rtnh = (struct rtnexthop *)RTA_DATA(rta); rtnh = (struct rtnexthop *)RTA_DATA(rta);
thisifi = rtnh->rtnh_ifindex; thisifi = rtnh->rtnh_ifindex;
} else if (rta->rta_type == RTA_DST) {
dst = RTA_DATA(rta);
} }
} }
if (!thisifi) if (!thisifi)
continue; /* No interface for this route */ continue; /* No interface for this route */
/* Skip routes to link-local addresses */
if (af == AF_INET && dst &&
IN4_IS_PREFIX_LINKLOCAL(dst, rtm->rtm_dst_len))
continue;
if (af == AF_INET6 && dst &&
IN6_IS_PREFIX_LINKLOCAL(dst, rtm->rtm_dst_len))
continue;
if (rtm->rtm_dst_len == 0) { if (rtm->rtm_dst_len == 0) {
/* Default route */ /* Default route */
ndef++; ndef++;
@ -322,7 +335,7 @@ unsigned int nl_get_ext_if(int s, sa_family_t af)
} }
if (!nany) if (!nany)
info("No interfaces with %s routes", af_name(af)); info("No interfaces with usable %s routes", af_name(af));
return 0; return 0;
} }