qosify: update to latest version

This improves bulk traffic detection.

Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin
2021-11-01 11:32:13 +01:00
parent 11ed0b089c
commit 70c2c36e0f
5 changed files with 112 additions and 61 deletions

View File

@@ -1,10 +1,12 @@
config defaults config defaults
list defaults /etc/qosify-defaults.conf list defaults /etc/qosify-defaults.conf
option dscp_prio CS5 option dscp_prio CS5
option dscp_icmp CS6
option dscp_bulk CS0 option dscp_bulk CS0
option dscp_default_udp CS4 option dscp_default_udp CS4
option bulk_trigger_timeout 5 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 config interface wan
option name wan option name wan

View File

@@ -30,10 +30,12 @@ add_defaults() {
add_option int timeout add_option int timeout
add_option string dscp_prio add_option string dscp_prio
add_option string dscp_bulk add_option string dscp_bulk
add_option string dscp_icmp
add_option string dscp_default_udp add_option string dscp_default_udp
add_option string dscp_default_tcp add_option string dscp_default_tcp
add_option int bulk_trigger_timeout add_option int bulk_trigger_timeout
add_option int bulk_trigger_pps add_option int bulk_trigger_pps
add_option int prio_max_avg_pkt_len
} }
add_interface() { add_interface() {

View File

@@ -36,6 +36,34 @@ static const struct {
[CL_MAP_CONFIG] = { "config", "config" }, [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) static void qosify_map_timer_cb(struct uloop_timeout *t)
{ {
qosify_map_gc(); 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 fd = qosify_map_fds[id];
int i; int i;
val |= QOSIFY_DSCP_DEFAULT_FLAG;
for (i = 0; i < (1 << 16); i++) { for (i = 0; i < (1 << 16); i++) {
data.addr.port = htons(i); data.addr.port = htons(i);
if (avl_find(&map_data, &data)) if (avl_find(&map_data, &data))
@@ -159,38 +189,11 @@ static char *str_skip(char *str, bool space)
static int static int
qosify_map_codepoint(const char *val) 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; int i;
for (i = 0; i < ARRAY_SIZE(cp); i++) for (i = 0; i < ARRAY_SIZE(codepoints); i++)
if (!strcmp(cp[i].name, val)) if (!strcmp(codepoints[i].name, val))
return cp[i].val; return codepoints[i].val;
return 0xff; return 0xff;
} }
@@ -351,6 +354,28 @@ int qosify_map_dscp_value(const char *val)
return dscp + (fallback << 6); 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 static void
qosify_map_parse_line(char *str) 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, "file", e->data.file);
blobmsg_add_u8(b, "user", e->data.user); 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); blobmsg_add_string(b, "type", qosify_map_info[e->data.id].type_name);
buf = blobmsg_alloc_string_buffer(b, "value", buf_len); buf = blobmsg_alloc_string_buffer(b, "value", buf_len);

View File

@@ -16,7 +16,6 @@
#include "qosify-bpf.h" #include "qosify-bpf.h"
#define INET_ECN_MASK 3 #define INET_ECN_MASK 3
#define DSCP_FALLBACK_FLAG BIT(6)
#define FLOW_CHECK_INTERVAL ((u32)((1000000000ULL) >> 24)) #define FLOW_CHECK_INTERVAL ((u32)((1000000000ULL) >> 24))
#define FLOW_TIMEOUT ((u32)((30ULL * 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, parse_l4proto(struct qosify_config *config, struct __sk_buff *skb,
__u32 offset, __u8 proto, __u8 *dscp_out) __u32 offset, __u8 proto, __u8 *dscp_out)
{ {
struct udphdr *udp = skb_ptr(skb, offset); struct udphdr *udp;
__u32 key; __u32 src, dest, key;
__u8 *value; __u8 *value;
udp = skb_ptr(skb, offset);
if (skb_check(skb, &udp->len)) if (skb_check(skb, &udp->len))
return; return;
if (module_flags & QOSIFY_INGRESS) if (config && (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)) {
key = udp->source; *dscp_out = config->dscp_icmp;
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;
return; return;
} }
if (!value) src = udp->source;
return; 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; return;
*dscp_out = *value; *dscp_out = *value;
@@ -253,9 +256,16 @@ check_flow(struct qosify_config *config, struct __sk_buff *skb,
__u32 hash; __u32 hash;
__u32 time; __u32 time;
if (!(*dscp & QOSIFY_DSCP_DEFAULT_FLAG))
return;
if (!config) if (!config)
return; return;
if (!config->bulk_trigger_pps &&
!config->prio_max_avg_pkt_len)
return;
time = cur_time(); time = cur_time();
hash = bpf_get_hash_recalc(skb); hash = bpf_get_hash_recalc(skb);
flow = bpf_map_lookup_elem(&flow_map, &hash); 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) if (flow->pkt_count < 0xffff)
flow->pkt_count++; 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->dscp = config->dscp_bulk;
flow->bulk_timeout = config->bulk_trigger_timeout; flow->bulk_timeout = config->bulk_trigger_timeout;
} }
@@ -302,8 +313,7 @@ out:
flow->dscp = 0xff; flow->dscp = 0xff;
} }
if (flow->dscp != 0xff && if (flow->dscp != 0xff)
!(*dscp && (flow->dscp & DSCP_FALLBACK_FLAG)))
*dscp = flow->dscp; *dscp = flow->dscp;
return; return;
@@ -324,8 +334,9 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset)
struct qosify_config *config; struct qosify_config *config;
const __u32 zero_port = 0; const __u32 zero_port = 0;
struct iphdr *iph; struct iphdr *iph;
__u8 dscp = 0; __u8 dscp = 0xff;
__u8 *value; __u8 *value;
__u8 ipproto;
int hdr_len; int hdr_len;
void *key; void *key;
bool force; bool force;
@@ -337,7 +348,7 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset)
return; return;
hdr_len = iph->ihl * 4; 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; return;
iph = skb_ptr(skb, *offset); iph = skb_ptr(skb, *offset);
@@ -346,7 +357,8 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset)
if (skb_check(skb, (void *)(iph + 1))) if (skb_check(skb, (void *)(iph + 1)))
return; return;
parse_l4proto(config, skb, *offset, iph->protocol, &dscp); ipproto = iph->protocol;
parse_l4proto(config, skb, *offset, ipproto, &dscp);
if (module_flags & QOSIFY_INGRESS) if (module_flags & QOSIFY_INGRESS)
key = &iph->saddr; key = &iph->saddr;
@@ -355,14 +367,14 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset)
value = bpf_map_lookup_elem(&ipv4_map, key); value = bpf_map_lookup_elem(&ipv4_map, key);
/* use udp port 0 entry as fallback for non-tcp/udp */ /* 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); value = bpf_map_lookup_elem(&udp_ports, &zero_port);
if (value) if (value)
dscp = *value; dscp = *value;
check_flow(config, skb, &dscp); check_flow(config, skb, &dscp);
force = !(dscp & DSCP_FALLBACK_FLAG); force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG);
dscp &= GENMASK(5, 0); dscp &= GENMASK(5, 0);
ipv4_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force); 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; struct ipv6hdr *iph;
__u8 dscp = 0; __u8 dscp = 0;
__u8 *value; __u8 *value;
__u8 ipproto;
void *key; void *key;
bool force; bool force;
config = get_config(); 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; return;
iph = skb_ptr(skb, *offset); iph = skb_ptr(skb, *offset);
@@ -390,12 +403,13 @@ parse_ipv6(struct __sk_buff *skb, __u32 *offset)
if (skb_check(skb, (void *)(iph + 1))) if (skb_check(skb, (void *)(iph + 1)))
return; return;
ipproto = iph->nexthdr;
if (module_flags & QOSIFY_INGRESS) if (module_flags & QOSIFY_INGRESS)
key = &iph->saddr; key = &iph->saddr;
else else
key = &iph->daddr; 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); 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); check_flow(config, skb, &dscp);
force = !(dscp & DSCP_FALLBACK_FLAG); force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG);
dscp &= GENMASK(5, 0); dscp &= GENMASK(5, 0);
ipv6_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force); ipv6_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force);

View File

@@ -11,6 +11,10 @@
#define QOSIFY_INGRESS (1 << 0) #define QOSIFY_INGRESS (1 << 0)
#define QOSIFY_IP_ONLY (1 << 1) #define QOSIFY_IP_ONLY (1 << 1)
#define QOSIFY_DSCP_FALLBACK_FLAG (1 << 6)
#define QOSIFY_DSCP_DEFAULT_FLAG (1 << 7)
/* global config data */ /* global config data */
struct qosify_config { struct qosify_config {
uint8_t dscp_prio; uint8_t dscp_prio;