From 70c2c36e0fe4ac5db4751fc09c9565b0972f6334 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 1 Nov 2021 11:32:13 +0100 Subject: [PATCH] qosify: update to latest version This improves bulk traffic detection. Signed-off-by: John Crispin --- feeds/ucentral/qosify/files/qosify.conf | 4 +- feeds/ucentral/qosify/files/qosify.init | 2 + feeds/ucentral/qosify/src/map.c | 89 ++++++++++++++++--------- feeds/ucentral/qosify/src/qosify-bpf.c | 74 +++++++++++--------- feeds/ucentral/qosify/src/qosify-bpf.h | 4 ++ 5 files changed, 112 insertions(+), 61 deletions(-) diff --git a/feeds/ucentral/qosify/files/qosify.conf b/feeds/ucentral/qosify/files/qosify.conf index d0e077b68..cf703a3bf 100644 --- a/feeds/ucentral/qosify/files/qosify.conf +++ b/feeds/ucentral/qosify/files/qosify.conf @@ -1,10 +1,12 @@ config defaults list defaults /etc/qosify-defaults.conf option dscp_prio CS5 + option dscp_icmp CS6 option dscp_bulk CS0 option dscp_default_udp CS4 option bulk_trigger_timeout 5 - option bulk_trigger_pps 0 + option bulk_trigger_pps 100 + option prio_max_avg_pkt_len 500 config interface wan option name wan diff --git a/feeds/ucentral/qosify/files/qosify.init b/feeds/ucentral/qosify/files/qosify.init index 20697e3ab..2546c2a7a 100644 --- a/feeds/ucentral/qosify/files/qosify.init +++ b/feeds/ucentral/qosify/files/qosify.init @@ -30,10 +30,12 @@ add_defaults() { add_option int timeout add_option string dscp_prio add_option string dscp_bulk + add_option string dscp_icmp add_option string dscp_default_udp add_option string dscp_default_tcp add_option int bulk_trigger_timeout add_option int bulk_trigger_pps + add_option int prio_max_avg_pkt_len } add_interface() { diff --git a/feeds/ucentral/qosify/src/map.c b/feeds/ucentral/qosify/src/map.c index 9d23caee1..0bb3eccaf 100644 --- a/feeds/ucentral/qosify/src/map.c +++ b/feeds/ucentral/qosify/src/map.c @@ -36,6 +36,34 @@ static const struct { [CL_MAP_CONFIG] = { "config", "config" }, }; +static const struct { + const char name[5]; + uint8_t val; +} codepoints[] = { + { "CS0", 0 }, + { "CS1", 8 }, + { "CS2", 16 }, + { "CS3", 24 }, + { "CS4", 32 }, + { "CS5", 40 }, + { "CS6", 48 }, + { "CS7", 56 }, + { "AF11", 10 }, + { "AF12", 12 }, + { "AF13", 14 }, + { "AF21", 18 }, + { "AF22", 20 }, + { "AF22", 22 }, + { "AF31", 26 }, + { "AF32", 28 }, + { "AF33", 30 }, + { "AF41", 34 }, + { "AF42", 36 }, + { "AF43", 38 }, + { "EF", 46 }, + { "VA", 44 }, +}; + static void qosify_map_timer_cb(struct uloop_timeout *t) { qosify_map_gc(); @@ -104,6 +132,8 @@ static void __qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val) int fd = qosify_map_fds[id]; int i; + val |= QOSIFY_DSCP_DEFAULT_FLAG; + for (i = 0; i < (1 << 16); i++) { data.addr.port = htons(i); if (avl_find(&map_data, &data)) @@ -159,38 +189,11 @@ static char *str_skip(char *str, bool space) static int qosify_map_codepoint(const char *val) { - static const struct { - const char name[5]; - uint8_t val; - } cp[] = { - { "CS0", 0 }, - { "CS1", 8 }, - { "CS2", 16 }, - { "CS3", 24 }, - { "CS4", 32 }, - { "CS5", 40 }, - { "CS6", 48 }, - { "CS7", 56 }, - { "AF11", 10 }, - { "AF12", 12 }, - { "AF13", 14 }, - { "AF21", 18 }, - { "AF22", 20 }, - { "AF22", 22 }, - { "AF31", 26 }, - { "AF32", 28 }, - { "AF33", 30 }, - { "AF41", 34 }, - { "AF42", 36 }, - { "AF43", 38 }, - { "EF", 46 }, - { "VA", 44 }, - }; int i; - for (i = 0; i < ARRAY_SIZE(cp); i++) - if (!strcmp(cp[i].name, val)) - return cp[i].val; + for (i = 0; i < ARRAY_SIZE(codepoints); i++) + if (!strcmp(codepoints[i].name, val)) + return codepoints[i].val; return 0xff; } @@ -351,6 +354,28 @@ int qosify_map_dscp_value(const char *val) return dscp + (fallback << 6); } +static void +qosify_map_dscp_codepoint_str(char *dest, int len, uint8_t dscp) +{ + int i; + + if (dscp & QOSIFY_DSCP_FALLBACK_FLAG) { + *(dest++) = '+'; + len--; + dscp &= ~QOSIFY_DSCP_FALLBACK_FLAG; + } + + for (i = 0; i < ARRAY_SIZE(codepoints); i++) { + if (codepoints[i].val != dscp) + continue; + + snprintf(dest, len, "%s", codepoints[i].name); + return; + } + + snprintf(dest, len, "0x%x", dscp); +} + static void qosify_map_parse_line(char *str) { @@ -543,6 +568,10 @@ void qosify_map_dump(struct blob_buf *b) blobmsg_add_u8(b, "file", e->data.file); blobmsg_add_u8(b, "user", e->data.user); + buf = blobmsg_alloc_string_buffer(b, "dscp", buf_len); + qosify_map_dscp_codepoint_str(buf, buf_len, e->data.dscp); + blobmsg_add_string_buffer(b); + blobmsg_add_string(b, "type", qosify_map_info[e->data.id].type_name); buf = blobmsg_alloc_string_buffer(b, "value", buf_len); diff --git a/feeds/ucentral/qosify/src/qosify-bpf.c b/feeds/ucentral/qosify/src/qosify-bpf.c index 49468c96e..48e143e5c 100644 --- a/feeds/ucentral/qosify/src/qosify-bpf.c +++ b/feeds/ucentral/qosify/src/qosify-bpf.c @@ -16,7 +16,6 @@ #include "qosify-bpf.h" #define INET_ECN_MASK 3 -#define DSCP_FALLBACK_FLAG BIT(6) #define FLOW_CHECK_INTERVAL ((u32)((1000000000ULL) >> 24)) #define FLOW_TIMEOUT ((u32)((30ULL * 1000000000ULL) >> 24)) @@ -211,33 +210,37 @@ static void parse_l4proto(struct qosify_config *config, struct __sk_buff *skb, __u32 offset, __u8 proto, __u8 *dscp_out) { - struct udphdr *udp = skb_ptr(skb, offset); - __u32 key; + struct udphdr *udp; + __u32 src, dest, key; __u8 *value; + udp = skb_ptr(skb, offset); if (skb_check(skb, &udp->len)) return; - if (module_flags & QOSIFY_INGRESS) - key = udp->source; - else - key = udp->dest; - - if (proto == IPPROTO_TCP) - value = bpf_map_lookup_elem(&tcp_ports, &key); - else if (proto == IPPROTO_UDP) - value = bpf_map_lookup_elem(&udp_ports, &key); - else { - if ((proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) && - config && config->dscp_icmp != 0xff) - *dscp_out = config->dscp_icmp; + if (config && (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)) { + *dscp_out = config->dscp_icmp; return; } - if (!value) - return; + src = udp->source; + dest = udp->dest; - if ((*value & DSCP_FALLBACK_FLAG) && *dscp_out) + if (module_flags & QOSIFY_INGRESS) + key = src; + else + key = dest; + + if (proto == IPPROTO_TCP) { + value = bpf_map_lookup_elem(&tcp_ports, &key); + } else { + if (proto != IPPROTO_UDP) + key = 0; + + value = bpf_map_lookup_elem(&udp_ports, &key); + } + + if (!value) return; *dscp_out = *value; @@ -253,9 +256,16 @@ check_flow(struct qosify_config *config, struct __sk_buff *skb, __u32 hash; __u32 time; + if (!(*dscp & QOSIFY_DSCP_DEFAULT_FLAG)) + return; + if (!config) return; + if (!config->bulk_trigger_pps && + !config->prio_max_avg_pkt_len) + return; + time = cur_time(); hash = bpf_get_hash_recalc(skb); flow = bpf_map_lookup_elem(&flow_map, &hash); @@ -287,7 +297,8 @@ check_flow(struct qosify_config *config, struct __sk_buff *skb, if (flow->pkt_count < 0xffff) flow->pkt_count++; - if (flow->pkt_count > config->bulk_trigger_pps) { + if (config->bulk_trigger_pps && + flow->pkt_count > config->bulk_trigger_pps) { flow->dscp = config->dscp_bulk; flow->bulk_timeout = config->bulk_trigger_timeout; } @@ -302,8 +313,7 @@ out: flow->dscp = 0xff; } - if (flow->dscp != 0xff && - !(*dscp && (flow->dscp & DSCP_FALLBACK_FLAG))) + if (flow->dscp != 0xff) *dscp = flow->dscp; return; @@ -324,8 +334,9 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset) struct qosify_config *config; const __u32 zero_port = 0; struct iphdr *iph; - __u8 dscp = 0; + __u8 dscp = 0xff; __u8 *value; + __u8 ipproto; int hdr_len; void *key; bool force; @@ -337,7 +348,7 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset) return; hdr_len = iph->ihl * 4; - if (bpf_skb_pull_data(skb, *offset + hdr_len)) + if (bpf_skb_pull_data(skb, *offset + hdr_len + sizeof(struct udphdr))) return; iph = skb_ptr(skb, *offset); @@ -346,7 +357,8 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset) if (skb_check(skb, (void *)(iph + 1))) return; - parse_l4proto(config, skb, *offset, iph->protocol, &dscp); + ipproto = iph->protocol; + parse_l4proto(config, skb, *offset, ipproto, &dscp); if (module_flags & QOSIFY_INGRESS) key = &iph->saddr; @@ -355,14 +367,14 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset) value = bpf_map_lookup_elem(&ipv4_map, key); /* use udp port 0 entry as fallback for non-tcp/udp */ - if (!value) + if (!value && dscp == 0xff) value = bpf_map_lookup_elem(&udp_ports, &zero_port); if (value) dscp = *value; check_flow(config, skb, &dscp); - force = !(dscp & DSCP_FALLBACK_FLAG); + force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG); dscp &= GENMASK(5, 0); ipv4_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force); @@ -376,12 +388,13 @@ parse_ipv6(struct __sk_buff *skb, __u32 *offset) struct ipv6hdr *iph; __u8 dscp = 0; __u8 *value; + __u8 ipproto; void *key; bool force; config = get_config(); - if (bpf_skb_pull_data(skb, *offset + sizeof(*iph))) + if (bpf_skb_pull_data(skb, *offset + sizeof(*iph) + sizeof(struct udphdr))) return; iph = skb_ptr(skb, *offset); @@ -390,12 +403,13 @@ parse_ipv6(struct __sk_buff *skb, __u32 *offset) if (skb_check(skb, (void *)(iph + 1))) return; + ipproto = iph->nexthdr; if (module_flags & QOSIFY_INGRESS) key = &iph->saddr; else key = &iph->daddr; - parse_l4proto(config, skb, *offset, iph->nexthdr, &dscp); + parse_l4proto(config, skb, *offset, ipproto, &dscp); value = bpf_map_lookup_elem(&ipv6_map, key); @@ -407,7 +421,7 @@ parse_ipv6(struct __sk_buff *skb, __u32 *offset) check_flow(config, skb, &dscp); - force = !(dscp & DSCP_FALLBACK_FLAG); + force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG); dscp &= GENMASK(5, 0); ipv6_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force); diff --git a/feeds/ucentral/qosify/src/qosify-bpf.h b/feeds/ucentral/qosify/src/qosify-bpf.h index b7b4f2aad..fd4eaa4bc 100644 --- a/feeds/ucentral/qosify/src/qosify-bpf.h +++ b/feeds/ucentral/qosify/src/qosify-bpf.h @@ -11,6 +11,10 @@ #define QOSIFY_INGRESS (1 << 0) #define QOSIFY_IP_ONLY (1 << 1) + +#define QOSIFY_DSCP_FALLBACK_FLAG (1 << 6) +#define QOSIFY_DSCP_DEFAULT_FLAG (1 << 7) + /* global config data */ struct qosify_config { uint8_t dscp_prio;