summaryrefslogtreecommitdiff
path: root/sysdep/linux/netlink.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2024-02-14 14:01:04 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2024-02-14 14:29:19 +0100
commit225943eaea3cdd634dce8fd84547baf1bc363640 (patch)
treef886cdf942a8da49a5fb1f167a27a47c48be4050 /sysdep/linux/netlink.c
parent224a152c53f304881f8616a1c9255b467062a069 (diff)
Filter: Add support for setting TCP congestion control algorithm
Allow to set TCP congestion control algorithm using krt_congctl route attribute. Based on patch from Trisha Biswas <tbiswas@fastly.com>, thanks!
Diffstat (limited to 'sysdep/linux/netlink.c')
-rw-r--r--sysdep/linux/netlink.c84
1 files changed, 66 insertions, 18 deletions
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index 29446cab..fb54de39 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -479,6 +479,9 @@ static inline u16 rta_get_u16(struct rtattr *a)
static inline u32 rta_get_u32(struct rtattr *a)
{ return *(u32 *) RTA_DATA(a); }
+static inline const char *rta_get_str(struct rtattr *a)
+{ return RTA_DATA(a); }
+
static inline ip4_addr rta_get_ip4(struct rtattr *a)
{ return ip4_ntoh(*(ip4_addr *) RTA_DATA(a)); }
@@ -570,6 +573,12 @@ nl_add_attr_u32(struct nlmsghdr *h, uint bufsize, int code, u32 data)
}
static inline void
+nl_add_attr_str(struct nlmsghdr *h, unsigned bufsize, int code, const char *str)
+{
+ nl_add_attr(h, bufsize, code, str, strlen(str) + 1);
+}
+
+static inline void
nl_add_attr_ip4(struct nlmsghdr *h, uint bufsize, int code, ip4_addr ip4)
{
ip4 = ip4_hton(ip4);
@@ -822,21 +831,26 @@ err:
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;
for (t = 1; t < max; t++)
if (metrics[0] & (1 << t))
- nl_add_attr_u32(h, bufsize, t, metrics[t]);
+ if (t == RTAX_CC_ALGO)
+ nl_add_attr_str(h, bufsize, t, cc_algo);
+ else
+ nl_add_attr_u32(h, bufsize, t, metrics[t]);
nl_close_attr(h, a);
}
static int
-nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
+nl_parse_metrics(struct rtattr *hdr, u32 *metrics, const char **cc_algo, int max)
{
struct rtattr *a = RTA_DATA(hdr);
int len = RTA_PAYLOAD(hdr);
@@ -844,17 +858,31 @@ nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
metrics[0] = 0;
for (; RTA_OK(a, len); a = RTA_NEXT(a, len))
{
- if (a->rta_type == RTA_UNSPEC)
+ if (a->rta_type == RTAX_UNSPEC)
continue;
if (a->rta_type >= max)
continue;
- if (RTA_PAYLOAD(a) != 4)
- return -1;
+ if (a->rta_type == RTAX_CC_ALGO)
+ {
+ *cc_algo = rta_get_str(a);
+ int slen = RTA_PAYLOAD(a);
+
+ if (!slen || ((*cc_algo)[slen - 1] != 0))
+ return -1;
- metrics[0] |= 1 << a->rta_type;
- metrics[a->rta_type] = rta_get_u32(a);
+ metrics[0] |= 1 << a->rta_type;
+ metrics[a->rta_type] = 0;
+ }
+ else
+ {
+ if (RTA_PAYLOAD(a) != 4)
+ return -1;
+
+ metrics[0] |= 1 << a->rta_type;
+ metrics[a->rta_type] = rta_get_u32(a);
+ }
}
if (len > 0)
@@ -1382,6 +1410,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op)
u32 metrics[KRT_METRICS_MAX];
+ const char *cc_algo = NULL;
metrics[0] = 0;
struct ea_walk_state ews = { .eattrs = eattrs };
@@ -1389,11 +1418,15 @@ nl_send_route(struct krt_proto *p, rte *e, int op)
{
int id = ea->id - EA_KRT_METRICS;
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)
{
@@ -1795,10 +1828,11 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (a[RTA_METRICS])
{
u32 metrics[KRT_METRICS_MAX];
+ 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, ARRAY_SIZE(metrics)) < 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);
return;
@@ -1806,12 +1840,25 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
for (t = 1; t < KRT_METRICS_MAX; t++)
if (metrics[0] & (1 << t))
- ea->attrs[n++] = (eattr) {
- .id = EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t),
- .flags = 0,
- .type = EAF_TYPE_INT, /* FIXME: Some are EAF_TYPE_BITFIELD */
- .u.data = 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,
+ };
+ }
+ 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)
{
@@ -2094,7 +2141,8 @@ krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
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"
+ "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack",
+ "congctl"
};
static const char *krt_features_names[KRT_FEATURES_MAX] = {