0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 17:51:53 +00:00

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!
This commit is contained in:
Ondrej Zajicek 2024-02-14 14:01:04 +01:00
parent 224a152c53
commit 225943eaea
4 changed files with 73 additions and 23 deletions

View File

@ -3962,15 +3962,15 @@ these attributes:
<p>In Linux, there is also a plenty of obscure route attributes mostly focused <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 on tuning TCP performance of local connections. BIRD supports most of these
attributes, see Linux or iproute2 documentation for their meaning. Attributes attributes, see Linux or iproute2 documentation for their meaning. Attributes
<cf/krt_lock_*/ and <cf/krt_feature_*/ have type bool, others have type int. <cf/krt_lock_*/ and <cf/krt_feature_*/ have type bool, <cf/krt_congctl/ has type
Supported attributes are: string, others have type int. Supported attributes are:
<cf/krt_mtu/, <cf/krt_lock_mtu/, <cf/krt_window/, <cf/krt_lock_window/, <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_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_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_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_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/ <cf/krt_feature_ecn/, <cf/krt_feature_allfrag/
<sect1>Example <sect1>Example

View 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 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_METRICS_OFFSET 0x20 /* Offset of EA_KRT_* vs RTAX_* */
#define KRT_FEATURES_MAX 4 #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_RTO_MIN EA_CODE(PROTOCOL_KERNEL, 0x2d)
#define EA_KRT_INITRWND EA_CODE(PROTOCOL_KERNEL, 0x2e) #define EA_KRT_INITRWND EA_CODE(PROTOCOL_KERNEL, 0x2e)
#define EA_KRT_QUICKACK EA_CODE(PROTOCOL_KERNEL, 0x2f) #define EA_KRT_QUICKACK EA_CODE(PROTOCOL_KERNEL, 0x2f)
#define EA_KRT_CONGCTL EA_CODE(PROTOCOL_KERNEL, 0x30)
struct krt_params { struct krt_params {

View File

@ -14,7 +14,7 @@ CF_KEYWORDS(KERNEL, TABLE, METRIC, NETLINK, RX, BUFFER,
KRT_PREFSRC, KRT_REALM, KRT_SCOPE, KRT_MTU, KRT_WINDOW, KRT_PREFSRC, KRT_REALM, KRT_SCOPE, KRT_MTU, KRT_WINDOW,
KRT_RTT, KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING, KRT_RTT, KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING,
KRT_HOPLIMIT, KRT_INITCWND, KRT_RTO_MIN, KRT_INITRWND, KRT_QUICKACK, 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_SSTRESH, KRT_LOCK_CWND, KRT_LOCK_ADVMSS, KRT_LOCK_REORDERING,
KRT_LOCK_HOPLIMIT, KRT_LOCK_RTO_MIN, KRT_FEATURE_ECN, KRT_FEATURE_ALLFRAG) 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_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_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_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 */ /* Bits of EA_KRT_LOCK, based on RTAX_* constants */

View File

@ -479,6 +479,9 @@ static inline u16 rta_get_u16(struct rtattr *a)
static inline u32 rta_get_u32(struct rtattr *a) static inline u32 rta_get_u32(struct rtattr *a)
{ return *(u32 *) RTA_DATA(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) static inline ip4_addr rta_get_ip4(struct rtattr *a)
{ return ip4_ntoh(*(ip4_addr *) RTA_DATA(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); 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 static inline void
nl_add_attr_ip4(struct nlmsghdr *h, uint bufsize, int code, ip4_addr ip4) nl_add_attr_ip4(struct nlmsghdr *h, uint bufsize, int code, ip4_addr ip4)
{ {
@ -822,21 +831,26 @@ err:
return NULL; return NULL;
} }
STATIC_ASSERT(EA_KRT_METRICS + RTAX_CC_ALGO == EA_KRT_CONGCTL);
static void 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); struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS);
int t; int t;
for (t = 1; t < max; t++) for (t = 1; t < max; t++)
if (metrics[0] & (1 << t)) if (metrics[0] & (1 << 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_add_attr_u32(h, bufsize, t, metrics[t]);
nl_close_attr(h, a); nl_close_attr(h, a);
} }
static int 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); struct rtattr *a = RTA_DATA(hdr);
int len = RTA_PAYLOAD(hdr); int len = RTA_PAYLOAD(hdr);
@ -844,18 +858,32 @@ nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
metrics[0] = 0; metrics[0] = 0;
for (; RTA_OK(a, len); a = RTA_NEXT(a, len)) for (; RTA_OK(a, len); a = RTA_NEXT(a, len))
{ {
if (a->rta_type == RTA_UNSPEC) if (a->rta_type == RTAX_UNSPEC)
continue; continue;
if (a->rta_type >= max) if (a->rta_type >= max)
continue; continue;
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] = 0;
}
else
{
if (RTA_PAYLOAD(a) != 4) if (RTA_PAYLOAD(a) != 4)
return -1; return -1;
metrics[0] |= 1 << a->rta_type; metrics[0] |= 1 << a->rta_type;
metrics[a->rta_type] = rta_get_u32(a); metrics[a->rta_type] = rta_get_u32(a);
} }
}
if (len > 0) if (len > 0)
return -1; return -1;
@ -1382,6 +1410,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op)
u32 metrics[KRT_METRICS_MAX]; u32 metrics[KRT_METRICS_MAX];
const char *cc_algo = NULL;
metrics[0] = 0; metrics[0] = 0;
struct ea_walk_state ews = { .eattrs = eattrs }; 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; int id = ea->id - EA_KRT_METRICS;
metrics[0] |= 1 << id; metrics[0] |= 1 << id;
if (id == RTAX_CC_ALGO)
cc_algo = ea->u.ptr->data;
else
metrics[id] = ea->u.data; metrics[id] = ea->u.data;
} }
if (metrics[0]) 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 (a->dest)
{ {
@ -1795,10 +1828,11 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (a[RTA_METRICS]) if (a[RTA_METRICS])
{ {
u32 metrics[KRT_METRICS_MAX]; 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)); ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr));
int t, n = 0; 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); log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr);
return; return;
@ -1806,12 +1840,25 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
for (t = 1; t < KRT_METRICS_MAX; t++) for (t = 1; t < KRT_METRICS_MAX; t++)
if (metrics[0] & (1 << t)) if (metrics[0] & (1 << 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) { ea->attrs[n++] = (eattr) {
.id = EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t), .id = EA_KRT_CONGCTL,
.flags = 0, .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 */ .type = EAF_TYPE_INT, /* FIXME: Some are EAF_TYPE_BITFIELD */
.u.data = metrics[t], .u.data = metrics[t],
}; };
}
if (n > 0) 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] = { static const char *krt_metrics_names[KRT_METRICS_MAX] = {
NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss", 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] = { static const char *krt_features_names[KRT_FEATURES_MAX] = {