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.
This commit is contained in:
Ondrej Zajicek (work) 2016-09-15 14:59:06 +02:00
parent 2feaa6931b
commit 4adcb9df1b
4 changed files with 34 additions and 10 deletions

View file

@ -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.
<tag>metric <m/number/</tag> (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 <cf/krt_metric/ attribute. Default:
0 (undefined).
<tag>graceful restart <m/switch/</tag>
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.
<tag>int <cf/krt_metric/</tag>
<tag>int <cf/krt_metric/</tag> (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
<cf/metric/, unless per-route metric values are needed.
<tag>ip <cf/krt_prefsrc/</tag> (Linux)
The preferred source address. Used in source address selection for

View file

@ -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 {

View file

@ -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); })

View file

@ -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] = {