The general-purpose scope attribute is detailed in the documentation as an attribute that BIRD won't set and won't use. Therefore, to expose the scope of a kernel route, this commit adds a new attribute, krt_scope. Its possible values are the numeric values for SCOPE_* variables (1 is SCOPE_LINK for example), not the values from the kernel (253 is RT_SCOPE_LINK). Both import and export are supported.
A typical use case is to install "scope link" routes for directly connected destinations, as the kernel won't accept routes with a broader scope when issuing an internal lookup. It would have been neat to be able to use "SCOPE_LINK" in a filter or to show "SCOPE_LINK" when displaying the route, but currently, only the numerical value can be used. Signed-off-by: Vincent Bernat <vinc...@bernat.im> --- sysdep/linux/krt-sys.h | 1 + sysdep/linux/netlink.Y | 3 ++- sysdep/linux/netlink.c | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index 96688e34c860..6d6586d10f02 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -36,6 +36,7 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; } #define EA_KRT_PREFSRC EA_CODE(EAP_KRT, 0x10) #define EA_KRT_REALM EA_CODE(EAP_KRT, 0x11) +#define EA_KRT_SCOPE EA_CODE(EAP_KRT, 0x12) #define KRT_METRICS_MAX 0x10 /* RTAX_QUICKACK+1 */ diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index a1c22f3ece17..c1c9503c33ec 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -10,7 +10,7 @@ CF_HDR CF_DECLS -CF_KEYWORDS(KERNEL, TABLE, METRIC, KRT_PREFSRC, KRT_REALM, KRT_MTU, KRT_WINDOW, +CF_KEYWORDS(KERNEL, TABLE, METRIC, KRT_PREFSRC, KRT_REALM, KRT_SCOPE, KRT_MTU, KRT_WINDOW, KRT_RTT, KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING, KRT_HOPLIMIT, KRT_INITCWND, KRT_RTO_MIN, KRT_INITRWND, KRT_QUICKACK, KRT_LOCK_MTU, KRT_LOCK_WINDOW, KRT_LOCK_RTT, KRT_LOCK_RTTVAR, @@ -28,6 +28,7 @@ kern_sys_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_ADDTO(dynamic_attr, KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_SCOPE, EA_KRT_SCOPE); }) CF_ADDTO(dynamic_attr, KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); }) CF_ADDTO(dynamic_attr, KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); }) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 9bdcc0d2ff19..9f73e0feeeaf 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -900,6 +900,15 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d r.r.rtm_dst_len = net->n.pxlen; r.r.rtm_protocol = RTPROT_BIRD; r.r.rtm_scope = RT_SCOPE_UNIVERSE; + if (ea = ea_find(eattrs, EA_KRT_SCOPE)) + switch (ea->u.data) + { + case SCOPE_HOST: r.r.rtm_scope = RT_SCOPE_HOST; break; + case SCOPE_LINK: r.r.rtm_scope = RT_SCOPE_LINK; break; + case SCOPE_SITE: r.r.rtm_scope = RT_SCOPE_SITE; break; + case SCOPE_UNIVERSE: r.r.rtm_scope = RT_SCOPE_UNIVERSE; break; + } + nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix); /* @@ -1157,7 +1166,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) return; } - if (a[RTA_DST]) { memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst)); @@ -1195,11 +1203,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) SKIP("strange class/scope\n"); - // ignore rtm_scope, it is not a real scope - // if (i->rtm_scope != RT_SCOPE_UNIVERSE) - // SKIP("scope %u\n", i->rtm_scope); - - switch (i->rtm_protocol) { case RTPROT_UNSPEC: @@ -1304,6 +1307,27 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) return; } + int krt_scope = -1; + switch (i->rtm_scope) + { + case RT_SCOPE_HOST: krt_scope = SCOPE_HOST; break; + case RT_SCOPE_LINK: krt_scope = SCOPE_LINK; break; + case RT_SCOPE_SITE: krt_scope = SCOPE_SITE; break; + case RT_SCOPE_UNIVERSE: krt_scope = SCOPE_UNIVERSE; break; + } + if (krt_scope != -1) + { + ea_list *ea = lp_alloc(s->pool, 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_SCOPE; + ea->attrs[0].flags = 0; + ea->attrs[0].type = EAF_TYPE_INT; + ea->attrs[0].u.data = krt_scope; + } + if (a[RTA_PREFSRC]) { ip_addr ps; @@ -1633,6 +1657,10 @@ krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED) bsprintf(buf, "realm"); return GA_NAME; + case EA_KRT_SCOPE: + bsprintf(buf, "scope"); + return GA_NAME; + case EA_KRT_LOCK: buf += bsprintf(buf, "lock:"); ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX); -- 2.9.3