1
0
mirror of https://gitlab.labs.nic.cz/labs/bird.git synced 2024-05-11 16:54:54 +00:00

Explicit definition structures of route attributes

Changes in internal API:

* Every route attribute must be defined as struct ea_class somewhere.
* Registration of route attributes known at startup must be done by
  ea_register_init() from protocol build functions.
* Every attribute has now its symbol registered in a global symbol table
  defined as SYM_ATTRIBUTE
* All attribute ID's are dynamically allocated.
* Attribute value custom formatting hook is defined in the ea_class.
* Attribute names are the same for display and filters, always prefixed
  by protocol name.

Also added some unit testing code for filters with route attributes.
This commit is contained in:
Maria Matejka
2022-03-19 16:23:42 +01:00
parent 165156beeb
commit 17f91f9e6e
54 changed files with 1056 additions and 878 deletions

View File

@@ -34,38 +34,6 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N
#define KRT_ALLOW_MERGE_PATHS 1
#define EA_KRT_PREFSRC EA_CODE(PROTOCOL_KERNEL, 0x10)
#define EA_KRT_REALM EA_CODE(PROTOCOL_KERNEL, 0x11)
#define EA_KRT_SCOPE EA_CODE(PROTOCOL_KERNEL, 0x12)
#define KRT_METRICS_MAX 0x10 /* RTAX_QUICKACK+1 */
#define KRT_METRICS_OFFSET 0x20 /* Offset of EA_KRT_* vs RTAX_* */
#define KRT_FEATURES_MAX 4
/*
* Following attributes are parts of RTA_METRICS kernel route attribute, their
* ids must be consistent with their RTAX_* constants (+ KRT_METRICS_OFFSET)
*/
#define EA_KRT_METRICS EA_CODE(PROTOCOL_KERNEL, 0x20) /* Dummy one */
#define EA_KRT_LOCK EA_CODE(PROTOCOL_KERNEL, 0x21)
#define EA_KRT_MTU EA_CODE(PROTOCOL_KERNEL, 0x22)
#define EA_KRT_WINDOW EA_CODE(PROTOCOL_KERNEL, 0x23)
#define EA_KRT_RTT EA_CODE(PROTOCOL_KERNEL, 0x24)
#define EA_KRT_RTTVAR EA_CODE(PROTOCOL_KERNEL, 0x25)
#define EA_KRT_SSTRESH EA_CODE(PROTOCOL_KERNEL, 0x26)
#define EA_KRT_CWND EA_CODE(PROTOCOL_KERNEL, 0x27)
#define EA_KRT_ADVMSS EA_CODE(PROTOCOL_KERNEL, 0x28)
#define EA_KRT_REORDERING EA_CODE(PROTOCOL_KERNEL, 0x29)
#define EA_KRT_HOPLIMIT EA_CODE(PROTOCOL_KERNEL, 0x2a)
#define EA_KRT_INITCWND EA_CODE(PROTOCOL_KERNEL, 0x2b)
#define EA_KRT_FEATURES EA_CODE(PROTOCOL_KERNEL, 0x2c)
#define EA_KRT_RTO_MIN EA_CODE(PROTOCOL_KERNEL, 0x2d)
#define EA_KRT_INITRWND EA_CODE(PROTOCOL_KERNEL, 0x2e)
#define EA_KRT_QUICKACK EA_CODE(PROTOCOL_KERNEL, 0x2f)
struct krt_params {
u32 table_id; /* Kernel table ID we sync with */
u32 metric; /* Kernel metric used for all routes */

View File

@@ -28,39 +28,22 @@ kern_sys_item:
| NETLINK RX BUFFER expr { THIS_KRT->sys.netlink_rx_buffer = $4; }
;
dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(T_IP, EA_KRT_PREFSRC); } ;
dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REALM); } ;
dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SCOPE); } ;
dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(T_INT, EA_KRT_MTU); } ;
dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(T_INT, EA_KRT_WINDOW); } ;
dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTT); } ;
dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTTVAR); } ;
dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SSTRESH); } ;
dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_CWND); } ;
dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(T_INT, EA_KRT_ADVMSS); } ;
dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REORDERING); } ;
dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_HOPLIMIT); } ;
dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITCWND); } ;
dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTO_MIN); } ;
dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITRWND); } ;
dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(T_INT, EA_KRT_QUICKACK); } ;
/* Bits of EA_KRT_LOCK, based on RTAX_* constants */
attr_bit: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, "krt_lock"); } ;
attr_bit: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, "krt_lock"); } ;
attr_bit: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, "krt_lock"); } ;
attr_bit: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, "krt_lock"); } ;
attr_bit: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, "krt_lock"); } ;
attr_bit: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, "krt_lock"); } ;
attr_bit: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, "krt_lock"); } ;
attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, "krt_lock"); } ;
attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, "krt_lock"); } ;
attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, "krt_lock"); } ;
attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, EA_KRT_FEATURES); } ;
attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, EA_KRT_FEATURES); } ;
/* Bits of EA_KRT_FEATURES */
attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, "krt_features"); } ;
attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, "krt_features"); } ;
CF_CODE

View File

@@ -26,6 +26,7 @@
#include "lib/socket.h"
#include "lib/string.h"
#include "lib/hash.h"
#include "lib/macro.h"
#include "conf/conf.h"
#include <asm/types.h>
@@ -121,6 +122,101 @@ struct nl_parse_state
u32 rta_flow; /* Used during parsing */
};
/*
* Netlink eattr definitions
*/
#define KRT_METRICS_MAX ARRAY_SIZE(ea_krt_metrics)
#define KRT_FEATURES_MAX 4
static void krt_bitfield_format(const eattr *e, byte *buf, uint buflen);
static struct ea_class
ea_krt_prefsrc = {
.name = "krt_prefsrc",
.type = T_IP,
},
ea_krt_realm = {
.name = "krt_realm",
.type = T_INT,
},
ea_krt_scope = {
.name = "krt_scope",
.type = T_INT,
};
static struct ea_class ea_krt_metrics[] = {
[RTAX_LOCK] = {
.name = "krt_lock",
.type = T_INT,
.format = krt_bitfield_format,
},
[RTAX_FEATURES] = {
.name = "krt_features",
.type = T_INT,
.format = krt_bitfield_format,
},
#define KRT_METRIC_INT(_rtax, _name) [_rtax] = { .name = _name, .type = T_INT }
KRT_METRIC_INT(RTAX_MTU, "krt_mtu"),
KRT_METRIC_INT(RTAX_WINDOW, "krt_window"),
KRT_METRIC_INT(RTAX_RTT, "krt_rtt"),
KRT_METRIC_INT(RTAX_RTTVAR, "krt_rttvar"),
KRT_METRIC_INT(RTAX_SSTHRESH, "krt_sstresh"),
KRT_METRIC_INT(RTAX_CWND, "krt_cwnd"),
KRT_METRIC_INT(RTAX_ADVMSS, "krt_advmss"),
KRT_METRIC_INT(RTAX_REORDERING, "krt_reordering"),
KRT_METRIC_INT(RTAX_HOPLIMIT, "krt_hoplimit"),
KRT_METRIC_INT(RTAX_INITCWND, "krt_initcwnd"),
KRT_METRIC_INT(RTAX_RTO_MIN, "krt_rto_min"),
KRT_METRIC_INT(RTAX_INITRWND, "krt_initrwnd"),
KRT_METRIC_INT(RTAX_QUICKACK, "krt_quickack"),
#undef KRT_METRIC_INT
};
static const char *krt_metrics_names[KRT_METRICS_MAX] = {
NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
"reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
};
static const char *krt_features_names[KRT_FEATURES_MAX] = {
"ecn", NULL, NULL, "allfrag"
};
static void
krt_bitfield_format(const eattr *a, byte *buf, uint buflen)
{
if (a->id == ea_krt_metrics[RTAX_LOCK].id)
ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
else if (a->id == ea_krt_metrics[RTAX_FEATURES].id)
ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
}
static void
nl_ea_register(void)
{
EA_REGISTER_ALL(
&ea_krt_prefsrc,
&ea_krt_realm,
&ea_krt_scope
);
for (uint i = 0; i < KRT_METRICS_MAX; i++)
{
if (!ea_krt_metrics[i].name)
ea_krt_metrics[i] = (struct ea_class) {
.name = mb_sprintf(&root_pool, "krt_metric_%d", i),
.type = T_INT,
};
ea_register_init(&ea_krt_metrics[i]);
}
for (uint i = 1; i < KRT_METRICS_MAX; i++)
ASSERT_DIE(ea_krt_metrics[i].id == ea_krt_metrics[0].id + i);
}
/*
* Synchronous Netlink interface
*/
@@ -734,7 +830,7 @@ static void
nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, ea_list *eattrs)
{
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
eattr *flow = ea_find(eattrs, EA_KRT_REALM);
eattr *flow = ea_find(eattrs, &ea_krt_realm);
for (; nh; nh = nh->next)
{
@@ -1399,7 +1495,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
priority = 0;
else if (KRT_CF->sys.metric)
priority = KRT_CF->sys.metric;
else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC)))
else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, &ea_krt_metric)))
priority = ea->u.data;
if (priority)
@@ -1412,15 +1508,15 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
/* Default scope is LINK for device routes, UNIVERSE otherwise */
if (p->af == AF_MPLS)
r->r.rtm_scope = RT_SCOPE_UNIVERSE;
else if (ea = ea_find(eattrs, EA_KRT_SCOPE))
else if (ea = ea_find(eattrs, &ea_krt_scope))
r->r.rtm_scope = ea->u.data;
else
r->r.rtm_scope = (dest == RTD_UNICAST && ipa_zero(nh->gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
if (ea = ea_find(eattrs, &ea_krt_prefsrc))
nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
if (ea = ea_find(eattrs, EA_KRT_REALM))
if (ea = ea_find(eattrs, &ea_krt_realm))
nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data);
@@ -1428,9 +1524,9 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
metrics[0] = 0;
struct ea_walk_state ews = { .eattrs = eattrs };
while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
while (ea = ea_walk(&ews, ea_krt_metrics[0].id, KRT_METRICS_MAX))
{
int id = ea->id - EA_KRT_METRICS;
int id = ea->id - ea_krt_metrics[0].id;
metrics[0] |= 1 << id;
metrics[id] = ea->u.data;
}
@@ -1581,21 +1677,15 @@ nl_announce_route(struct nl_parse_state *s)
rte *e = rte_get_temp(s->attrs, s->proto->p.main_source);
e->net = s->net;
EA_LOCAL_LIST(2) ea0 = {
EA_LOCAL_LIST(2) ea = {
.l = { .count = 2, .next = e->attrs->eattrs },
.a[0] = (eattr) {
.id = EA_KRT_SOURCE,
.type = T_INT,
.u.data = s->krt_proto,
},
.a[1] = (eattr) {
.id = EA_KRT_METRIC,
.type = T_INT,
.u.data = s->krt_metric,
.a = {
EA_LITERAL_EMBEDDED(&ea_krt_source, 0, s->krt_proto),
EA_LITERAL_EMBEDDED(&ea_krt_metric, 0, s->krt_metric),
},
};
e->attrs->eattrs = &ea0.l;
e->attrs->eattrs = &ea.l;
if (s->scan)
krt_got_route(s->proto, e, s->krt_src);
@@ -1867,20 +1957,20 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (i->rtm_scope != def_scope)
ea_set_attr(&ra->eattrs,
EA_LITERAL_EMBEDDED(EA_KRT_SCOPE, T_INT, 0, i->rtm_scope));
EA_LITERAL_EMBEDDED(&ea_krt_scope, 0, i->rtm_scope));
if (a[RTA_PREFSRC])
{
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
{
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
ea_set_attr(&ra->eattrs,
EA_LITERAL_STORE_ADATA(EA_KRT_PREFSRC, T_IP, 0, &ps, sizeof(ps)));
}
ea_set_attr(&ra->eattrs,
EA_LITERAL_STORE_ADATA(&ea_krt_prefsrc, 0, &ps, sizeof(ps)));
}
/* Can be set per-route or per-nexthop */
if (s->rta_flow)
ea_set_attr(&ra->eattrs,
EA_LITERAL_EMBEDDED(EA_KRT_REALM, T_INT, 0, s->rta_flow));
EA_LITERAL_EMBEDDED(&ea_krt_realm, 0, s->rta_flow));
if (a[RTA_METRICS])
{
@@ -1891,11 +1981,10 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
return;
}
for (int t = 1; t < KRT_METRICS_MAX; t++)
for (uint t = 1; t < KRT_METRICS_MAX; t++)
if (metrics[0] & (1 << t))
ea_set_attr(&ra->eattrs,
EA_LITERAL_EMBEDDED(EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t),
T_INT, 0, metrics[t]));
EA_LITERAL_EMBEDDED(&ea_krt_metrics[t], 0, metrics[t]));
}
/*
@@ -2133,6 +2222,8 @@ krt_sys_io_init(void)
{
nl_linpool = lp_new_default(krt_pool);
HASH_INIT(nl_table_map, krt_pool, 6);
nl_ea_register();
}
int
@@ -2186,56 +2277,6 @@ krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
d->sys.metric = s->sys.metric;
}
static const char *krt_metrics_names[KRT_METRICS_MAX] = {
NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
"reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
};
static const char *krt_features_names[KRT_FEATURES_MAX] = {
"ecn", NULL, NULL, "allfrag"
};
int
krt_sys_get_attr(const 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;
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);
return GA_FULL;
case EA_KRT_FEATURES:
buf += bsprintf(buf, "features:");
ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
return GA_FULL;
default:;
int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET;
if (id > 0 && id < KRT_METRICS_MAX)
{
bsprintf(buf, "%s", krt_metrics_names[id]);
return GA_NAME;
}
return GA_UNKNOWN;
}
}
void
kif_sys_start(struct kif_proto *p UNUSED)
{