aboutsummaryrefslogtreecommitdiffstats
path: root/sysdep
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2018-02-13 16:27:57 +0100
committerOndrej Zajicek (work) <santiago@crfreenet.org>2018-02-13 16:39:07 +0100
commitbe17805c0bbd37e865dc9b17b56e8e8d210c2c6c (patch)
tree50506f959f6bc4ea505ee2b7ef5e6d7e75f909b6 /sysdep
parenta82f692e5844d5efdc091a796dc0e8ae8ab5a322 (diff)
downloadbird-be17805c0bbd37e865dc9b17b56e8e8d210c2c6c.tar.gz
Add support for source-specific IPv6 routes to BIRD core
This patch adds support for source-specific IPv6 routes to BIRD core. This is based on Dean Luga's original patch, with the review comments addressed. SADR support is added to network address parsing in confbase.Y and to the kernel protocol on Linux. Currently there is no way to mix source-specific and non-source-specific routes (i.e., SADR tables cannot be connected to non-SADR tables). Thanks to Toke Hoiland-Jorgensen for the original patch. Minor changes by Ondrej Santiago Zajicek.
Diffstat (limited to 'sysdep')
-rw-r--r--sysdep/cf/linux.h1
-rw-r--r--sysdep/linux/netlink.c43
-rw-r--r--sysdep/unix/krt.c25
3 files changed, 53 insertions, 16 deletions
diff --git a/sysdep/cf/linux.h b/sysdep/cf/linux.h
index 3a3a15da..047d3764 100644
--- a/sysdep/cf/linux.h
+++ b/sysdep/cf/linux.h
@@ -10,6 +10,7 @@
#define CONFIG_SELF_CONSCIOUS
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_ALL_TABLES_AT_ONCE
+#define CONFIG_IP6_SADR_KERNEL
#define CONFIG_MC_PROPER_SRC
#define CONFIG_UNIX_DONTROUTE
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index 4cb51519..84591eb2 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -374,6 +374,7 @@ static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
[RTA_DST] = { 1, 1, sizeof(ip6_addr) },
+ [RTA_SRC] = { 1, 1, sizeof(ip6_addr) },
[RTA_IIF] = { 1, 1, sizeof(u32) },
[RTA_OIF] = { 1, 1, sizeof(u32) },
[RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
@@ -1221,8 +1222,18 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
}
else
#endif
+ {
nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr));
+ /* Add source address for IPv6 SADR routes */
+ if (net->n.addr->type == NET_IP6_SADR)
+ {
+ net_addr_ip6_sadr *a = (void *) &net->n.addr;
+ nl_add_attr_ip6(&r->h, rsize, RTA_SRC, a->src_prefix);
+ r->r.rtm_src_len = a->src_pxlen;
+ }
+ }
+
/*
* Strange behavior for RTM_DELROUTE:
* 1) rtm_family is ignored in IPv6, works for IPv4
@@ -1447,12 +1458,12 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
struct rtattr *a[BIRD_RTA_MAX];
int new = h->nlmsg_type == RTM_NEWROUTE;
- net_addr dst;
+ net_addr dst, src = {};
u32 oif = ~0;
u32 table_id;
u32 priority = 0;
u32 def_scope = RT_SCOPE_UNIVERSE;
- int src;
+ int krt_src;
if (!(i = nl_checkin(h, sizeof(*i))))
return;
@@ -1477,6 +1488,11 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
net_fill_ip6(&dst, rta_get_ip6(a[RTA_DST]), i->rtm_dst_len);
else
net_fill_ip6(&dst, IP6_NONE, 0);
+
+ if (a[RTA_SRC])
+ net_fill_ip6(&src, rta_get_ip6(a[RTA_SRC]), i->rtm_src_len);
+ else
+ net_fill_ip6(&src, IP6_NONE, 0);
break;
#ifdef HAVE_MPLS_KERNEL
@@ -1511,6 +1527,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (!p)
SKIP("unknown table %d\n", table);
+ if (a[RTA_SRC] && (p->p.net_type != NET_IP6_SADR))
+ SKIP("src prefix for non-SADR channel\n");
+
if (a[RTA_IIF])
SKIP("IIF set\n");
@@ -1533,25 +1552,33 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
SKIP("proto unspec\n");
case RTPROT_REDIRECT:
- src = KRT_SRC_REDIRECT;
+ krt_src = KRT_SRC_REDIRECT;
break;
case RTPROT_KERNEL:
- src = KRT_SRC_KERNEL;
+ krt_src = KRT_SRC_KERNEL;
return;
case RTPROT_BIRD:
if (!s->scan)
SKIP("echo\n");
- src = KRT_SRC_BIRD;
+ krt_src = KRT_SRC_BIRD;
break;
case RTPROT_BOOT:
default:
- src = KRT_SRC_ALIEN;
+ krt_src = KRT_SRC_ALIEN;
}
- net *net = net_get(p->p.main_channel->table, &dst);
+ net_addr *n = &dst;
+ if (p->p.net_type == NET_IP6_SADR)
+ {
+ n = alloca(sizeof(net_addr_ip6_sadr));
+ net_fill_ip6_sadr(n, net6_prefix(&dst), net6_pxlen(&dst),
+ net6_prefix(&src), net6_pxlen(&src));
+ }
+
+ net *net = net_get(p->p.main_channel->table, n);
if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type))
nl_announce_route(s);
@@ -1755,7 +1782,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
s->attrs = ra;
s->proto = p;
s->new = new;
- s->krt_src = src;
+ s->krt_src = krt_src;
s->krt_type = i->rtm_type;
s->krt_proto = i->rtm_protocol;
s->krt_metric = priority;
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index a3cbb336..b4fb1967 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -1108,10 +1108,11 @@ krt_start(struct proto *P)
switch (p->p.net_type)
{
- case NET_IP4: p->af = AF_INET; break;
- case NET_IP6: p->af = AF_INET6; break;
+ case NET_IP4: p->af = AF_INET; break;
+ case NET_IP6: p->af = AF_INET6; break;
+ case NET_IP6_SADR: p->af = AF_INET6; break;
#ifdef AF_MPLS
- case NET_MPLS: p->af = AF_MPLS; break;
+ case NET_MPLS: p->af = AF_MPLS; break;
#endif
default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break;
}
@@ -1219,16 +1220,24 @@ krt_get_attr(eattr *a, byte *buf, int buflen)
}
+#ifdef CONFIG_IP6_SADR_KERNEL
+#define MAYBE_IP6_SADR NB_IP6_SADR
+#else
+#define MAYBE_IP6_SADR 0
+#endif
+
+#ifdef HAVE_MPLS_KERNEL
+#define MAYBE_MPLS NB_MPLS
+#else
+#define MAYBE_MPLS 0
+#endif
+
struct protocol proto_unix_kernel = {
.name = "Kernel",
.template = "kernel%d",
.attr_class = EAP_KRT,
.preference = DEF_PREF_INHERITED,
-#ifdef HAVE_MPLS_KERNEL
- .channel_mask = NB_IP | NB_MPLS,
-#else
- .channel_mask = NB_IP,
-#endif
+ .channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS,
.proto_size = sizeof(struct krt_proto),
.config_size = sizeof(struct krt_config),
.preconfig = krt_preconfig,