]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Add support for setting TCP congestion control algorithm
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 14 Feb 2024 13:01:04 +0000 (14:01 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 14 Feb 2024 13:29:19 +0000 (14:29 +0100)
Allow to set TCP congestion control algorithm using krt_congctl
route attribute.

Based on patch from Trisha Biswas <tbiswas@fastly.com>, thanks!

doc/bird.sgml
sysdep/linux/krt-sys.h
sysdep/linux/netlink.Y
sysdep/linux/netlink.c

index 79d5873f8fe64b877053e9a2dba7afbef62d33da..5d59ae4dbb99c664715c77f56c2ff812b4ce5b01 100644 (file)
@@ -3962,15 +3962,15 @@ these attributes:
 <p>In Linux, there is also a plenty of obscure route attributes mostly focused
 on tuning TCP performance of local connections. BIRD supports most of these
 attributes, see Linux or iproute2 documentation for their meaning. Attributes
-<cf/krt_lock_*/ and <cf/krt_feature_*/ have type bool, others have type int.
-Supported attributes are:
+<cf/krt_lock_*/ and <cf/krt_feature_*/ have type bool, <cf/krt_congctl/ has type
+string, others have type int. Supported attributes are:
 
 <cf/krt_mtu/, <cf/krt_lock_mtu/, <cf/krt_window/, <cf/krt_lock_window/,
 <cf/krt_rtt/, <cf/krt_lock_rtt/, <cf/krt_rttvar/, <cf/krt_lock_rttvar/,
 <cf/krt_sstresh/, <cf/krt_lock_sstresh/, <cf/krt_cwnd/, <cf/krt_lock_cwnd/,
 <cf/krt_advmss/, <cf/krt_lock_advmss/, <cf/krt_reordering/, <cf/krt_lock_reordering/,
 <cf/krt_hoplimit/, <cf/krt_lock_hoplimit/, <cf/krt_rto_min/, <cf/krt_lock_rto_min/,
-<cf/krt_initcwnd/, <cf/krt_initrwnd/, <cf/krt_quickack/,
+<cf/krt_initcwnd/, <cf/krt_initrwnd/, <cf/krt_quickack/, <cf/krt_congctl/,
 <cf/krt_feature_ecn/, <cf/krt_feature_allfrag/
 
 <sect1>Example
index 8897f889fbff8a2b660d68d6e533988c421e3ef9..7c20a09e0f25f228ea4f0c5618bc143eab549842 100644 (file)
@@ -39,7 +39,7 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N
 #define EA_KRT_SCOPE           EA_CODE(PROTOCOL_KERNEL, 0x12)
 
 
-#define KRT_METRICS_MAX                0x10    /* RTAX_QUICKACK+1 */
+#define KRT_METRICS_MAX                0x11    /* RTAX_CC_ALGO+1 */
 #define KRT_METRICS_OFFSET     0x20    /* Offset of EA_KRT_* vs RTAX_* */
 
 #define KRT_FEATURES_MAX       4
@@ -64,6 +64,7 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N
 #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)
+#define EA_KRT_CONGCTL         EA_CODE(PROTOCOL_KERNEL, 0x30)
 
 
 struct krt_params {
index 487ad1d8e10f7dc12a6360de218e6f7e6e515310..70b83dafeb3078843f62518254e2d063a113b96b 100644 (file)
@@ -14,7 +14,7 @@ CF_KEYWORDS(KERNEL, TABLE, METRIC, NETLINK, RX, BUFFER,
            KRT_PREFSRC, KRT_REALM, KRT_SCOPE, 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_CONGCTL, KRT_LOCK_MTU, KRT_LOCK_WINDOW, KRT_LOCK_RTT, KRT_LOCK_RTTVAR,
            KRT_LOCK_SSTRESH, KRT_LOCK_CWND, KRT_LOCK_ADVMSS, KRT_LOCK_REORDERING,
            KRT_LOCK_HOPLIMIT, KRT_LOCK_RTO_MIN, KRT_FEATURE_ECN, KRT_FEATURE_ALLFRAG)
 
@@ -45,6 +45,7 @@ dynamic_attr: KRT_INITCWND    { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT
 dynamic_attr: KRT_RTO_MIN      { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); } ;
 dynamic_attr: KRT_INITRWND     { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); } ;
 dynamic_attr: KRT_QUICKACK     { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); } ;
+dynamic_attr: KRT_CONGCTL      { $$ = f_new_dynamic_attr(EAF_TYPE_STRING, T_STRING, EA_KRT_CONGCTL); } ;
 
 /* Bits of EA_KRT_LOCK, based on RTAX_* constants */
 
index 29446cab3899bfa02fa43411f31a5245b5b0e571..fb54de391468f3b958f444c0222425e5b326621d 100644 (file)
@@ -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)); }
 
@@ -569,6 +572,12 @@ nl_add_attr_u32(struct nlmsghdr *h, uint bufsize, int code, u32 data)
   nl_add_attr(h, bufsize, code, &data, 4);
 }
 
+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)
 {
@@ -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] = {