diff options
Diffstat (limited to 'sysdep/bsd')
-rw-r--r-- | sysdep/bsd/krt-sock.Y | 10 | ||||
-rw-r--r-- | sysdep/bsd/krt-sock.c | 145 | ||||
-rw-r--r-- | sysdep/bsd/krt-sys.h | 2 | ||||
-rw-r--r-- | sysdep/bsd/sysio.h | 34 |
4 files changed, 141 insertions, 50 deletions
diff --git a/sysdep/bsd/krt-sock.Y b/sysdep/bsd/krt-sock.Y index 8581bd43..a03d6df5 100644 --- a/sysdep/bsd/krt-sock.Y +++ b/sysdep/bsd/krt-sock.Y @@ -10,7 +10,7 @@ CF_HDR CF_DECLS -CF_KEYWORDS(KERNEL, TABLE) +CF_KEYWORDS(KERNEL, TABLE, METRIC) CF_GRAMMAR @@ -25,6 +25,14 @@ kern_sys_item: THIS_KRT->sys.table_id = $3; } + | METRIC expr { + if ($2 && !krt_max_metric) + cf_error("Kernel route metric not supported"); + if ($2 > krt_max_metric) + cf_error("Kernel table id must be in range 0-%u", krt_max_metric); + + THIS_KRT->sys.metric = $2; + } ; CF_CODE diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index fb407739..094268b7 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -25,7 +25,7 @@ #include "nest/bird.h" #include "nest/iface.h" -#include "nest/route.h" +#include "nest/rt.h" #include "nest/protocol.h" #include "nest/iface.h" #include "sysdep/unix/unix.h" @@ -47,6 +47,11 @@ const int rt_default_ecmp = 0; * table_id is specified explicitly as sysctl scan argument, while in FreeBSD it * is handled implicitly by changing default table using setfib() syscall. * + * OpenBSD allows to use route metric. The behavior is controlled by these macro + * KRT_USE_METRIC, which enables use of rtm_priority in route send/recevive. + * There is also KRT_DEFAULT_METRIC and KRT_MAX_METRIC for default and maximum + * metric values. + * * KRT_SHARED_SOCKET - use shared kernel socked instead of one for each krt_proto * KRT_USE_SETFIB_SCAN - use setfib() for sysctl() route scan * KRT_USE_SETFIB_SOCK - use SO_SETFIB socket option for kernel sockets @@ -63,6 +68,9 @@ const int rt_default_ecmp = 0; #ifdef __OpenBSD__ #define KRT_MAX_TABLES (RT_TABLEID_MAX+1) +#define KRT_USE_METRIC +#define KRT_MAX_METRIC 255 +#define KRT_DEFAULT_METRIC 56 #define KRT_SHARED_SOCKET #define KRT_USE_SYSCTL_7 #endif @@ -71,6 +79,14 @@ const int rt_default_ecmp = 0; #define KRT_MAX_TABLES 1 #endif +#ifndef KRT_MAX_METRIC +#define KRT_MAX_METRIC 0 +#endif + +#ifndef KRT_DEFAULT_METRIC +#define KRT_DEFAULT_METRIC 0 +#endif + /* Dynamic max number of tables */ @@ -143,20 +159,27 @@ static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2]; #endif +/* Make it available to parser code */ +const uint krt_max_metric = KRT_MAX_METRIC; + + /* Route socket message processing */ int krt_capable(rte *e) { - rta *a = e->attrs; + ea_list *eattrs = e->attrs; + eattr *nhea = ea_find(eattrs, &ea_gen_nexthop); + struct nexthop_adata *nh = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL; + int dest = nhea_dest(nhea); return - ((a->dest == RTD_UNICAST && !a->nh.next) /* No multipath support */ + ((dest == RTD_UNICAST && !NEXTHOP_ONE(nh)) /* No multipath support */ #ifdef RTF_REJECT - || a->dest == RTD_UNREACHABLE + || dest == RTD_UNREACHABLE #endif #ifdef RTF_BLACKHOLE - || a->dest == RTD_BLACKHOLE + || dest == RTD_BLACKHOLE #endif ); } @@ -186,10 +209,14 @@ struct ks_msg memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\ body += l;} -static inline void +static inline void UNUSED sockaddr_fill_dl(struct sockaddr_dl *sa, struct iface *ifa) { uint len = OFFSETOF(struct sockaddr_dl, sdl_data); + + /* Workaround for FreeBSD 13.0 */ + len = MAX(len, sizeof(struct sockaddr)); + memset(sa, 0, len); sa->sdl_len = len; sa->sdl_family = AF_LINK; @@ -200,15 +227,19 @@ static int krt_send_route(struct krt_proto *p, int cmd, const rte *e) { const net_addr *net = e->net; - rta *a = e->attrs; + ea_list *eattrs = e->attrs; + eattr *nhea = ea_find(eattrs, &ea_gen_nexthop); + struct nexthop_adata *nh = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL; + int dest = nhea_dest(nhea); + static int msg_seq; - struct iface *j, *i = a->nh.iface; + struct iface *j, *i = (dest == RTD_UNICAST) ? nh->nh.iface : NULL; int l; struct ks_msg msg; char *body = (char *)msg.buf; sockaddr gate, mask, dst; -// DBG("krt-sock: send %I/%d via %I\n", net->prefix, net->pxlen, a->gw); + DBG("krt-sock: send %N via %I\n", net, nh->nh.gw); bzero(&msg,sizeof (struct rt_msghdr)); msg.rtm.rtm_version = RTM_VERSION; @@ -218,7 +249,7 @@ krt_send_route(struct krt_proto *p, int cmd, const rte *e) msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1; /* XXXX */ - if (net_pxlen(net) == net_max_prefix_length[net->type]) + if (net_pxlen(e->net) == net_max_prefix_length[net->type]) msg.rtm.rtm_flags |= RTF_HOST; else msg.rtm.rtm_addrs |= RTA_NETMASK; @@ -227,12 +258,16 @@ krt_send_route(struct krt_proto *p, int cmd, const rte *e) msg.rtm.rtm_tableid = KRT_CF->sys.table_id; #endif +#ifdef KRT_USE_METRIC + msg.rtm.rtm_priority = KRT_CF->sys.metric; +#endif + #ifdef RTF_REJECT - if(a->dest == RTD_UNREACHABLE) + if(dest == RTD_UNREACHABLE) msg.rtm.rtm_flags |= RTF_REJECT; #endif #ifdef RTF_BLACKHOLE - if(a->dest == RTD_BLACKHOLE) + if(dest == RTD_BLACKHOLE) msg.rtm.rtm_flags |= RTF_BLACKHOLE; #endif @@ -242,16 +277,17 @@ krt_send_route(struct krt_proto *p, int cmd, const rte *e) */ if (!i) { - IFACE_LOCK; - WALK_LIST(j, global_iface_list) + j = if_walk_first(); + while (j) { if (j->flags & IF_LOOPBACK) { i = j; break; } + j = if_walk_next(j); } - IFACE_UNLOCK; + if_walk_done(); if (!i) { @@ -277,12 +313,12 @@ krt_send_route(struct krt_proto *p, int cmd, const rte *e) sockaddr_fill(&dst, af, net_prefix(net), NULL, 0); sockaddr_fill(&mask, af, net_pxmask(net), NULL, 0); - switch (a->dest) + switch (dest) { case RTD_UNICAST: - if (ipa_nonzero(a->nh.gw)) + if (ipa_nonzero(nh->nh.gw)) { - ip_addr gw = a->nh.gw; + ip_addr gw = nh->nh.gw; /* Embed interface ID to link-local address */ if (ipa_is_link_local(gw)) @@ -294,6 +330,8 @@ krt_send_route(struct krt_proto *p, int cmd, const rte *e) break; } + /* Fall through */ + #ifdef RTF_REJECT case RTD_UNREACHABLE: #endif @@ -515,79 +553,87 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) src = KRT_SRC_ALIEN; else src = KRT_SRC_KERNEL; + + union { + struct { + struct adata ad; + struct nexthop nh; + u32 labels[MPLS_MAX_LABEL_STACK]; + }; + struct nexthop_adata nhad; + } nhad = {}; + + ea_list *eattrs = NULL; - rta a = { - .source = RTS_INHERIT, - .scope = SCOPE_UNIVERSE, - }; + ea_set_attr_u32(&eattrs, &ea_gen_source, 0, RTS_INHERIT); /* reject/blackhole routes have also set RTF_GATEWAY, we wil check them first. */ #ifdef RTF_REJECT if(flags & RTF_REJECT) { - a.dest = RTD_UNREACHABLE; + nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_UNREACHABLE); goto done; } #endif #ifdef RTF_BLACKHOLE if(flags & RTF_BLACKHOLE) { - a.dest = RTD_BLACKHOLE; + nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_BLACKHOLE); goto done; } #endif - a.nh.iface = if_find_by_index(msg->rtm.rtm_index); - if (!a.nh.iface) + nhad.nh.iface = if_find_by_index(msg->rtm.rtm_index); + if (!nhad.nh.iface) { log(L_ERR "KRT: Received route %N with unknown ifindex %u", &ndst, msg->rtm.rtm_index); return; } - a.dest = RTD_UNICAST; if (flags & RTF_GATEWAY) { - a.nh.gw = igate; + nhad.nh.gw = igate; /* Clean up embedded interface ID returned in link-local address */ - if (ipa_is_link_local(a.nh.gw)) - _I0(a.nh.gw) = 0xfe800000; + if (ipa_is_link_local(nhad.nh.gw)) + _I0(nhad.nh.gw) = 0xfe800000; /* The BSD kernel does not support an onlink flag. We heuristically set the onlink flag, if the iface has only host addresses. */ - if (krt_assume_onlink(a.nh.iface, ipv6)) - a.nh.flags |= RNF_ONLINK; + if (krt_assume_onlink(nhad.nh.iface, ipv6)) + nhad.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); + nbr = neigh_find(&p->p, nhad.nh.gw, nhad.nh.iface, + (nhad.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 next-hop appear on OpenBSD for address aliases. */ - if (ipa_classify(a.nh.gw) == (IADDR_HOST | SCOPE_HOST)) + if (ipa_classify(nhad.nh.gw) == (IADDR_HOST | SCOPE_HOST)) return; log(L_ERR "KRT: Received route %N with strange next-hop %I", - &ndst, a.nh.gw); + &ndst, nhad.nh.gw); return; } } - done:; - rte e0 = { .attrs = &a, .net = &ndst, }; + nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data; - ea_list *ea = alloca(sizeof(ea_list) + 1 * sizeof(eattr)); - *ea = (ea_list) { .count = 1, .next = e0.attrs->eattrs }; - e0.attrs->eattrs = ea; + done: + ea_set_attr(&eattrs, EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nhad.ad)); + rte e0 = { .attrs = eattrs, .net = &ndst, }; - ea->attrs[0] = (eattr) { - .id = EA_KRT_SOURCE, - .type = EAF_TYPE_INT, - .u.data = src2, - }; + ea_set_attr(&e0.attrs, + EA_LITERAL_EMBEDDED(&ea_krt_source, 0, src2)); + +#ifdef KRT_USE_METRIC + ea_set_attr(&e0.attrs, + EA_LITERAL_EMBEDDED(&ea_krt_metric, 0, msg->rtm.rtm_priority)); +#endif if (scan) krt_got_route(p, &e0, src); @@ -828,6 +874,7 @@ krt_read_msg(struct proto *p, struct ks_msg *msg, int scan) { case RTM_GET: if(!scan) return; + /* Fall through */ case RTM_ADD: case RTM_DELETE: case RTM_CHANGE: @@ -1041,7 +1088,7 @@ krt_sock_open(pool *pool, void *data, int table_id UNUSED) sk->fd = fd; sk->data = data; - if (sk_open(sk) < 0) + if (sk_open(sk, &main_birdloop) < 0) bug("krt-sock: sk_open failed"); return sk; @@ -1148,7 +1195,7 @@ krt_sys_shutdown(struct krt_proto *p) int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o) { - return n->sys.table_id == o->sys.table_id; + return (n->sys.table_id == o->sys.table_id) && (n->sys.metric == o->sys.metric); } void @@ -1161,11 +1208,13 @@ krt_sys_preconfig(struct config *c UNUSED) void krt_sys_init_config(struct krt_config *c) { c->sys.table_id = 0; /* Default table */ + c->sys.metric = KRT_DEFAULT_METRIC; } void krt_sys_copy_config(struct krt_config *d, struct krt_config *s) { d->sys.table_id = s->sys.table_id; + d->sys.metric = s->sys.metric; } diff --git a/sysdep/bsd/krt-sys.h b/sysdep/bsd/krt-sys.h index 57501884..198373c0 100644 --- a/sysdep/bsd/krt-sys.h +++ b/sysdep/bsd/krt-sys.h @@ -32,9 +32,11 @@ static inline void kif_sys_copy_config(struct kif_config *d UNUSED, struct kif_c /* Kernel routes */ extern uint krt_max_tables; +extern const uint krt_max_metric; struct krt_params { int table_id; /* Kernel table ID we sync with */ + u32 metric; /* Kernel metric used for all routes */ }; struct krt_state { diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index f1887fb4..b6b42b1e 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -15,8 +15,23 @@ #ifdef __FreeBSD__ /* Should be defined in sysdep/cf/bsd.h, but it is flavor-specific */ #define CONFIG_DONTROUTE_UNICAST + +#if __FreeBSD_version >= 1201000 +#define CONFIG_USE_IP_MREQN +#endif + #endif + +#ifdef __OpenBSD__ + +#if OpenBSD >= 202105 +#define CONFIG_USE_IP_MREQN +#endif + +#endif + + #ifdef __NetBSD__ #ifndef IP_RECVTTL @@ -29,6 +44,7 @@ #endif + #ifdef __DragonFly__ #define TCP_MD5SIG TCP_SIGNATURE_ENABLE #endif @@ -45,13 +61,21 @@ #define INIT_MREQ4(maddr,ifa) \ { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ip4_to_in4(ifa->sysdep) } +#define INIT_MREQN4(maddr,ifa) \ + { .imr_multiaddr = ipa_to_in4(maddr), .imr_ifindex = ifa->index } + static inline int sk_setup_multicast4(sock *s) { - struct in_addr ifa = ip4_to_in4(s->iface->sysdep); u8 ttl = s->ttl; u8 n = 0; +#ifdef CONFIG_USE_IP_MREQN + struct ip_mreqn ifa = { .imr_ifindex = s->iface->index }; +#else + struct in_addr ifa = ip4_to_in4(s->iface->sysdep); +#endif + /* This defines where should we send _outgoing_ multicasts */ if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &ifa, sizeof(ifa)) < 0) ERR("IP_MULTICAST_IF"); @@ -68,7 +92,11 @@ sk_setup_multicast4(sock *s) static inline int sk_join_group4(sock *s, ip_addr maddr) { +#ifdef CONFIG_USE_IP_MREQN + struct ip_mreqn mr = INIT_MREQN4(maddr, s->iface); +#else struct ip_mreq mr = INIT_MREQ4(maddr, s->iface); +#endif if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) ERR("IP_ADD_MEMBERSHIP"); @@ -79,7 +107,11 @@ sk_join_group4(sock *s, ip_addr maddr) static inline int sk_leave_group4(sock *s, ip_addr maddr) { +#ifdef CONFIG_USE_IP_MREQN + struct ip_mreqn mr = INIT_MREQN4(maddr, s->iface); +#else struct ip_mreq mr = INIT_MREQ4(maddr, s->iface); +#endif if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0) ERR("IP_ADD_MEMBERSHIP"); |