map: add support for defining aliases
authorFelix Fietkau <nbd@nbd.name>
Fri, 12 Nov 2021 21:54:51 +0000 (22:54 +0100)
committerFelix Fietkau <nbd@nbd.name>
Fri, 12 Nov 2021 21:54:53 +0000 (22:54 +0100)
Aliases can be used to make a distinction between ingress and egress tags,
and they make it easier to reconfigure tags without having to update the rule
config files

Signed-off-by: Felix Fietkau <nbd@nbd.name>
map.c
qosify.h
ubus.c

diff --git a/map.c b/map.c
index 92b8a07afe2d2cef16484fb72303eefe5d3800de..303cf39a426366e1dcabb0da3e867fbc8eacb625 100644 (file)
--- a/map.c
+++ b/map.c
@@ -13,6 +13,7 @@
 #include <glob.h>
 
 #include <libubox/uloop.h>
+#include <libubox/avl-cmp.h>
 
 #include "qosify.h"
 
@@ -21,6 +22,7 @@ static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr);
 static int qosify_map_fds[__CL_MAP_MAX];
 static AVL_TREE(map_data, qosify_map_entry_cmp, false, NULL);
 static LIST_HEAD(map_files);
+static AVL_TREE(map_aliases, avl_strcmp, false, NULL);
 static uint32_t next_timeout;
 static struct qosify_dscp_val qosify_dscp_default[2] = {
        { 0xff, 0xff },
@@ -35,6 +37,11 @@ struct qosify_map_file {
        char filename[];
 };
 
+struct qosify_map_alias {
+       struct avl_node avl;
+       struct qosify_dscp_val value;
+};
+
 static const struct {
        const char *name;
        const char *type_name;
@@ -394,11 +401,12 @@ int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str,
        return 0;
 }
 
-int qosify_map_dscp_value(const char *val, struct qosify_dscp_val *dscp_val)
+static int
+__qosify_map_dscp_value(const char *val, uint8_t *dscp_val)
 {
        unsigned long dscp;
-       char *err;
        bool fallback = false;
+       char *err;
 
        if (*val == '+') {
                fallback = true;
@@ -412,7 +420,35 @@ int qosify_map_dscp_value(const char *val, struct qosify_dscp_val *dscp_val)
        if (dscp >= 64)
                return -1;
 
-       dscp_val->ingress = dscp_val->egress = dscp + (fallback << 6);
+       *dscp_val = dscp | (fallback << 6);
+
+       return 0;
+}
+
+int qosify_map_dscp_value(const char *val, struct qosify_dscp_val *dscp_val)
+{
+       struct qosify_map_alias *alias;
+       bool fallback = false;
+
+       if (*val == '+') {
+               fallback = true;
+               val++;
+       }
+
+       alias = avl_find_element(&map_aliases, val, alias, avl);
+       if (alias) {
+               *dscp_val = alias->value;
+       } else {
+               if (__qosify_map_dscp_value(val, &dscp_val->egress))
+                       return -1;
+
+               dscp_val->ingress = dscp_val->egress;
+       }
+
+       if (fallback) {
+               dscp_val->ingress |= (1 << 6);
+               dscp_val->egress |= (1 << 6);
+       }
 
        return 0;
 }
@@ -778,6 +814,60 @@ void qosify_map_dump(struct blob_buf *b)
        blobmsg_close_array(b, a);
 }
 
+static int
+qosify_map_create_alias(struct blob_attr *attr)
+{
+       struct qosify_map_alias *alias;
+       enum {
+               MAP_ALIAS_INGRESS,
+               MAP_ALIAS_EGRESS,
+               __MAP_ALIAS_MAX
+       };
+       static const struct blobmsg_policy policy[__MAP_ALIAS_MAX] = {
+               [MAP_ALIAS_INGRESS] = { .type = BLOBMSG_TYPE_STRING },
+               [MAP_ALIAS_EGRESS] = { .type = BLOBMSG_TYPE_STRING },
+       };
+       struct blob_attr *tb[__MAP_ALIAS_MAX];
+       const char *name;
+       char *name_buf;
+
+       if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) != 2)
+               return -1;
+
+       blobmsg_parse_array(policy, __MAP_ALIAS_MAX, tb,
+                           blobmsg_data(attr), blobmsg_len(attr));
+
+       if (!tb[MAP_ALIAS_INGRESS] || !tb[MAP_ALIAS_EGRESS])
+               return -1;
+
+       name = blobmsg_name(attr);
+       alias = calloc_a(sizeof(*alias), &name_buf, strlen(name) + 1);
+       alias->avl.key = strcpy(name_buf, name);
+       if (__qosify_map_dscp_value(blobmsg_get_string(tb[MAP_ALIAS_INGRESS]),
+                                   &alias->value.ingress) ||
+           __qosify_map_dscp_value(blobmsg_get_string(tb[MAP_ALIAS_EGRESS]),
+                                   &alias->value.egress) ||
+           avl_insert(&map_aliases, &alias->avl)) {
+               free(alias);
+               return -1;
+       }
+
+       return 0;
+}
+
+void qosify_map_set_aliases(struct blob_attr *val)
+{
+       struct qosify_map_alias *alias, *tmp;
+       struct blob_attr *cur;
+       int rem;
+
+       avl_remove_all_elements(&map_aliases, alias, avl, tmp)
+               free(alias);
+
+       blobmsg_for_each_attr(cur, val, rem)
+               qosify_map_create_alias(cur);
+}
+
 void qosify_map_update_config(void)
 {
        int fd = qosify_map_fds[CL_MAP_CONFIG];
index 872b04801a2fbee856e725a5fe1e0ea582b67b5c..e5ca58acc7350d3bc20a4d3c8f5bcbc87a78516f 100644 (file)
--- a/qosify.h
+++ b/qosify.h
@@ -81,6 +81,7 @@ void qosify_map_dump(struct blob_buf *b);
 void qosify_map_set_dscp_default(enum qosify_map_id id, struct qosify_dscp_val val);
 void qosify_map_reset_config(void);
 void qosify_map_update_config(void);
+void qosify_map_set_aliases(struct blob_attr *val);
 int qosify_map_add_dns_host(char *host, const char *addr, const char *type, int ttl);
 
 int qosify_iface_init(void);
diff --git a/ubus.c b/ubus.c
index d1c03032b8a2376dbf91b79325478bd3edf4133e..fb5a6b7244c2dc0e76e0befaec23ed0b158dfbfa 100644 (file)
--- a/ubus.c
+++ b/ubus.c
@@ -138,6 +138,7 @@ enum {
        CL_CONFIG_PRIO_PKT_LEN,
        CL_CONFIG_INTERFACES,
        CL_CONFIG_DEVICES,
+       CL_CONFIG_ALIASES,
        __CL_CONFIG_MAX
 };
 
@@ -155,6 +156,7 @@ static const struct blobmsg_policy qosify_config_policy[__CL_CONFIG_MAX] = {
        [CL_CONFIG_PRIO_PKT_LEN] = { "prio_max_avg_pkt_len", BLOBMSG_TYPE_INT32 },
        [CL_CONFIG_INTERFACES] = { "interfaces", BLOBMSG_TYPE_TABLE },
        [CL_CONFIG_DEVICES] = { "devices", BLOBMSG_TYPE_TABLE },
+       [CL_CONFIG_ALIASES] = { "aliases", BLOBMSG_TYPE_TABLE },
 };
 
 static int __set_dscp(struct qosify_dscp_val *dest, struct blob_attr *attr, bool reset)
@@ -193,6 +195,9 @@ qosify_ubus_config(struct ubus_context *ctx, struct ubus_object *obj,
        if (reset)
                qosify_map_reset_config();
 
+       if ((cur = tb[CL_CONFIG_ALIASES]) != NULL || reset)
+               qosify_map_set_aliases(cur);
+
        if ((cur = tb[CL_CONFIG_TIMEOUT]) != NULL)
                qosify_map_timeout = blobmsg_get_u32(cur);