From 4adcb9df1bf551cc5fd1145c09af1843fdc4fe85 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Thu, 15 Sep 2016 14:59:06 +0200 Subject: [PATCH] KRT: Add kernel metric protocol option Kernel routes with different metrics do not clash with each other, therefore using dedicated metric value is a reliable way to avoid overwriting routes from other sources (e.g. kernel device routes). Although kernel route metric could already be set as a route attribute by filters, that is not consistent with the way how Linux kernel handles route metric - not just a route attribute, but a part of a route key. --- doc/bird.sgml | 15 ++++++++++++++- sysdep/linux/krt-sys.h | 1 + sysdep/linux/netlink.Y | 9 ++++----- sysdep/linux/netlink.c | 19 +++++++++++++++---- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 1af7f2c1..9bd7df86 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -2388,6 +2388,17 @@ limitations can be overcome using another routing table and the pipe protocol. protocol work with. Available only on systems supporting multiple routing tables. + metric (Linux) + Use specified value as a kernel metric (priority) for all routes sent to + the kernel. When multiple routes for the same network are in the kernel + routing table, the Linux kernel chooses one with lower metric. Also, + routes with different metrics do not clash with each other, therefore + using dedicated metric value is a reliable way to avoid overwriting + routes from other sources (e.g. kernel device routes). Metric 0 has a + special meaning of undefined metric, in which either OS default is used, + or per-route metric can be set using graceful restart Participate in graceful restart recovery. If this option is enabled and a graceful restart recovery is active, the Kernel protocol will defer @@ -2420,9 +2431,11 @@ these attributes: route. See /etc/iproute2/rt_protos for common values. On BSD, it is based on STATIC and PROTOx flags. The attribute is read-only. - int + int (Linux) The kernel metric of the route. When multiple same routes are in a kernel routing table, the Linux kernel chooses one with lower metric. + Note that preferred way to set kernel metric is to use protocol option + ip (Linux) The preferred source address. Used in source address selection for diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index 076870f5..96688e34 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -88,6 +88,7 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; } struct krt_params { u32 table_id; /* Kernel table ID we sync with */ + u32 metric; /* Kernel metric used for all routes */ }; struct krt_state { diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index e9c225a2..a1c22f3e 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -10,8 +10,8 @@ CF_HDR CF_DECLS -CF_KEYWORDS(KERNEL, TABLE, KRT_PREFSRC, KRT_REALM, KRT_MTU, KRT_WINDOW, KRT_RTT, - KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING, +CF_KEYWORDS(KERNEL, TABLE, METRIC, KRT_PREFSRC, KRT_REALM, 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, KRT_LOCK_SSTRESH, KRT_LOCK_CWND, KRT_LOCK_ADVMSS, KRT_LOCK_REORDERING, @@ -22,9 +22,8 @@ CF_GRAMMAR CF_ADDTO(kern_proto, kern_proto kern_sys_item ';') kern_sys_item: - KERNEL TABLE expr { - THIS_KRT->sys.table_id = $3; - } + KERNEL TABLE expr { THIS_KRT->sys.table_id = $3; } + | METRIC expr { THIS_KRT->sys.metric = $2; } ; CF_ADDTO(dynamic_attr, KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); }) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 1ab1cda1..9bdcc0d2 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -880,6 +880,8 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d eattr *ea; net *net = e->net; rta *a = e->attrs; + u32 priority = 0; + struct { struct nlmsghdr h; struct rtmsg r; @@ -912,13 +914,20 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d else nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p)); + if (a->source == RTS_DUMMY) + priority = e->u.krt.metric; + else if (KRT_CF->sys.metric) + priority = KRT_CF->sys.metric; + else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC))) + priority = ea->u.data; + + if (priority) + nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, priority); + /* For route delete, we do not specify remaining route attributes */ if (op == NL_OP_DELETE) goto dest; - if (ea = ea_find(eattrs, EA_KRT_METRIC)) - nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data); - if (ea = ea_find(eattrs, EA_KRT_PREFSRC)) nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data); @@ -1585,19 +1594,21 @@ krt_sys_shutdown(struct krt_proto *p) int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o) { - return n->sys.table_id == o->sys.table_id; + return (n->sys.table_id == o->sys.table_id) && (n->sys.metric == o->sys.metric); } void krt_sys_init_config(struct krt_config *cf) { cf->sys.table_id = RT_TABLE_MAIN; + cf->sys.metric = 0; } void krt_sys_copy_config(struct krt_config *d, struct krt_config *s) { d->sys.table_id = s->sys.table_id; + d->sys.metric = s->sys.metric; } static const char *krt_metrics_names[KRT_METRICS_MAX] = {