BSD: Assume onlink flag on ifaces with only host addresses

The BSD kernel does not support the onlink flag and BIRD does not use
direct routes for next hop validation, instead depends on interface
address ranges. We would like to handle PtMP cases with only host
addresses configured, like:

  ifconfig wg0 192.168.0.10/32
  route add 192.168.0.4 -iface wg0
  route add 192.168.0.8 -iface wg0

To accept BIRD routes with onlink next-hop, like:

  route 192.168.42.0/24 via 192.168.0.4%wg0 onlink

BIRD would dismiss the route when receiving from the kernel, as the
next-hop 192.168.0.4 is not part of any interface subnet and onlink
flag is not kept by the BSD kernel.

The commit fixes this by assuming that for routes received from the
kernel, any next-hop is onlink on ifaces with only host addresses.

Thanks to Stefan Haller for the original patch.
This commit is contained in:
Ondrej Zajicek (work) 2021-12-27 19:10:35 +01:00
parent b9f38727a7
commit a39cd2cc0b

View file

@ -366,6 +366,30 @@ krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
} }
} }
/**
* krt_assume_onlink - check if routes on interface are considered onlink
* @iface: The interface of the next hop
* @ipv6: Switch to only consider IPv6 or IPv4 addresses.
*
* The BSD kernel does not support an onlink flag. If the interface has only
* host addresses configured, all routes should be considered as onlink and
* the function returns 1.
*/
static int
krt_assume_onlink(struct iface *iface, int ipv6)
{
const u8 type = ipv6 ? NET_IP6 : NET_IP4;
struct ifa *ifa;
WALK_LIST(ifa, iface->addrs)
{
if ((ifa->prefix.type == type) && !(ifa->flags & IA_HOST))
return 0;
}
return 1;
}
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0) #define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
static void static void
@ -528,15 +552,21 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
a.dest = RTD_UNICAST; a.dest = RTD_UNICAST;
if (flags & RTF_GATEWAY) if (flags & RTF_GATEWAY)
{ {
neighbor *ng;
a.nh.gw = igate; a.nh.gw = igate;
/* Clean up embedded interface ID returned in link-local address */ /* Clean up embedded interface ID returned in link-local address */
if (ipa_is_link_local(a.nh.gw)) if (ipa_is_link_local(a.nh.gw))
_I0(a.nh.gw) = 0xfe800000; _I0(a.nh.gw) = 0xfe800000;
ng = neigh_find(&p->p, a.nh.gw, a.nh.iface, 0); /* The BSD kernel does not support an onlink flag. We heuristically
if (!ng || (ng->scope == SCOPE_HOST)) set the onlink flag, if the iface has only host addresses. */
if (krt_assume_onlink(a.nh.iface, ipv6))
a.nh.flags |= RNF_ONLINK;
neighbor *nbr;
nbr = neigh_find(&p->p, a.nh.gw, a.nh.iface,
(a.nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
if (!nbr || (nbr->scope == SCOPE_HOST))
{ {
/* Ignore routes with next-hop 127.0.0.1, host routes with such /* Ignore routes with next-hop 127.0.0.1, host routes with such
next-hop appear on OpenBSD for address aliases. */ next-hop appear on OpenBSD for address aliases. */