mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-11-04 04:18:07 +00:00 
			
		
		
		
	qosify: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
		
							
								
								
									
										112
									
								
								feeds/ucentral/qosify/src/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								feeds/ucentral/qosify/src/README
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					QoSify is simple daemon for setting up and managing CAKE along with a custom
 | 
				
			||||||
 | 
					eBPF based classifier that sets DSCP fields of packets.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It supports the following features:
 | 
				
			||||||
 | 
					- simple TCP/UDP port based mapping
 | 
				
			||||||
 | 
					- IP address based mapping
 | 
				
			||||||
 | 
					- priority boosting based on average packet size
 | 
				
			||||||
 | 
					- bulk flow detection based on number of packets per second
 | 
				
			||||||
 | 
					- dynamically add IP entries with timeout
 | 
				
			||||||
 | 
					- dns regex entries and ubus api for providing dns lookup results
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It can be configured via ubus call qosify config.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This call supports the following parameters:
 | 
				
			||||||
 | 
					- "reset": BOOL
 | 
				
			||||||
 | 
						Reset the config to defaults instead of only updating supplied values
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "files": ARRAY of STRING
 | 
				
			||||||
 | 
						List of files with port/IP/host mappings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "timeout": INT32
 | 
				
			||||||
 | 
						Default timeout for dynamically added entries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "dscp_default_udp": STRING
 | 
				
			||||||
 | 
						Default DSCP value for UDP packets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "dscp_default_tcp": STRING
 | 
				
			||||||
 | 
						Default DSCP value for TCP packets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "dscp_prio": STRING
 | 
				
			||||||
 | 
						DSCP value for priority-marked packets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "dscp_bulk": STRING
 | 
				
			||||||
 | 
						DSCP value for bulk-marked packets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "dscp_icmp": STRING
 | 
				
			||||||
 | 
						DSCP value for ICMP packets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "bulk_trigger_pps": INT32
 | 
				
			||||||
 | 
						Number of packets per second to trigger bulk flow detection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "bulk_trigger_timeout": INT32
 | 
				
			||||||
 | 
						Time below bulk_trigger_pps threshold until a bulk flow mark is removed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "prio_max_avg_pkt_len": INT32
 | 
				
			||||||
 | 
						Maximum average packet length for marking a flow as priority
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "interfaces": TABLE of TABLE
 | 
				
			||||||
 | 
						netifd interfaces to enable QoS on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "devices": TABLE of TABLE
 | 
				
			||||||
 | 
						netdevs to enable QoS on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface/device properties:
 | 
				
			||||||
 | 
					- "bandwidth_up": STRING
 | 
				
			||||||
 | 
						Uplink bandwidth (same format as tc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "bandwidth_down": STRING
 | 
				
			||||||
 | 
						Downlink bandwidth (same format as tc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "ingress": BOOL
 | 
				
			||||||
 | 
						Enable ingress shaping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "egress": BOOL
 | 
				
			||||||
 | 
						Enable egress shaping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "mode": STRING
 | 
				
			||||||
 | 
						CAKE diffserv mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "nat": BOOL
 | 
				
			||||||
 | 
						Enable CAKE NAT host detection via conntrack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "host_isolate": BOOL
 | 
				
			||||||
 | 
						Enable CAKE host isolation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "autorate_ingress": BOOL
 | 
				
			||||||
 | 
						Enable CAKE automatic rate estimation for ingress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "ingress_options": STRING
 | 
				
			||||||
 | 
						CAKE ingress options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "egress_options": STRING
 | 
				
			||||||
 | 
						CAKE egress options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "options": STRING
 | 
				
			||||||
 | 
						CAKE options for ingress + egress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Mapping file syntax:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each line has two whitespace separated fields, match and dscp
 | 
				
			||||||
 | 
					match is one of:
 | 
				
			||||||
 | 
					- tcp:<port>[-<endport>]
 | 
				
			||||||
 | 
						TCP single port, or range from <port> to <endport>
 | 
				
			||||||
 | 
					- udp:<port>[-<endport>]
 | 
				
			||||||
 | 
						UDP single port, or range from <port> to <endport>
 | 
				
			||||||
 | 
					- <ipaddr>
 | 
				
			||||||
 | 
						IPv4 address, e.g. 1.1.1.1
 | 
				
			||||||
 | 
					- <ipv6addr>
 | 
				
			||||||
 | 
						IPv6 address, e.g. ff01::1
 | 
				
			||||||
 | 
					- dns:<regex>
 | 
				
			||||||
 | 
						POSIX.2 extended regular expression for matching hostnames
 | 
				
			||||||
 | 
						Only works, if dns lookups are passed to qosify via the add_dns_host ubus call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dscp can be a raw value, or a codepoint like CS0
 | 
				
			||||||
 | 
					Adding a + in front of the value tells qosify to only override the DSCP value if it is zero
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Planned features:
 | 
				
			||||||
 | 
					- Integration with dnsmasq to support hostname pattern based DSCP marking
 | 
				
			||||||
 | 
					- Support for LAN host based priority
 | 
				
			||||||
@@ -1,3 +1,7 @@
 | 
				
			|||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
@@ -130,8 +134,9 @@ static const char *check_str(struct blob_attr *attr)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
iface_config_set(struct qosify_iface_config *cfg, struct blob_attr *attr)
 | 
					iface_config_set(struct qosify_iface *iface, struct blob_attr *attr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct qosify_iface_config *cfg = &iface->config;
 | 
				
			||||||
	struct blob_attr *tb[__IFACE_ATTR_MAX];
 | 
						struct blob_attr *tb[__IFACE_ATTR_MAX];
 | 
				
			||||||
	struct blob_attr *cur;
 | 
						struct blob_attr *cur;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -145,6 +150,7 @@ iface_config_set(struct qosify_iface_config *cfg, struct blob_attr *attr)
 | 
				
			|||||||
	cfg->egress = true;
 | 
						cfg->egress = true;
 | 
				
			||||||
	cfg->host_isolate = true;
 | 
						cfg->host_isolate = true;
 | 
				
			||||||
	cfg->autorate_ingress = true;
 | 
						cfg->autorate_ingress = true;
 | 
				
			||||||
 | 
						cfg->nat = !iface->device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((cur = tb[IFACE_ATTR_BW_UP]) != NULL)
 | 
						if ((cur = tb[IFACE_ATTR_BW_UP]) != NULL)
 | 
				
			||||||
		cfg->bandwidth_up = check_str(cur);
 | 
							cfg->bandwidth_up = check_str(cur);
 | 
				
			||||||
@@ -386,7 +392,7 @@ static void
 | 
				
			|||||||
interface_set_config(struct qosify_iface *iface, struct blob_attr *config)
 | 
					interface_set_config(struct qosify_iface *iface, struct blob_attr *config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	iface->config_data = blob_memdup(config);
 | 
						iface->config_data = blob_memdup(config);
 | 
				
			||||||
	iface_config_set(&iface->config, iface->config_data);
 | 
						iface_config_set(iface, iface->config_data);
 | 
				
			||||||
	interface_start(iface);
 | 
						interface_start(iface);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,7 @@
 | 
				
			|||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#include <sys/resource.h>
 | 
					#include <sys/resource.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
@@ -35,24 +39,17 @@ static void qosify_fill_rodata(struct bpf_object *obj, uint32_t flags)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
qosify_create_program(const char *suffix, uint32_t flags, bool *force_init)
 | 
					qosify_create_program(const char *suffix, uint32_t flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
 | 
						DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
 | 
				
			||||||
		.pin_root_path = CLASSIFY_DATA_PATH,
 | 
							.pin_root_path = CLASSIFY_DATA_PATH,
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
	struct bpf_program *prog;
 | 
						struct bpf_program *prog;
 | 
				
			||||||
	struct bpf_object *obj;
 | 
						struct bpf_object *obj;
 | 
				
			||||||
	struct stat st;
 | 
					 | 
				
			||||||
	char path[256];
 | 
						char path[256];
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(path, sizeof(path), CLASSIFY_PIN_PATH "_" "%s", suffix);
 | 
						snprintf(path, sizeof(path), CLASSIFY_PIN_PATH "_" "%s", suffix);
 | 
				
			||||||
	if (!*force_init) {
 | 
					 | 
				
			||||||
		if (stat(path, &st) == 0)
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		*force_init = true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	obj = bpf_object__open_file(CLASSIFY_PROG_PATH, &opts);
 | 
						obj = bpf_object__open_file(CLASSIFY_PROG_PATH, &opts);
 | 
				
			||||||
	err = libbpf_get_error(obj);
 | 
						err = libbpf_get_error(obj);
 | 
				
			||||||
@@ -91,7 +88,7 @@ qosify_create_program(const char *suffix, uint32_t flags, bool *force_init)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qosify_loader_init(bool force_init)
 | 
					int qosify_loader_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static const struct {
 | 
						static const struct {
 | 
				
			||||||
		const char *suffix;
 | 
							const char *suffix;
 | 
				
			||||||
@@ -105,8 +102,7 @@ int qosify_loader_init(bool force_init)
 | 
				
			|||||||
	glob_t g;
 | 
						glob_t g;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (force_init &&
 | 
						if (glob(CLASSIFY_DATA_PATH "/*", 0, NULL, &g) == 0) {
 | 
				
			||||||
	    glob(CLASSIFY_DATA_PATH "/*", 0, NULL, &g) == 0) {
 | 
					 | 
				
			||||||
		for (i = 0; i < g.gl_pathc; i++)
 | 
							for (i = 0; i < g.gl_pathc; i++)
 | 
				
			||||||
			unlink(g.gl_pathv[i]);
 | 
								unlink(g.gl_pathv[i]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -117,8 +113,7 @@ int qosify_loader_init(bool force_init)
 | 
				
			|||||||
	qosify_init_env();
 | 
						qosify_init_env();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(progs); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(progs); i++) {
 | 
				
			||||||
		if (qosify_create_program(progs[i].suffix, progs[i].flags,
 | 
							if (qosify_create_program(progs[i].suffix, progs[i].flags))
 | 
				
			||||||
				      &force_init))
 | 
					 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,7 @@
 | 
				
			|||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
@@ -10,7 +14,6 @@ static int usage(const char *progname)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	fprintf(stderr, "Usage: %s [options]\n"
 | 
						fprintf(stderr, "Usage: %s [options]\n"
 | 
				
			||||||
		"Options:\n"
 | 
							"Options:\n"
 | 
				
			||||||
		"	-f:		force reload of BPF programs\n"
 | 
					 | 
				
			||||||
		"	-l <file>	Load defaults from <file>\n"
 | 
							"	-l <file>	Load defaults from <file>\n"
 | 
				
			||||||
		"	-o		only load program/maps without running as daemon\n"
 | 
							"	-o		only load program/maps without running as daemon\n"
 | 
				
			||||||
		"\n", progname);
 | 
							"\n", progname);
 | 
				
			||||||
@@ -21,14 +24,12 @@ static int usage(const char *progname)
 | 
				
			|||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *load_file = NULL;
 | 
						const char *load_file = NULL;
 | 
				
			||||||
	bool force_init = false;
 | 
					 | 
				
			||||||
	bool oneshot = false;
 | 
						bool oneshot = false;
 | 
				
			||||||
	int ch;
 | 
						int ch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((ch = getopt(argc, argv, "fl:o")) != -1) {
 | 
						while ((ch = getopt(argc, argv, "fl:o")) != -1) {
 | 
				
			||||||
		switch (ch) {
 | 
							switch (ch) {
 | 
				
			||||||
		case 'f':
 | 
							case 'f':
 | 
				
			||||||
			force_init = true;
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'l':
 | 
							case 'l':
 | 
				
			||||||
			load_file = optarg;
 | 
								load_file = optarg;
 | 
				
			||||||
@@ -41,7 +42,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (qosify_loader_init(force_init))
 | 
						if (qosify_loader_init())
 | 
				
			||||||
		return 2;
 | 
							return 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (qosify_map_init())
 | 
						if (qosify_map_init())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,7 @@
 | 
				
			|||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
@@ -17,7 +21,8 @@ static AVL_TREE(map_data, qosify_map_entry_cmp, false, NULL);
 | 
				
			|||||||
static LIST_HEAD(map_files);
 | 
					static LIST_HEAD(map_files);
 | 
				
			||||||
static uint32_t next_timeout;
 | 
					static uint32_t next_timeout;
 | 
				
			||||||
static uint8_t qosify_dscp_default[2] = { 0xff, 0xff };
 | 
					static uint8_t qosify_dscp_default[2] = { 0xff, 0xff };
 | 
				
			||||||
int qosify_map_timeout = 3600;
 | 
					int qosify_map_timeout;
 | 
				
			||||||
 | 
					int qosify_active_timeout;
 | 
				
			||||||
struct qosify_config config;
 | 
					struct qosify_config config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct qosify_map_file {
 | 
					struct qosify_map_file {
 | 
				
			||||||
@@ -34,6 +39,7 @@ static const struct {
 | 
				
			|||||||
	[CL_MAP_IPV4_ADDR] = { "ipv4_map", "ipv4_addr" },
 | 
						[CL_MAP_IPV4_ADDR] = { "ipv4_map", "ipv4_addr" },
 | 
				
			||||||
	[CL_MAP_IPV6_ADDR] = { "ipv6_map", "ipv6_addr" },
 | 
						[CL_MAP_IPV6_ADDR] = { "ipv6_map", "ipv6_addr" },
 | 
				
			||||||
	[CL_MAP_CONFIG] = { "config", "config" },
 | 
						[CL_MAP_CONFIG] = { "config", "config" },
 | 
				
			||||||
 | 
						[CL_MAP_DNS] = { "dns", "dns" },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct {
 | 
					static const struct {
 | 
				
			||||||
@@ -62,6 +68,8 @@ static const struct {
 | 
				
			|||||||
	{ "AF43", 38 },
 | 
						{ "AF43", 38 },
 | 
				
			||||||
	{ "EF", 46 },
 | 
						{ "EF", 46 },
 | 
				
			||||||
	{ "VA", 44 },
 | 
						{ "VA", 44 },
 | 
				
			||||||
 | 
						{ "LE", 1 },
 | 
				
			||||||
 | 
						{ "DF", 0 },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void qosify_map_timer_cb(struct uloop_timeout *t)
 | 
					static void qosify_map_timer_cb(struct uloop_timeout *t)
 | 
				
			||||||
@@ -165,7 +173,7 @@ int qosify_map_init(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(qosify_map_fds); i++) {
 | 
						for (i = 0; i < CL_MAP_DNS; i++) {
 | 
				
			||||||
		qosify_map_fds[i] = qosify_map_get_fd(i);
 | 
							qosify_map_fds[i] = qosify_map_get_fd(i);
 | 
				
			||||||
		if (qosify_map_fds[i] < 0)
 | 
							if (qosify_map_fds[i] < 0)
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
@@ -206,9 +214,37 @@ static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr)
 | 
				
			|||||||
	if (d1->id != d2->id)
 | 
						if (d1->id != d2->id)
 | 
				
			||||||
		return d2->id - d1->id;
 | 
							return d2->id - d1->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (d1->id == CL_MAP_DNS)
 | 
				
			||||||
 | 
							return strcmp(d1->addr.dns.pattern, d2->addr.dns.pattern);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return memcmp(&d1->addr, &d2->addr, sizeof(d1->addr));
 | 
						return memcmp(&d1->addr, &d2->addr, sizeof(d1->addr));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct qosify_map_entry *
 | 
				
			||||||
 | 
					__qosify_map_alloc_entry(struct qosify_map_data *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct qosify_map_entry *e;
 | 
				
			||||||
 | 
						char *pattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data->id < CL_MAP_DNS) {
 | 
				
			||||||
 | 
							e = calloc(1, sizeof(*e));
 | 
				
			||||||
 | 
							memcpy(&e->data.addr, &data->addr, sizeof(e->data.addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return e;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						e = calloc_a(sizeof(*e), &pattern, strlen(data->addr.dns.pattern) + 1);
 | 
				
			||||||
 | 
						strcpy(pattern, data->addr.dns.pattern);
 | 
				
			||||||
 | 
						e->data.addr.dns.pattern = pattern;
 | 
				
			||||||
 | 
						if (regcomp(&e->data.addr.dns.regex, pattern,
 | 
				
			||||||
 | 
							    REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
 | 
				
			||||||
 | 
							free(e);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return e;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __qosify_map_set_entry(struct qosify_map_data *data)
 | 
					static void __qosify_map_set_entry(struct qosify_map_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int fd = qosify_map_fds[data->id];
 | 
						int fd = qosify_map_fds[data->id];
 | 
				
			||||||
@@ -223,10 +259,12 @@ static void __qosify_map_set_entry(struct qosify_map_data *data)
 | 
				
			|||||||
		if (!add)
 | 
							if (!add)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		e = calloc(1, sizeof(*e));
 | 
							e = __qosify_map_alloc_entry(data);
 | 
				
			||||||
 | 
							if (!e)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		e->avl.key = &e->data;
 | 
							e->avl.key = &e->data;
 | 
				
			||||||
		e->data.id = data->id;
 | 
							e->data.id = data->id;
 | 
				
			||||||
		memcpy(&e->data.addr, &data->addr, sizeof(e->data.addr));
 | 
					 | 
				
			||||||
		avl_insert(&map_data, &e->avl);
 | 
							avl_insert(&map_data, &e->avl);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		prev_dscp = e->data.dscp;
 | 
							prev_dscp = e->data.dscp;
 | 
				
			||||||
@@ -246,8 +284,14 @@ static void __qosify_map_set_entry(struct qosify_map_data *data)
 | 
				
			|||||||
		e->data.dscp = e->data.file_dscp;
 | 
							e->data.dscp = e->data.file_dscp;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (e->data.dscp != prev_dscp)
 | 
						if (e->data.dscp != prev_dscp && data->id < CL_MAP_DNS) {
 | 
				
			||||||
		bpf_map_update_elem(fd, &data->addr, &e->data.dscp, BPF_ANY);
 | 
							struct qosify_ip_map_val val = {
 | 
				
			||||||
 | 
								.dscp = e->data.dscp,
 | 
				
			||||||
 | 
								.seen = 1,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bpf_map_update_elem(fd, &data->addr, &val, BPF_ANY);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (add) {
 | 
						if (add) {
 | 
				
			||||||
		if (qosify_map_timeout == ~0 || file) {
 | 
							if (qosify_map_timeout == ~0 || file) {
 | 
				
			||||||
@@ -316,6 +360,9 @@ int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str, uint
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (id) {
 | 
						switch (id) {
 | 
				
			||||||
 | 
						case CL_MAP_DNS:
 | 
				
			||||||
 | 
							data.addr.dns.pattern = str;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	case CL_MAP_TCP_PORTS:
 | 
						case CL_MAP_TCP_PORTS:
 | 
				
			||||||
	case CL_MAP_UDP_PORTS:
 | 
						case CL_MAP_UDP_PORTS:
 | 
				
			||||||
		return qosify_map_set_port(&data, str);
 | 
							return qosify_map_set_port(&data, str);
 | 
				
			||||||
@@ -397,6 +444,8 @@ qosify_map_parse_line(char *str)
 | 
				
			|||||||
	if (dscp < 0)
 | 
						if (dscp < 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!strncmp(key, "dns:", 4))
 | 
				
			||||||
 | 
							qosify_map_set_entry(CL_MAP_DNS, true, key + 4, dscp);
 | 
				
			||||||
	if (!strncmp(key, "tcp:", 4))
 | 
						if (!strncmp(key, "tcp:", 4))
 | 
				
			||||||
		qosify_map_set_entry(CL_MAP_TCP_PORTS, true, key + 4, dscp);
 | 
							qosify_map_set_entry(CL_MAP_TCP_PORTS, true, key + 4, dscp);
 | 
				
			||||||
	else if (!strncmp(key, "udp:", 4))
 | 
						else if (!strncmp(key, "udp:", 4))
 | 
				
			||||||
@@ -483,6 +532,7 @@ void qosify_map_reset_config(void)
 | 
				
			|||||||
	qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, 0);
 | 
						qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, 0);
 | 
				
			||||||
	qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, 0);
 | 
						qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, 0);
 | 
				
			||||||
	qosify_map_timeout = 3600;
 | 
						qosify_map_timeout = 3600;
 | 
				
			||||||
 | 
						qosify_active_timeout = 300;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&config, 0, sizeof(config));
 | 
						memset(&config, 0, sizeof(config));
 | 
				
			||||||
	config.dscp_prio = 0xff;
 | 
						config.dscp_prio = 0xff;
 | 
				
			||||||
@@ -502,12 +552,44 @@ void qosify_map_reload(void)
 | 
				
			|||||||
	qosify_map_gc();
 | 
						qosify_map_gc();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void qosify_map_free_entry(struct qosify_map_entry *e)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fd = qosify_map_fds[e->data.id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						avl_delete(&map_data, &e->avl);
 | 
				
			||||||
 | 
						if (e->data.id < CL_MAP_DNS)
 | 
				
			||||||
 | 
							bpf_map_delete_elem(fd, &e->data.addr);
 | 
				
			||||||
 | 
						free(e);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					qosify_map_entry_refresh_timeout(struct qosify_map_entry *e)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct qosify_ip_map_val val;
 | 
				
			||||||
 | 
						int fd = qosify_map_fds[e->data.id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (e->data.id != CL_MAP_IPV4_ADDR &&
 | 
				
			||||||
 | 
						    e->data.id != CL_MAP_IPV6_ADDR)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bpf_map_lookup_elem(fd, &e->data.addr, &val))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!val.seen)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						e->timeout = qosify_gettime() + qosify_active_timeout;
 | 
				
			||||||
 | 
						val.seen = 0;
 | 
				
			||||||
 | 
						bpf_map_update_elem(fd, &e->data.addr, &val, BPF_ANY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qosify_map_gc(void)
 | 
					void qosify_map_gc(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct qosify_map_entry *e, *tmp;
 | 
						struct qosify_map_entry *e, *tmp;
 | 
				
			||||||
	int32_t timeout = 0;
 | 
						int32_t timeout = 0;
 | 
				
			||||||
	uint32_t cur_time = qosify_gettime();
 | 
						uint32_t cur_time = qosify_gettime();
 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	next_timeout = 0;
 | 
						next_timeout = 0;
 | 
				
			||||||
	avl_for_each_element_safe(&map_data, e, avl, tmp) {
 | 
						avl_for_each_element_safe(&map_data, e, avl, tmp) {
 | 
				
			||||||
@@ -515,6 +597,9 @@ void qosify_map_gc(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (e->data.user && e->timeout != ~0) {
 | 
							if (e->data.user && e->timeout != ~0) {
 | 
				
			||||||
			cur_timeout = e->timeout - cur_time;
 | 
								cur_timeout = e->timeout - cur_time;
 | 
				
			||||||
 | 
								if (cur_timeout <= 0 &&
 | 
				
			||||||
 | 
								    qosify_map_entry_refresh_timeout(e))
 | 
				
			||||||
 | 
									cur_timeout = e->timeout - cur_time;
 | 
				
			||||||
			if (cur_timeout <= 0) {
 | 
								if (cur_timeout <= 0) {
 | 
				
			||||||
				e->data.user = false;
 | 
									e->data.user = false;
 | 
				
			||||||
				e->data.dscp = e->data.file_dscp;
 | 
									e->data.dscp = e->data.file_dscp;
 | 
				
			||||||
@@ -527,10 +612,7 @@ void qosify_map_gc(void)
 | 
				
			|||||||
		if (e->data.file || e->data.user)
 | 
							if (e->data.file || e->data.user)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		avl_delete(&map_data, &e->avl);
 | 
							qosify_map_free_entry(e);
 | 
				
			||||||
		fd = qosify_map_fds[e->data.id];
 | 
					 | 
				
			||||||
		bpf_map_delete_elem(fd, &e->data.addr);
 | 
					 | 
				
			||||||
		free(e);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!timeout)
 | 
						if (!timeout)
 | 
				
			||||||
@@ -539,6 +621,52 @@ void qosify_map_gc(void)
 | 
				
			|||||||
	uloop_timeout_set(&qosify_map_timer, timeout * 1000);
 | 
						uloop_timeout_set(&qosify_map_timer, timeout * 1000);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int qosify_map_add_dns_host(const char *host, const char *addr, const char *type, int ttl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct qosify_map_data data = {
 | 
				
			||||||
 | 
							.id = CL_MAP_DNS,
 | 
				
			||||||
 | 
							.addr.dns.pattern = "",
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						struct qosify_map_entry *e;
 | 
				
			||||||
 | 
						int prev_timeout = qosify_map_timeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						e = avl_find_ge_element(&map_data, &data, e, avl);
 | 
				
			||||||
 | 
						if (!e)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&data, 0, sizeof(data));
 | 
				
			||||||
 | 
						data.user = true;
 | 
				
			||||||
 | 
						if (!strcmp(type, "A"))
 | 
				
			||||||
 | 
							data.id = CL_MAP_IPV4_ADDR;
 | 
				
			||||||
 | 
						else if (!strcmp(type, "AAAA"))
 | 
				
			||||||
 | 
							data.id = CL_MAP_IPV6_ADDR;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (qosify_map_fill_ip(&data, addr))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						avl_for_element_to_last(&map_data, e, e, avl) {
 | 
				
			||||||
 | 
							regex_t *regex = &e->data.addr.dns.regex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (e->data.id != CL_MAP_DNS)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (regexec(regex, host, 0, NULL, 0) != 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ttl)
 | 
				
			||||||
 | 
								qosify_map_timeout = ttl;
 | 
				
			||||||
 | 
							data.dscp = e->data.dscp;
 | 
				
			||||||
 | 
							__qosify_map_set_entry(&data);
 | 
				
			||||||
 | 
							qosify_map_timeout = prev_timeout;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qosify_map_dump(struct blob_buf *b)
 | 
					void qosify_map_dump(struct blob_buf *b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct qosify_map_entry *e;
 | 
						struct qosify_map_entry *e;
 | 
				
			||||||
@@ -574,22 +702,25 @@ void qosify_map_dump(struct blob_buf *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);
 | 
					 | 
				
			||||||
		switch (e->data.id) {
 | 
							switch (e->data.id) {
 | 
				
			||||||
		case CL_MAP_TCP_PORTS:
 | 
							case CL_MAP_TCP_PORTS:
 | 
				
			||||||
		case CL_MAP_UDP_PORTS:
 | 
							case CL_MAP_UDP_PORTS:
 | 
				
			||||||
			snprintf(buf, buf_len, "%d", ntohs(e->data.addr.port));
 | 
								blobmsg_printf(b, "addr", "%d", ntohs(e->data.addr.port));
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case CL_MAP_IPV4_ADDR:
 | 
							case CL_MAP_IPV4_ADDR:
 | 
				
			||||||
		case CL_MAP_IPV6_ADDR:
 | 
							case CL_MAP_IPV6_ADDR:
 | 
				
			||||||
 | 
								buf = blobmsg_alloc_string_buffer(b, "addr", buf_len);
 | 
				
			||||||
			af = e->data.id == CL_MAP_IPV6_ADDR ? AF_INET6 : AF_INET;
 | 
								af = e->data.id == CL_MAP_IPV6_ADDR ? AF_INET6 : AF_INET;
 | 
				
			||||||
			inet_ntop(af, &e->data.addr, buf, buf_len);
 | 
								inet_ntop(af, &e->data.addr, buf, buf_len);
 | 
				
			||||||
 | 
								blobmsg_add_string_buffer(b);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case CL_MAP_DNS:
 | 
				
			||||||
 | 
								blobmsg_add_string(b, "addr", e->data.addr.dns.pattern);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			*buf = 0;
 | 
								*buf = 0;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		blobmsg_add_string_buffer(b);
 | 
					 | 
				
			||||||
		blobmsg_close_table(b, c);
 | 
							blobmsg_close_table(b, c);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	blobmsg_close_array(b, a);
 | 
						blobmsg_close_array(b, a);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,7 @@
 | 
				
			|||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#define KBUILD_MODNAME "foo"
 | 
					#define KBUILD_MODNAME "foo"
 | 
				
			||||||
#include <uapi/linux/bpf.h>
 | 
					#include <uapi/linux/bpf.h>
 | 
				
			||||||
#include <uapi/linux/if_ether.h>
 | 
					#include <uapi/linux/if_ether.h>
 | 
				
			||||||
@@ -64,7 +68,7 @@ struct {
 | 
				
			|||||||
	__uint(type, BPF_MAP_TYPE_HASH);
 | 
						__uint(type, BPF_MAP_TYPE_HASH);
 | 
				
			||||||
	__uint(pinning, 1);
 | 
						__uint(pinning, 1);
 | 
				
			||||||
	__uint(key_size, sizeof(struct in_addr));
 | 
						__uint(key_size, sizeof(struct in_addr));
 | 
				
			||||||
	__type(value, __u8);
 | 
						__type(value, struct qosify_ip_map_val);
 | 
				
			||||||
	__uint(max_entries, 100000);
 | 
						__uint(max_entries, 100000);
 | 
				
			||||||
	__uint(map_flags, BPF_F_NO_PREALLOC);
 | 
						__uint(map_flags, BPF_F_NO_PREALLOC);
 | 
				
			||||||
} ipv4_map SEC(".maps");
 | 
					} ipv4_map SEC(".maps");
 | 
				
			||||||
@@ -73,7 +77,7 @@ struct {
 | 
				
			|||||||
	__uint(type, BPF_MAP_TYPE_HASH);
 | 
						__uint(type, BPF_MAP_TYPE_HASH);
 | 
				
			||||||
	__uint(pinning, 1);
 | 
						__uint(pinning, 1);
 | 
				
			||||||
	__uint(key_size, sizeof(struct in6_addr));
 | 
						__uint(key_size, sizeof(struct in6_addr));
 | 
				
			||||||
	__type(value, __u8);
 | 
						__type(value, struct qosify_ip_map_val);
 | 
				
			||||||
	__uint(max_entries, 100000);
 | 
						__uint(max_entries, 100000);
 | 
				
			||||||
	__uint(map_flags, BPF_F_NO_PREALLOC);
 | 
						__uint(map_flags, BPF_F_NO_PREALLOC);
 | 
				
			||||||
} ipv6_map SEC(".maps");
 | 
					} ipv6_map SEC(".maps");
 | 
				
			||||||
@@ -332,6 +336,7 @@ static __always_inline void
 | 
				
			|||||||
parse_ipv4(struct __sk_buff *skb, __u32 *offset)
 | 
					parse_ipv4(struct __sk_buff *skb, __u32 *offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct qosify_config *config;
 | 
						struct qosify_config *config;
 | 
				
			||||||
 | 
						struct qosify_ip_map_val *ip_val;
 | 
				
			||||||
	const __u32 zero_port = 0;
 | 
						const __u32 zero_port = 0;
 | 
				
			||||||
	struct iphdr *iph;
 | 
						struct iphdr *iph;
 | 
				
			||||||
	__u8 dscp = 0xff;
 | 
						__u8 dscp = 0xff;
 | 
				
			||||||
@@ -365,12 +370,17 @@ parse_ipv4(struct __sk_buff *skb, __u32 *offset)
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		key = &iph->daddr;
 | 
							key = &iph->daddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	value = bpf_map_lookup_elem(&ipv4_map, key);
 | 
						ip_val = bpf_map_lookup_elem(&ipv4_map, key);
 | 
				
			||||||
	/* use udp port 0 entry as fallback for non-tcp/udp */
 | 
						if (ip_val) {
 | 
				
			||||||
	if (!value && dscp == 0xff)
 | 
							if (!ip_val->seen)
 | 
				
			||||||
 | 
								ip_val->seen = 1;
 | 
				
			||||||
 | 
							dscp = ip_val->dscp;
 | 
				
			||||||
 | 
						} else if (dscp == 0xff) {
 | 
				
			||||||
 | 
							/* use udp port 0 entry as fallback for non-tcp/udp */
 | 
				
			||||||
		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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -384,6 +394,7 @@ static __always_inline void
 | 
				
			|||||||
parse_ipv6(struct __sk_buff *skb, __u32 *offset)
 | 
					parse_ipv6(struct __sk_buff *skb, __u32 *offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct qosify_config *config;
 | 
						struct qosify_config *config;
 | 
				
			||||||
 | 
						struct qosify_ip_map_val *ip_val;
 | 
				
			||||||
	const __u32 zero_port = 0;
 | 
						const __u32 zero_port = 0;
 | 
				
			||||||
	struct ipv6hdr *iph;
 | 
						struct ipv6hdr *iph;
 | 
				
			||||||
	__u8 dscp = 0;
 | 
						__u8 dscp = 0;
 | 
				
			||||||
@@ -411,13 +422,17 @@ parse_ipv6(struct __sk_buff *skb, __u32 *offset)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	parse_l4proto(config, skb, *offset, ipproto, &dscp);
 | 
						parse_l4proto(config, skb, *offset, ipproto, &dscp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	value = bpf_map_lookup_elem(&ipv6_map, key);
 | 
						ip_val = bpf_map_lookup_elem(&ipv6_map, key);
 | 
				
			||||||
 | 
						if (ip_val) {
 | 
				
			||||||
	/* use udp port 0 entry as fallback for non-tcp/udp */
 | 
							if (!ip_val->seen)
 | 
				
			||||||
	if (!value)
 | 
								ip_val->seen = 1;
 | 
				
			||||||
 | 
							dscp = ip_val->dscp;
 | 
				
			||||||
 | 
						} else if (dscp == 0xff) {
 | 
				
			||||||
 | 
							/* use udp port 0 entry as fallback for non-tcp/udp */
 | 
				
			||||||
		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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,7 @@
 | 
				
			|||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#ifndef __BPF_QOSIFY_H
 | 
					#ifndef __BPF_QOSIFY_H
 | 
				
			||||||
#define __BPF_QOSIFY_H
 | 
					#define __BPF_QOSIFY_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -27,4 +31,9 @@ struct qosify_config {
 | 
				
			|||||||
	uint16_t prio_max_avg_pkt_len;
 | 
						uint16_t prio_max_avg_pkt_len;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct qosify_ip_map_val {
 | 
				
			||||||
 | 
						uint8_t dscp; /* must be first */
 | 
				
			||||||
 | 
						uint8_t seen;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,12 @@
 | 
				
			|||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#ifndef __QOS_CLASSIFY_H
 | 
					#ifndef __QOS_CLASSIFY_H
 | 
				
			||||||
#define __QOS_CLASSIFY_H
 | 
					#define __QOS_CLASSIFY_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <regex.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <bpf/bpf.h>
 | 
					#include <bpf/bpf.h>
 | 
				
			||||||
#include <bpf/libbpf.h>
 | 
					#include <bpf/libbpf.h>
 | 
				
			||||||
@@ -25,6 +30,7 @@ enum qosify_map_id {
 | 
				
			|||||||
	CL_MAP_IPV4_ADDR,
 | 
						CL_MAP_IPV4_ADDR,
 | 
				
			||||||
	CL_MAP_IPV6_ADDR,
 | 
						CL_MAP_IPV6_ADDR,
 | 
				
			||||||
	CL_MAP_CONFIG,
 | 
						CL_MAP_CONFIG,
 | 
				
			||||||
 | 
						CL_MAP_DNS,
 | 
				
			||||||
	__CL_MAP_MAX,
 | 
						__CL_MAP_MAX,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,6 +47,10 @@ struct qosify_map_data {
 | 
				
			|||||||
		uint32_t port;
 | 
							uint32_t port;
 | 
				
			||||||
		struct in_addr ip;
 | 
							struct in_addr ip;
 | 
				
			||||||
		struct in6_addr ip6;
 | 
							struct in6_addr ip6;
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								const char *pattern;
 | 
				
			||||||
 | 
								regex_t regex;
 | 
				
			||||||
 | 
							} dns;
 | 
				
			||||||
	} addr;
 | 
						} addr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,9 +64,10 @@ struct qosify_map_entry {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int qosify_map_timeout;
 | 
					extern int qosify_map_timeout;
 | 
				
			||||||
 | 
					extern int qosify_active_timeout;
 | 
				
			||||||
extern struct qosify_config config;
 | 
					extern struct qosify_config config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qosify_loader_init(bool force_init);
 | 
					int qosify_loader_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qosify_map_init(void);
 | 
					int qosify_map_init(void);
 | 
				
			||||||
int qosify_map_dscp_value(const char *val);
 | 
					int qosify_map_dscp_value(const char *val);
 | 
				
			||||||
@@ -69,6 +80,7 @@ void qosify_map_dump(struct blob_buf *b);
 | 
				
			|||||||
void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val);
 | 
					void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val);
 | 
				
			||||||
void qosify_map_reset_config(void);
 | 
					void qosify_map_reset_config(void);
 | 
				
			||||||
void qosify_map_update_config(void);
 | 
					void qosify_map_update_config(void);
 | 
				
			||||||
 | 
					int qosify_map_add_dns_host(const char *host, const char *addr, const char *type, int ttl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qosify_iface_init(void);
 | 
					int qosify_iface_init(void);
 | 
				
			||||||
void qosify_iface_config_update(struct blob_attr *ifaces, struct blob_attr *devs);
 | 
					void qosify_iface_config_update(struct blob_attr *ifaces, struct blob_attr *devs);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,7 @@
 | 
				
			|||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#include <libubus.h>
 | 
					#include <libubus.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "qosify.h"
 | 
					#include "qosify.h"
 | 
				
			||||||
@@ -46,6 +50,7 @@ enum {
 | 
				
			|||||||
	CL_ADD_IPV6,
 | 
						CL_ADD_IPV6,
 | 
				
			||||||
	CL_ADD_TCP_PORT,
 | 
						CL_ADD_TCP_PORT,
 | 
				
			||||||
	CL_ADD_UDP_PORT,
 | 
						CL_ADD_UDP_PORT,
 | 
				
			||||||
 | 
						CL_ADD_DNS,
 | 
				
			||||||
	__CL_ADD_MAX
 | 
						__CL_ADD_MAX
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -56,6 +61,7 @@ static const struct blobmsg_policy qosify_add_policy[__CL_ADD_MAX] = {
 | 
				
			|||||||
	[CL_ADD_IPV6] = { "ipv6", BLOBMSG_TYPE_ARRAY },
 | 
						[CL_ADD_IPV6] = { "ipv6", BLOBMSG_TYPE_ARRAY },
 | 
				
			||||||
	[CL_ADD_TCP_PORT] = { "tcp_port", BLOBMSG_TYPE_ARRAY },
 | 
						[CL_ADD_TCP_PORT] = { "tcp_port", BLOBMSG_TYPE_ARRAY },
 | 
				
			||||||
	[CL_ADD_UDP_PORT] = { "udp_port", BLOBMSG_TYPE_ARRAY },
 | 
						[CL_ADD_UDP_PORT] = { "udp_port", BLOBMSG_TYPE_ARRAY },
 | 
				
			||||||
 | 
						[CL_ADD_DNS] = { "dns", BLOBMSG_TYPE_ARRAY },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,6 +119,10 @@ qosify_ubus_add(struct ubus_context *ctx, struct ubus_object *obj,
 | 
				
			|||||||
	    (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_UDP_PORTS) != 0))
 | 
						    (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_UDP_PORTS) != 0))
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((cur = tb[CL_ADD_DNS]) != NULL &&
 | 
				
			||||||
 | 
						    (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_DNS) != 0))
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	qosify_map_timeout = prev_timemout;
 | 
						qosify_map_timeout = prev_timemout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -254,12 +264,6 @@ qosify_ubus_status(struct ubus_context *ctx, struct ubus_object *obj,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
	CL_DEV_EVENT_NAME,
 | 
					 | 
				
			||||||
	CL_DEV_EVENT_ADD,
 | 
					 | 
				
			||||||
	__CL_DEV_EVENT_MAX,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj,
 | 
					qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj,
 | 
				
			||||||
			  struct ubus_request_data *req, const char *method,
 | 
								  struct ubus_request_data *req, const char *method,
 | 
				
			||||||
@@ -270,6 +274,48 @@ qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						CL_DNS_HOST_NAME,
 | 
				
			||||||
 | 
						CL_DNS_HOST_TYPE,
 | 
				
			||||||
 | 
						CL_DNS_HOST_ADDR,
 | 
				
			||||||
 | 
						CL_DNS_HOST_TTL,
 | 
				
			||||||
 | 
						__CL_DNS_HOST_MAX
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct blobmsg_policy qosify_dns_policy[__CL_DNS_HOST_MAX] = {
 | 
				
			||||||
 | 
						[CL_DNS_HOST_NAME] = { "name", BLOBMSG_TYPE_STRING },
 | 
				
			||||||
 | 
						[CL_DNS_HOST_TYPE] = { "type", BLOBMSG_TYPE_STRING },
 | 
				
			||||||
 | 
						[CL_DNS_HOST_ADDR] = { "address", BLOBMSG_TYPE_STRING },
 | 
				
			||||||
 | 
						[CL_DNS_HOST_TTL] = { "ttl", BLOBMSG_TYPE_INT32 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qosify_ubus_add_dns_host(struct ubus_context *ctx, struct ubus_object *obj,
 | 
				
			||||||
 | 
								 struct ubus_request_data *req, const char *method,
 | 
				
			||||||
 | 
								 struct blob_attr *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct blob_attr *tb[__CL_DNS_HOST_MAX];
 | 
				
			||||||
 | 
						struct blob_attr *cur;
 | 
				
			||||||
 | 
						uint32_t ttl = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						blobmsg_parse(qosify_dns_policy, __CL_DNS_HOST_MAX, tb,
 | 
				
			||||||
 | 
							      blobmsg_data(msg), blobmsg_len(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!tb[CL_DNS_HOST_NAME] || !tb[CL_DNS_HOST_TYPE] ||
 | 
				
			||||||
 | 
						    !tb[CL_DNS_HOST_ADDR])
 | 
				
			||||||
 | 
							return UBUS_STATUS_INVALID_ARGUMENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((cur = tb[CL_DNS_HOST_TTL]) != NULL)
 | 
				
			||||||
 | 
							ttl = blobmsg_get_u32(cur);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (qosify_map_add_dns_host(blobmsg_get_string(tb[CL_DNS_HOST_NAME]),
 | 
				
			||||||
 | 
									    blobmsg_get_string(tb[CL_DNS_HOST_ADDR]),
 | 
				
			||||||
 | 
									    blobmsg_get_string(tb[CL_DNS_HOST_TYPE]),
 | 
				
			||||||
 | 
									    ttl))
 | 
				
			||||||
 | 
							return UBUS_STATUS_INVALID_ARGUMENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct ubus_method qosify_methods[] = {
 | 
					static const struct ubus_method qosify_methods[] = {
 | 
				
			||||||
	UBUS_METHOD_NOARG("reload", qosify_ubus_reload),
 | 
						UBUS_METHOD_NOARG("reload", qosify_ubus_reload),
 | 
				
			||||||
@@ -279,6 +325,7 @@ static const struct ubus_method qosify_methods[] = {
 | 
				
			|||||||
	UBUS_METHOD("config", qosify_ubus_config, qosify_config_policy),
 | 
						UBUS_METHOD("config", qosify_ubus_config, qosify_config_policy),
 | 
				
			||||||
	UBUS_METHOD_NOARG("dump", qosify_ubus_dump),
 | 
						UBUS_METHOD_NOARG("dump", qosify_ubus_dump),
 | 
				
			||||||
	UBUS_METHOD_NOARG("status", qosify_ubus_status),
 | 
						UBUS_METHOD_NOARG("status", qosify_ubus_status),
 | 
				
			||||||
 | 
						UBUS_METHOD("add_dns_host", qosify_ubus_add_dns_host, qosify_dns_policy),
 | 
				
			||||||
	UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices),
 | 
						UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user