From 71ca77169d5d3e67459e46841b8bdb95accd8c2a Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 13 Apr 2011 12:32:27 +0200 Subject: Adds support for several Linux kernel route attributes. --- doc/bird.sgml | 35 ++++++++++++++++++---- nest/route.h | 3 +- sysdep/linux/netlink/netlink.Y | 5 +++- sysdep/linux/netlink/netlink.c | 66 +++++++++++++++++++++++++++++++++--------- sysdep/unix/krt.c | 21 ++++++++++++++ sysdep/unix/krt.h | 4 +++ 6 files changed, 113 insertions(+), 21 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 5859c77..86f4c50 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1420,12 +1420,20 @@ device routes from BIRD tables to kernel routing tables is restricted to prevent accidental interference. This restriction can be disabled using If your OS supports only a single routing table, you can configure only one -instance of the Kernel protocol. If it supports multiple tables (in order to -allow policy routing; such an OS is for example Linux 2.2), you can run as many instances as you want, but each of -them must be connected to a different BIRD routing table and to a different +

If your OS supports only a single routing table, you can configure +only one instance of the Kernel protocol. If it supports multiple +tables (in order to allow policy routing; such an OS is for example +Linux), you can run as many instances as you want, but each of them +must be connected to a different BIRD routing table and to a different kernel table. +

Because the kernel protocol is partially integrated with the +connected routing table, there are two limitations - it is not +possible to connect more kernel protocols to the same routing table +and changing route attributes (even the kernel ones) in an export +filter of a kernel protocol does not work. Both limitations can be +overcome using another routing table and the pipe protocol. + Configuration

@@ -1450,12 +1458,27 @@ kernel table. only on systems supporting multiple routing tables. -

The Kernel protocol doesn't define any route attributes. +Attributes + +

The Kernel protocol defines several attributes. These attributes +are translated to appropriate system (and OS-specific) route attributes. +We support these attributes: + + + ip (Linux) The preferred source address. + Used in source address selection for outgoing packets. Have to + be one of IP addresses of the router. + + int (Linux) The realm of the route. Can be + used for traffic classification. + + +Example +

A simple configuration can look this way:

protocol kernel { - import all; export all; } diff --git a/nest/route.h b/nest/route.h index 8f9dff9..236882e 100644 --- a/nest/route.h +++ b/nest/route.h @@ -344,7 +344,8 @@ typedef struct eattr { #define EAP_BGP 1 /* BGP attributes */ #define EAP_RIP 2 /* RIP */ #define EAP_OSPF 3 /* OSPF */ -#define EAP_MAX 4 +#define EAP_KRT 4 /* Kernel route attributes */ +#define EAP_MAX 5 #define EA_CODE(proto,id) (((proto) << 8) | (id)) #define EA_PROTO(ea) ((ea) >> 8) diff --git a/sysdep/linux/netlink/netlink.Y b/sysdep/linux/netlink/netlink.Y index c5dcf62..b00b0ee 100644 --- a/sysdep/linux/netlink/netlink.Y +++ b/sysdep/linux/netlink/netlink.Y @@ -10,7 +10,7 @@ CF_HDR CF_DECLS -CF_KEYWORDS(ASYNC, KERNEL, TABLE) +CF_KEYWORDS(ASYNC, KERNEL, TABLE, KRT_PREFSRC, KRT_REALM) CF_GRAMMAR @@ -24,6 +24,9 @@ nl_item: } ; +CF_ADDTO(dynamic_attr, KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); }) +CF_ADDTO(dynamic_attr, KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); }) + CF_CODE CF_END diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c index 6cb3c80..0830097 100644 --- a/sysdep/linux/netlink/netlink.c +++ b/sysdep/linux/netlink/netlink.c @@ -18,6 +18,7 @@ #include "nest/route.h" #include "nest/protocol.h" #include "nest/iface.h" +#include "lib/alloca.h" #include "lib/timer.h" #include "lib/unix.h" #include "lib/krt.h" @@ -618,6 +619,7 @@ nh_bufsize(struct mpnh *nh) static void nl_send_route(struct krt_proto *p, rte *e, int new) { + eattr *ea; net *net = e->net; rta *a = e->attrs; struct { @@ -641,6 +643,13 @@ nl_send_route(struct krt_proto *p, rte *e, int new) r.r.rtm_protocol = RTPROT_BIRD; r.r.rtm_scope = RT_SCOPE_UNIVERSE; nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix); + + if (ea = ea_find(a->eattrs, EA_KRT_PREFSRC)) + nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data); + + if (ea = ea_find(a->eattrs, EA_KRT_REALM)) + nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data); + switch (a->dest) { case RTD_ROUTER: @@ -698,10 +707,9 @@ nl_parse_route(struct nlmsghdr *h, int scan) struct rtmsg *i; struct rtattr *a[RTA_CACHEINFO+1]; int new = h->nlmsg_type == RTM_NEWROUTE; - ip_addr dst; - rte *e; - net *net; - u32 oif; + + ip_addr dst = IPA_NONE; + u32 oif = ~0; int src; if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a))) @@ -709,12 +717,14 @@ nl_parse_route(struct nlmsghdr *h, int scan) if (i->rtm_family != BIRD_AF) return; if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) || - (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) || - (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) || #ifdef IPV6 (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) || #endif - (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr))) + (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) || + (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) || + (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) || + (a[RTA_PREFSRC] && RTA_PAYLOAD(a[RTA_PREFSRC]) != sizeof(ip_addr)) || + (a[RTA_FLOW] && RTA_PAYLOAD(a[RTA_OIF]) != 4)) { log(L_ERR "KRT: Malformed message received"); return; @@ -725,13 +735,9 @@ nl_parse_route(struct nlmsghdr *h, int scan) memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst)); ipa_ntoh(dst); } - else - dst = IPA_NONE; if (a[RTA_OIF]) memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif)); - else - oif = ~0; DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name); @@ -782,7 +788,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) src = KRT_SRC_ALIEN; } - net = net_get(p->p.table, dst, i->rtm_dst_len); + net *net = net_get(p->p.table, dst, i->rtm_dst_len); rta ra = { .proto = &p->p, @@ -871,15 +877,49 @@ nl_parse_route(struct nlmsghdr *h, int scan) return; } - e = rte_get_temp(&ra); + rte *e = rte_get_temp(&ra); e->net = net; e->u.krt.src = src; e->u.krt.proto = i->rtm_protocol; e->u.krt.type = i->rtm_type; + if (a[RTA_PRIORITY]) memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric)); else e->u.krt.metric = 0; + + if (a[RTA_PREFSRC]) + { + ip_addr ps; + memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps)); + ipa_ntoh(ps); + + ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr)); + ea->next = ra.eattrs; + ra.eattrs = ea; + ea->flags = EALF_SORTED; + ea->count = 1; + ea->attrs[0].id = EA_KRT_PREFSRC; + ea->attrs[0].flags = 0; + ea->attrs[0].type = EAF_TYPE_IP_ADDRESS; + ea->attrs[0].u.ptr = alloca(sizeof(struct adata) + sizeof(ps)); + ea->attrs[0].u.ptr->length = sizeof(ps); + memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps)); + } + + if (a[RTA_FLOW]) + { + ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr)); + ea->next = ra.eattrs; + ra.eattrs = ea; + ea->flags = EALF_SORTED; + ea->count = 1; + ea->attrs[0].id = EA_KRT_REALM; + ea->attrs[0].flags = 0; + ea->attrs[0].type = EAF_TYPE_INT; + memcpy(&ea->attrs[0].u.data, RTA_DATA(a[RTA_FLOW]), 4); + } + if (scan) krt_got_route(p, e); else diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 562dc71..7057070 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -890,6 +890,7 @@ krt_init(struct proto_config *c) p->p.accept_ra_types = RA_OPTIMAL; p->p.import_control = krt_import_control; p->p.rt_notify = krt_notify; + return &p->p; } @@ -907,15 +908,35 @@ krt_reconfigure(struct proto *p, struct proto_config *new) ; } + +static int +krt_get_attr(eattr * a, byte * buf, int buflen UNUSED) +{ + switch (a->id) + { + case EA_KRT_PREFSRC: + bsprintf(buf, "prefsrc"); + return GA_NAME; + case EA_KRT_REALM: + bsprintf(buf, "realm"); + return GA_NAME; + default: + return GA_UNKNOWN; + } +} + + struct protocol proto_unix_kernel = { name: "Kernel", template: "kernel%d", + attr_class: EAP_KRT, preconfig: krt_preconfig, postconfig: krt_postconfig, init: krt_init, start: krt_start, shutdown: krt_shutdown, reconfigure: krt_reconfigure, + get_attr: krt_get_attr, #ifdef KRT_ALLOW_LEARN dump: krt_dump, dump_attrs: krt_dump_attrs, diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index ed61621..c88bc48 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -30,6 +30,10 @@ struct kif_proto; #define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */ + +#define EA_KRT_PREFSRC EA_CODE(EAP_KRT, 0) +#define EA_KRT_REALM EA_CODE(EAP_KRT, 1) + /* Whenever we recognize our own routes, we allow learing of foreign routes */ #ifdef CONFIG_SELF_CONSCIOUS -- cgit v1.2.3