u32 rta_flow;
};
- "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
+/*
+ * 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,
+ },
++ [RTAX_CC_ALGO] = {
++ .name = "krt_congctl",
++ .type = T_STRING,
++ },
+#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",
++ "congctl"
+};
+
+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
*/
return NULL;
}
-STATIC_ASSERT(EA_KRT_METRICS + RTAX_CC_ALGO == EA_KRT_CONGCTL);
-
static void
- nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, int max)
+ nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, const char *cc_algo, int max)
{
struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS);
int t;
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;
+
+ if (id == RTAX_CC_ALGO)
+ cc_algo = ea->u.ptr->data;
+ else
+ metrics[id] = ea->u.data;
}
if (metrics[0])
- nl_add_metrics(&r->h, rsize, metrics, KRT_METRICS_MAX);
+ nl_add_metrics(&r->h, rsize, metrics, cc_algo, KRT_METRICS_MAX);
- switch (a->dest)
+ switch (dest)
{
case RTD_UNICAST:
r->r.rtm_type = RTN_UNICAST;
if (a[RTA_METRICS])
{
u32 metrics[KRT_METRICS_MAX];
- if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
+ const char *cc_algo = NULL;
- ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr));
- int t, n = 0;
+
+ if (nl_parse_metrics(a[RTA_METRICS], metrics, &cc_algo, ARRAY_SIZE(metrics)) < 0)
{
- log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr);
+ log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net);
return;
}
- for (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,
- EA_LITERAL_EMBEDDED(&ea_krt_metrics[t], 0, metrics[t]));
+ if (t == RTAX_CC_ALGO)
- {
- struct adata *ad = lp_alloc_adata(s->pool, strlen(cc_algo));
- memcpy(ad->data, cc_algo, ad->length);
-
- ea->attrs[n++] = (eattr) {
- .id = EA_KRT_CONGCTL,
- .type = EAF_TYPE_STRING,
- .u.ptr = ad,
- };
- }
++ ea_set_attr(&ra, EA_LITERAL_STORE_ADATA(&ea_krt_metrics[t], 0, cc_algo, strlen(cc_algo)));
+ else
- {
- ea->attrs[n++] = (eattr) {
- .id = EA_KRT_METRICS + t,
- .type = EAF_TYPE_INT, /* FIXME: Some are EAF_TYPE_BITFIELD */
- .u.data = metrics[t],
- };
- }
-
- if (n > 0)
- {
- ea->next = ra->eattrs;
- ea->flags = EALF_SORTED;
- ea->count = n;
- ra->eattrs = ea;
- }
++ ea_set_attr(&ra, EA_LITERAL_EMBEDDED(&ea_krt_metrics[t], 0, metrics[t]));
}
- rte *e = rte_get_temp(ra, p->p.main_source);
- e->net = net;
+ rte e0 = {
+ .net = net,
+ .attrs = ra,
+ };
if (s->scan)
- krt_got_route(p, e, krt_src);
+ krt_got_route(p, &e0, krt_src);
else
- krt_got_route_async(p, e, new, krt_src);
+ krt_got_route_async(p, &e0, new, krt_src);
lp_flush(s->pool);
}