summaryrefslogtreecommitdiff
path: root/sysdep
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep')
-rw-r--r--sysdep/bsd/krt-sock.c111
-rw-r--r--sysdep/linux/netlink.Y21
-rw-r--r--sysdep/unix/domain.c6
-rw-r--r--sysdep/unix/krt.c34
4 files changed, 102 insertions, 70 deletions
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index 1c1bd50c..0706f546 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -148,15 +148,18 @@ static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2];
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
);
}
@@ -197,18 +200,22 @@ sockaddr_fill_dl(struct sockaddr_dl *sa, struct iface *ifa)
}
static int
-krt_send_route(struct krt_proto *p, int cmd, rte *e)
+krt_send_route(struct krt_proto *p, int cmd, const rte *e)
{
- net *net = e->net;
- rta *a = e->attrs;
+ const net_addr *net = e->net;
+ 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->n.prefix, net->n.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 +225,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
/* XXXX */
- if (net_pxlen(net->n.addr) == net_max_prefix_length[net->n.addr->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;
@@ -228,11 +235,11 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
#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
@@ -260,7 +267,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
int af = AF_UNSPEC;
- switch (net->n.addr->type) {
+ switch (net->type) {
case NET_IP4:
af = AF_INET;
break;
@@ -268,19 +275,19 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
af = AF_INET6;
break;
default:
- log(L_ERR "KRT: Not sending route %N to kernel", net->n.addr);
+ log(L_ERR "KRT: Not sending route %N to kernel", net);
return -1;
}
- sockaddr_fill(&dst, af, net_prefix(net->n.addr), NULL, 0);
- sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
+ 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))
@@ -292,6 +299,8 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
break;
}
+ /* Fall through */
+
#ifdef RTF_REJECT
case RTD_UNREACHABLE:
#endif
@@ -303,7 +312,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
#if __OpenBSD__
/* Keeping temporarily old code for OpenBSD */
- struct ifa *addr = (net->n.addr->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
+ struct ifa *addr = (net->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
if (!addr)
{
@@ -339,7 +348,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
msg.rtm.rtm_msglen = l;
if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
- log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
+ log(L_ERR "KRT: Error sending route %N to kernel: %m", net);
return -1;
}
@@ -347,7 +356,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
}
void
-krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
+krt_replace_rte(struct krt_proto *p, const net_addr *n UNUSED, rte *new, const rte *old)
{
int err = 0;
@@ -398,7 +407,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
/* p is NULL iff KRT_SHARED_SOCKET and !scan */
int ipv6;
- net *net;
sockaddr dst, gate, mask;
ip_addr idst, igate, imask;
net_addr ndst;
@@ -514,74 +522,82 @@ 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 = {};
- net = net_get(p->p.main_channel->table, &ndst);
-
- rta a = {
- };
+ ea_list *eattrs = NULL;
- ea_set_attr_u32(&a->eattrs, &ea_gen_source, 0, RTS_INHERIT);
+ 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",
- net->n.addr, msg->rtm.rtm_index);
+ &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",
- net->n.addr, a.nh.gw);
+ &ndst, nhad.nh.gw);
return;
}
}
- done:;
- rte e0 = { .attrs = &a, .net = net, };
+ nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data;
+
+ done:
+ ea_set_attr(&eattrs, EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nhad.ad));
+ rte e0 = { .attrs = eattrs, .net = &ndst, };
- ea_set_attr(e0.attrs->eattrs,
- EA_LITERAL_EMBEDDED(EA_KRT_SOURCE, T_INT, 0, src2));
+ ea_set_attr(&e0.attrs,
+ EA_LITERAL_EMBEDDED(&ea_krt_source, 0, src2));
if (scan)
krt_got_route(p, &e0, src);
@@ -822,6 +838,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:
diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y
index 7ba8c7c9..9b07e9bb 100644
--- a/sysdep/linux/netlink.Y
+++ b/sysdep/linux/netlink.Y
@@ -15,6 +15,8 @@ CF_KEYWORDS(KERNEL, TABLE, METRIC, NETLINK, RX, BUFFER,
KRT_LOCK_SSTRESH, KRT_LOCK_CWND, KRT_LOCK_ADVMSS, KRT_LOCK_REORDERING,
KRT_LOCK_HOPLIMIT, KRT_LOCK_RTO_MIN, KRT_FEATURE_ECN, KRT_FEATURE_ALLFRAG)
+%type <fab> attr_bit
+
CF_GRAMMAR
kern_proto: kern_proto kern_sys_item ';' ;
@@ -42,6 +44,25 @@ attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, "krt_lock"); } ;
attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, "krt_features"); } ;
attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, "krt_features"); } ;
+/* Getting attribute bits (moved here to not confuse Bison on *BSD) */
+term:
+ attr_bit {
+ struct f_inst *c = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)});
+ $$ = f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, $1.class), c));
+ }
+ ;
+
+/* Setting attribute bits (moved here to not confuse Bison on *BSD) */
+cmd:
+ attr_bit '=' term ';' {
+ $$ = f_new_inst(FI_CONDITION, $3,
+ f_generate_complex_default(FI_BITOR, $1.class,
+ f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)}), 0),
+ f_generate_complex_default(FI_BITAND, $1.class,
+ f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = ~(1U << $1.bit)}), 0)
+ );
+ }
+ ;
CF_CODE
diff --git a/sysdep/unix/domain.c b/sysdep/unix/domain.c
index 1cba540b..f4ee595d 100644
--- a/sysdep/unix/domain.c
+++ b/sysdep/unix/domain.c
@@ -83,11 +83,15 @@ uint dg_order(struct domain_generic *dg)
void do_lock(struct domain_generic *dg, struct domain_generic **lsp)
{
+ struct lock_order stack_copy;
+ memcpy(&stack_copy, &locking_stack, sizeof(stack_copy));
+ struct domain_generic **lll = last_locked;
+
if ((char *) lsp - (char *) &locking_stack != dg->order)
bug("Trying to lock on bad position: order=%u, lsp=%p, base=%p", dg->order, lsp, &locking_stack);
if (lsp <= last_locked)
- bug("Trying to lock in a bad order");
+ bug("Trying to lock in a bad order: %p %p", &stack_copy, lll);
if (*lsp)
bug("Inconsistent locking stack state on lock");
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 3b6c91cc..b3681c9c 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -290,18 +290,6 @@ krt_metric(rte *a)
return ea ? ea->u.data : 0;
}
-static inline int
-krt_same_key(rte *a, rte *b)
-{
- return (krt_metric(a) == krt_metric(b));
-}
-
-static inline int
-krt_uptodate(rte *a, rte *b)
-{
- return (a->attrs == b->attrs);
-}
-
static void
krt_learn_alien_attr(struct channel *c, rte *e)
{
@@ -444,10 +432,13 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
switch (src)
{
case KRT_SRC_KERNEL:
- goto ignore;
+ krt_trace_in(p, e, "ignored");
+ return;
case KRT_SRC_REDIRECT:
- goto delete;
+ krt_trace_in(p, e, "deleting");
+ krt_replace_rte(p, e->net, NULL, e);
+ return;
case KRT_SRC_ALIEN:
if (KRT_CF->learn)
@@ -457,6 +448,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
return;
}
#endif
+
/* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
RT_LOCKED(p->p.main_channel->table, tab)
@@ -719,7 +711,11 @@ static int
krt_preexport(struct channel *C, rte *e)
{
if (e->src->owner == &C->proto->sources)
+#ifdef CONFIG_SINGLE_ROUTE
+ return 1;
+#else
return -1;
+#endif
if (!krt_capable(e))
return -1;
@@ -737,14 +733,8 @@ krt_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net,
return;
#ifdef CONFIG_SINGLE_ROUTE
- /*
- * Implicit withdraw - when the imported kernel route becomes the best one,
- * we know that the previous one exported to the kernel was already removed,
- * but if we processed the update as usual, we would send withdraw to the
- * kernel, which would remove the new imported route instead.
- */
- rte *best = net->routes;
- if (!new && best && (best->attrs->src->proto == P))
+ /* Got the same route as we imported. Keep it, do nothing. */
+ if (new && new->src->owner == &P->sources)
return;
#endif