diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2011-04-13 12:32:27 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2011-04-13 12:32:27 +0200 |
commit | 71ca77169d5d3e67459e46841b8bdb95accd8c2a (patch) | |
tree | 7d357b53c645b77957eddef4cd24979bf0418051 /sysdep/linux/netlink | |
parent | 4aef102be1e29d3450e53a20a6b2f96d50527139 (diff) |
Adds support for several Linux kernel route attributes.
Diffstat (limited to 'sysdep/linux/netlink')
-rw-r--r-- | sysdep/linux/netlink/netlink.Y | 5 | ||||
-rw-r--r-- | sysdep/linux/netlink/netlink.c | 66 |
2 files changed, 57 insertions, 14 deletions
diff --git a/sysdep/linux/netlink/netlink.Y b/sysdep/linux/netlink/netlink.Y index c5dcf620..b00b0eee 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 6cb3c800..0830097a 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 |