summaryrefslogtreecommitdiff
path: root/sysdep/bsd
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/bsd')
-rw-r--r--sysdep/bsd/krt-sock.Y10
-rw-r--r--sysdep/bsd/krt-sock.c145
-rw-r--r--sysdep/bsd/krt-sys.h2
-rw-r--r--sysdep/bsd/sysio.h34
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");