1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
15 #include <libubox/uloop.h>
16 #include <libubox/avl-cmp.h>
20 struct qosify_map_class
;
22 static int qosify_map_entry_cmp(const void *k1
, const void *k2
, void *ptr
);
24 static int qosify_map_fds
[__CL_MAP_MAX
];
25 static AVL_TREE(map_data
, qosify_map_entry_cmp
, false, NULL
);
26 static LIST_HEAD(map_files
);
27 static struct qosify_map_class
*map_class
[QOSIFY_MAX_CLASS_ENTRIES
];
28 static uint32_t next_timeout
;
29 static uint8_t qosify_dscp_default
[2] = { 0xff, 0xff };
30 int qosify_map_timeout
;
31 int qosify_active_timeout
;
32 struct qosify_config config
;
33 struct qosify_flow_config flow_config
;
34 static uint32_t map_dns_seq
;
36 struct qosify_map_file
{
37 struct list_head list
;
41 struct qosify_map_class
{
43 struct qosify_class data
;
48 const char *type_name
;
49 } qosify_map_info
[] = {
50 [CL_MAP_TCP_PORTS
] = { "tcp_ports", "tcp_port" },
51 [CL_MAP_UDP_PORTS
] = { "udp_ports", "udp_port" },
52 [CL_MAP_IPV4_ADDR
] = { "ipv4_map", "ipv4_addr" },
53 [CL_MAP_IPV6_ADDR
] = { "ipv6_map", "ipv6_addr" },
54 [CL_MAP_CONFIG
] = { "config", "config" },
55 [CL_MAP_CLASS
] = { "class_map", "class" },
56 [CL_MAP_DNS
] = { "dns", "dns" },
89 static void qosify_map_timer_cb(struct uloop_timeout
*t
)
94 static struct uloop_timeout qosify_map_timer
= {
95 .cb
= qosify_map_timer_cb
,
98 static uint32_t qosify_gettime(void)
102 clock_gettime(CLOCK_MONOTONIC
, &ts
);
108 qosify_map_path(enum qosify_map_id id
)
110 static char path
[128];
113 if (id
>= ARRAY_SIZE(qosify_map_info
))
116 name
= qosify_map_info
[id
].name
;
120 snprintf(path
, sizeof(path
), "%s/%s", CLASSIFY_DATA_PATH
, name
);
125 static int qosify_map_get_fd(enum qosify_map_id id
)
127 const char *path
= qosify_map_path(id
);
133 fd
= bpf_obj_get(path
);
135 fprintf(stderr
, "Failed to open map %s: %s\n", path
, strerror(errno
));
140 static void qosify_map_clear_list(enum qosify_map_id id
)
142 int fd
= qosify_map_fds
[id
];
145 while (bpf_map_get_next_key(fd
, &key
, &key
) != -1)
146 bpf_map_delete_elem(fd
, &key
);
149 static void __qosify_map_set_dscp_default(enum qosify_map_id id
, uint8_t val
)
151 struct qosify_map_data data
= {
154 struct qosify_class
class = {
162 if (!(val
& QOSIFY_DSCP_CLASS_FLAG
)) {
163 if (id
== CL_MAP_TCP_PORTS
)
164 key
= QOSIFY_MAX_CLASS_ENTRIES
;
165 else if (id
== CL_MAP_UDP_PORTS
)
166 key
= QOSIFY_MAX_CLASS_ENTRIES
+ 1;
170 fd
= qosify_map_fds
[CL_MAP_CLASS
];
172 memcpy(&class.config
, &flow_config
, sizeof(class.config
));
173 bpf_map_update_elem(fd
, &key
, &class, BPF_ANY
);
175 val
= key
| QOSIFY_DSCP_CLASS_FLAG
;
178 fd
= qosify_map_fds
[id
];
179 for (i
= 0; i
< (1 << 16); i
++) {
180 data
.addr
.port
= htons(i
);
181 if (avl_find(&map_data
, &data
))
184 bpf_map_update_elem(fd
, &data
.addr
, &val
, BPF_ANY
);
188 void qosify_map_set_dscp_default(enum qosify_map_id id
, uint8_t val
)
192 if (id
== CL_MAP_TCP_PORTS
)
194 else if (id
== CL_MAP_UDP_PORTS
)
199 if (!memcmp(&qosify_dscp_default
[udp
], &val
, sizeof(val
)))
202 qosify_dscp_default
[udp
] = val
;
203 __qosify_map_set_dscp_default(id
, val
);
206 int qosify_map_init(void)
210 for (i
= 0; i
< CL_MAP_DNS
; i
++) {
211 qosify_map_fds
[i
] = qosify_map_get_fd(i
);
212 if (qosify_map_fds
[i
] < 0)
216 qosify_map_clear_list(CL_MAP_IPV4_ADDR
);
217 qosify_map_clear_list(CL_MAP_IPV6_ADDR
);
218 qosify_map_reset_config();
223 static char *str_skip(char *str
, bool space
)
225 while (*str
&& isspace(*str
) == space
)
232 qosify_map_codepoint(const char *val
)
236 for (i
= 0; i
< ARRAY_SIZE(codepoints
); i
++)
237 if (!strcmp(codepoints
[i
].name
, val
))
238 return codepoints
[i
].val
;
243 static int qosify_map_entry_cmp(const void *k1
, const void *k2
, void *ptr
)
245 const struct qosify_map_data
*d1
= k1
;
246 const struct qosify_map_data
*d2
= k2
;
248 if (d1
->id
!= d2
->id
)
249 return d2
->id
- d1
->id
;
251 if (d1
->id
== CL_MAP_DNS
)
252 return strcmp(d1
->addr
.dns
.pattern
, d2
->addr
.dns
.pattern
);
254 return memcmp(&d1
->addr
, &d2
->addr
, sizeof(d1
->addr
));
257 static struct qosify_map_entry
*
258 __qosify_map_alloc_entry(struct qosify_map_data
*data
)
260 struct qosify_map_entry
*e
;
264 if (data
->id
< CL_MAP_DNS
) {
265 e
= calloc(1, sizeof(*e
));
266 memcpy(&e
->data
.addr
, &data
->addr
, sizeof(e
->data
.addr
));
271 e
= calloc_a(sizeof(*e
), &pattern
, strlen(data
->addr
.dns
.pattern
) + 1);
272 strcpy(pattern
, data
->addr
.dns
.pattern
);
273 e
->data
.addr
.dns
.pattern
= pattern
;
275 for (c
= pattern
; *c
; c
++)
278 if (pattern
[0] == '/' &&
279 regcomp(&e
->data
.addr
.dns
.regex
, pattern
+ 1,
280 REG_EXTENDED
| REG_NOSUB
)) {
288 void __qosify_map_set_entry(struct qosify_map_data
*data
)
290 int fd
= qosify_map_fds
[data
->id
];
291 struct qosify_map_entry
*e
;
292 bool file
= data
->file
;
293 uint8_t prev_dscp
= 0xff;
295 bool add
= data
->dscp
!= 0xff;
297 e
= avl_find_element(&map_data
, data
, e
, avl
);
302 e
= __qosify_map_alloc_entry(data
);
306 e
->avl
.key
= &e
->data
;
307 e
->data
.id
= data
->id
;
308 avl_insert(&map_data
, &e
->avl
);
310 prev_dscp
= e
->data
.dscp
;
320 e
->data
.file_dscp
= data
->dscp
;
321 if (!e
->data
.user
|| !file
)
322 e
->data
.dscp
= data
->dscp
;
323 } else if (e
->data
.file
&& !file
) {
324 e
->data
.dscp
= e
->data
.file_dscp
;
327 if (e
->data
.dscp
!= prev_dscp
&& data
->id
< CL_MAP_DNS
) {
328 struct qosify_ip_map_val val
= {
329 .dscp
= e
->data
.dscp
,
333 bpf_map_update_elem(fd
, &data
->addr
, &val
, BPF_ANY
);
336 if (data
->id
== CL_MAP_DNS
)
337 e
->data
.addr
.dns
.seq
= ++map_dns_seq
;
340 if (qosify_map_timeout
== ~0 || file
) {
345 e
->timeout
= qosify_gettime() + qosify_map_timeout
;
346 delta
= e
->timeout
- next_timeout
;
347 if (next_timeout
&& delta
>= 0)
351 uloop_timeout_set(&qosify_map_timer
, 1);
355 qosify_map_set_port(struct qosify_map_data
*data
, const char *str
)
357 unsigned long start_port
, end_port
;
361 start_port
= end_port
= strtoul(str
, &err
, 0);
364 end_port
= strtoul(err
+ 1, &err
, 0);
369 if (!start_port
|| end_port
< start_port
||
373 for (i
= start_port
; i
<= end_port
; i
++) {
374 data
->addr
.port
= htons(i
);
375 __qosify_map_set_entry(data
);
382 qosify_map_fill_ip(struct qosify_map_data
*data
, const char *str
)
386 if (data
->id
== CL_MAP_IPV6_ADDR
)
391 if (inet_pton(af
, str
, &data
->addr
) != 1)
397 int qosify_map_set_entry(enum qosify_map_id id
, bool file
, const char *str
,
400 struct qosify_map_data data
= {
408 data
.addr
.dns
.pattern
= str
;
410 data
.addr
.dns
.only_cname
= 1;
412 case CL_MAP_TCP_PORTS
:
413 case CL_MAP_UDP_PORTS
:
414 return qosify_map_set_port(&data
, str
);
415 case CL_MAP_IPV4_ADDR
:
416 case CL_MAP_IPV6_ADDR
:
417 if (qosify_map_fill_ip(&data
, str
))
424 __qosify_map_set_entry(&data
);
430 __qosify_map_dscp_value(const char *val
, uint8_t *dscp_val
)
433 bool fallback
= false;
441 dscp
= strtoul(val
, &err
, 0);
443 dscp
= qosify_map_codepoint(val
);
448 *dscp_val
= dscp
| (fallback
<< 6);
454 qosify_map_check_class(const char *val
, uint8_t *dscp_val
)
458 for (i
= 0; i
< ARRAY_SIZE(map_class
); i
++) {
459 if (map_class
[i
] && !strcmp(val
, map_class
[i
]->name
)) {
460 *dscp_val
= i
| QOSIFY_DSCP_CLASS_FLAG
;
468 int qosify_map_dscp_value(const char *val
, uint8_t *dscp_val
)
470 uint8_t fallback
= 0;
473 fallback
= QOSIFY_DSCP_FALLBACK_FLAG
;
477 if (qosify_map_check_class(val
, dscp_val
) &&
478 __qosify_map_dscp_value(val
, dscp_val
))
481 *dscp_val
|= fallback
;
487 qosify_map_dscp_codepoint_str(char *dest
, int len
, uint8_t dscp
)
491 if (dscp
& QOSIFY_DSCP_FALLBACK_FLAG
) {
494 dscp
&= ~QOSIFY_DSCP_FALLBACK_FLAG
;
497 for (i
= 0; i
< ARRAY_SIZE(codepoints
); i
++) {
498 if (codepoints
[i
].val
!= dscp
)
501 snprintf(dest
, len
, "%s", codepoints
[i
].name
);
505 snprintf(dest
, len
, "0x%x", dscp
);
509 qosify_map_parse_line(char *str
)
511 const char *key
, *value
;
514 str
= str_skip(str
, true);
517 str
= str_skip(str
, false);
522 str
= str_skip(str
, true);
525 if (qosify_map_dscp_value(value
, &dscp
))
528 if (!strncmp(key
, "dns:", 4))
529 qosify_map_set_entry(CL_MAP_DNS
, true, key
+ 4, dscp
);
530 if (!strncmp(key
, "dns_q:", 6) || !strncmp(key
, "dns_c:", 6))
531 qosify_map_set_entry(CL_MAP_DNS
, true, key
+ 6, dscp
);
532 if (!strncmp(key
, "tcp:", 4))
533 qosify_map_set_entry(CL_MAP_TCP_PORTS
, true, key
+ 4, dscp
);
534 else if (!strncmp(key
, "udp:", 4))
535 qosify_map_set_entry(CL_MAP_UDP_PORTS
, true, key
+ 4, dscp
);
536 else if (strchr(key
, ':'))
537 qosify_map_set_entry(CL_MAP_IPV6_ADDR
, true, key
, dscp
);
538 else if (strchr(key
, '.'))
539 qosify_map_set_entry(CL_MAP_IPV4_ADDR
, true, key
, dscp
);
543 __qosify_map_load_file_data(FILE *f
)
548 while (fgets(line
, sizeof(line
), f
)) {
549 cur
= strchr(line
, '#');
553 cur
= line
+ strlen(line
);
557 while (cur
> line
&& isspace(cur
[-1]))
561 qosify_map_parse_line(line
);
567 __qosify_map_load_file(const char *file
)
576 glob(file
, 0, NULL
, &gl
);
578 for (i
= 0; i
< gl
.gl_pathc
; i
++) {
579 f
= fopen(file
, "r");
583 __qosify_map_load_file_data(f
);
592 int qosify_map_load_file(const char *file
)
594 struct qosify_map_file
*f
;
599 f
= calloc(1, sizeof(*f
) + strlen(file
) + 1);
600 strcpy(f
->filename
, file
);
601 list_add_tail(&f
->list
, &map_files
);
603 return __qosify_map_load_file(file
);
606 static void qosify_map_reset_file_entries(void)
608 struct qosify_map_entry
*e
;
611 avl_for_each_element(&map_data
, e
, avl
)
612 e
->data
.file
= false;
615 void qosify_map_clear_files(void)
617 struct qosify_map_file
*f
, *tmp
;
619 qosify_map_reset_file_entries();
621 list_for_each_entry_safe(f
, tmp
, &map_files
, list
) {
627 void qosify_map_reset_config(void)
629 qosify_map_clear_files();
630 qosify_map_set_dscp_default(CL_MAP_TCP_PORTS
, 0);
631 qosify_map_set_dscp_default(CL_MAP_UDP_PORTS
, 0);
632 qosify_map_timeout
= 3600;
633 qosify_active_timeout
= 300;
635 memset(&config
, 0, sizeof(config
));
636 flow_config
.dscp_prio
= 0xff;
637 flow_config
.dscp_bulk
= 0xff;
638 config
.dscp_icmp
= 0xff;
641 void qosify_map_reload(void)
643 struct qosify_map_file
*f
;
645 qosify_map_reset_file_entries();
647 list_for_each_entry(f
, &map_files
, list
)
648 __qosify_map_load_file(f
->filename
);
653 static void qosify_map_free_entry(struct qosify_map_entry
*e
)
655 int fd
= qosify_map_fds
[e
->data
.id
];
657 avl_delete(&map_data
, &e
->avl
);
658 if (e
->data
.id
< CL_MAP_DNS
)
659 bpf_map_delete_elem(fd
, &e
->data
.addr
);
664 qosify_map_entry_refresh_timeout(struct qosify_map_entry
*e
)
666 struct qosify_ip_map_val val
;
667 int fd
= qosify_map_fds
[e
->data
.id
];
669 if (e
->data
.id
!= CL_MAP_IPV4_ADDR
&&
670 e
->data
.id
!= CL_MAP_IPV6_ADDR
)
673 if (bpf_map_lookup_elem(fd
, &e
->data
.addr
, &val
))
679 e
->timeout
= qosify_gettime() + qosify_active_timeout
;
681 bpf_map_update_elem(fd
, &e
->data
.addr
, &val
, BPF_ANY
);
686 void qosify_map_gc(void)
688 struct qosify_map_entry
*e
, *tmp
;
690 uint32_t cur_time
= qosify_gettime();
693 avl_for_each_element_safe(&map_data
, e
, avl
, tmp
) {
696 if (e
->data
.user
&& e
->timeout
!= ~0) {
697 cur_timeout
= e
->timeout
- cur_time
;
698 if (cur_timeout
<= 0 &&
699 qosify_map_entry_refresh_timeout(e
))
700 cur_timeout
= e
->timeout
- cur_time
;
701 if (cur_timeout
<= 0) {
702 e
->data
.user
= false;
703 e
->data
.dscp
= e
->data
.file_dscp
;
704 } else if (!timeout
|| cur_timeout
< timeout
) {
705 timeout
= cur_timeout
;
706 next_timeout
= e
->timeout
;
710 if (e
->data
.file
|| e
->data
.user
)
713 qosify_map_free_entry(e
);
719 uloop_timeout_set(&qosify_map_timer
, timeout
* 1000);
722 int qosify_map_lookup_dns_entry(char *host
, bool cname
, uint8_t *dscp
, uint32_t *seq
)
724 struct qosify_map_data data
= {
726 .addr
.dns
.pattern
= "",
728 struct qosify_map_entry
*e
;
732 e
= avl_find_ge_element(&map_data
, &data
, e
, avl
);
736 for (c
= host
; *c
; c
++)
739 avl_for_element_to_last(&map_data
, e
, e
, avl
) {
740 regex_t
*regex
= &e
->data
.addr
.dns
.regex
;
742 if (e
->data
.id
!= CL_MAP_DNS
)
745 if (!cname
&& e
->data
.addr
.dns
.only_cname
)
748 if (e
->data
.addr
.dns
.pattern
[0] == '/') {
749 if (regexec(regex
, host
, 0, NULL
, 0) != 0)
752 if (fnmatch(e
->data
.addr
.dns
.pattern
, host
, 0))
756 if (*dscp
== 0xff || e
->data
.addr
.dns
.seq
< *seq
) {
757 *dscp
= e
->data
.dscp
;
758 *seq
= e
->data
.addr
.dns
.seq
;
767 int qosify_map_add_dns_host(char *host
, const char *addr
, const char *type
, int ttl
)
769 struct qosify_map_data data
= {
772 int prev_timeout
= qosify_map_timeout
;
773 uint32_t lookup_seq
= 0;
775 if (qosify_map_lookup_dns_entry(host
, false, &data
.dscp
, &lookup_seq
))
779 if (!strcmp(type
, "A"))
780 data
.id
= CL_MAP_IPV4_ADDR
;
781 else if (!strcmp(type
, "AAAA"))
782 data
.id
= CL_MAP_IPV6_ADDR
;
786 if (qosify_map_fill_ip(&data
, addr
))
790 qosify_map_timeout
= ttl
;
791 __qosify_map_set_entry(&data
);
792 qosify_map_timeout
= prev_timeout
;
798 blobmsg_add_dscp(struct blob_buf
*b
, const char *name
, uint8_t dscp
)
803 if (dscp
& QOSIFY_DSCP_CLASS_FLAG
) {
807 idx
= dscp
& QOSIFY_DSCP_VALUE_MASK
;
809 val
= map_class
[idx
]->name
;
813 blobmsg_printf(b
, name
, "%s%s",
814 (dscp
& QOSIFY_DSCP_FALLBACK_FLAG
) ? "+" : "", val
);
818 buf
= blobmsg_alloc_string_buffer(b
, name
, buf_len
);
819 qosify_map_dscp_codepoint_str(buf
, buf_len
, dscp
);
820 blobmsg_add_string_buffer(b
);
824 void qosify_map_dump(struct blob_buf
*b
)
826 struct qosify_map_entry
*e
;
827 uint32_t cur_time
= qosify_gettime();
828 int buf_len
= INET6_ADDRSTRLEN
+ 1;
833 a
= blobmsg_open_array(b
, "entries");
834 avl_for_each_element(&map_data
, e
, avl
) {
837 if (!e
->data
.file
&& !e
->data
.user
)
840 c
= blobmsg_open_table(b
, NULL
);
841 if (e
->data
.user
&& e
->timeout
!= ~0) {
842 int32_t cur_timeout
= e
->timeout
- cur_time
;
847 blobmsg_add_u32(b
, "timeout", cur_timeout
);
850 blobmsg_add_u8(b
, "file", e
->data
.file
);
851 blobmsg_add_u8(b
, "user", e
->data
.user
);
853 blobmsg_add_dscp(b
, "dscp", e
->data
.dscp
);
855 blobmsg_add_string(b
, "type", qosify_map_info
[e
->data
.id
].type_name
);
857 switch (e
->data
.id
) {
858 case CL_MAP_TCP_PORTS
:
859 case CL_MAP_UDP_PORTS
:
860 blobmsg_printf(b
, "addr", "%d", ntohs(e
->data
.addr
.port
));
862 case CL_MAP_IPV4_ADDR
:
863 case CL_MAP_IPV6_ADDR
:
864 buf
= blobmsg_alloc_string_buffer(b
, "addr", buf_len
);
865 af
= e
->data
.id
== CL_MAP_IPV6_ADDR
? AF_INET6
: AF_INET
;
866 inet_ntop(af
, &e
->data
.addr
, buf
, buf_len
);
867 blobmsg_add_string_buffer(b
);
870 blobmsg_add_string(b
, "addr", e
->data
.addr
.dns
.pattern
);
875 blobmsg_close_table(b
, c
);
877 blobmsg_close_array(b
, a
);
881 qosify_map_get_class_id(const char *name
)
885 for (i
= 0; i
< ARRAY_SIZE(map_class
); i
++)
886 if (map_class
[i
] && !strcmp(map_class
[i
]->name
, name
))
889 for (i
= 0; i
< ARRAY_SIZE(map_class
); i
++)
893 for (i
= 0; i
< ARRAY_SIZE(map_class
); i
++) {
894 if (!(map_class
[i
]->data
.flags
& QOSIFY_CLASS_FLAG_PRESENT
)) {
904 int map_fill_dscp_value(uint8_t *dest
, struct blob_attr
*attr
, bool reset
)
912 if (qosify_map_dscp_value(blobmsg_get_string(attr
), dest
))
918 int map_parse_flow_config(struct qosify_flow_config
*cfg
, struct blob_attr
*attr
,
924 CL_CONFIG_BULK_TIMEOUT
,
926 CL_CONFIG_PRIO_PKT_LEN
,
929 static const struct blobmsg_policy policy
[__CL_CONFIG_MAX
] = {
930 [CL_CONFIG_DSCP_PRIO
] = { "dscp_prio", BLOBMSG_TYPE_STRING
},
931 [CL_CONFIG_DSCP_BULK
] = { "dscp_bulk", BLOBMSG_TYPE_STRING
},
932 [CL_CONFIG_BULK_TIMEOUT
] = { "bulk_trigger_timeout", BLOBMSG_TYPE_INT32
},
933 [CL_CONFIG_BULK_PPS
] = { "bulk_trigger_pps", BLOBMSG_TYPE_INT32
},
934 [CL_CONFIG_PRIO_PKT_LEN
] = { "prio_max_avg_pkt_len", BLOBMSG_TYPE_INT32
},
936 struct blob_attr
*tb
[__CL_CONFIG_MAX
];
937 struct blob_attr
*cur
;
940 memset(cfg
, 0, sizeof(*cfg
));
942 blobmsg_parse(policy
, __CL_CONFIG_MAX
, tb
, blobmsg_data(attr
), blobmsg_len(attr
));
944 if (map_fill_dscp_value(&cfg
->dscp_prio
, tb
[CL_CONFIG_DSCP_PRIO
], reset
) ||
945 map_fill_dscp_value(&cfg
->dscp_bulk
, tb
[CL_CONFIG_DSCP_BULK
], reset
))
948 if ((cur
= tb
[CL_CONFIG_BULK_TIMEOUT
]) != NULL
)
949 cfg
->bulk_trigger_timeout
= blobmsg_get_u32(cur
);
951 if ((cur
= tb
[CL_CONFIG_BULK_PPS
]) != NULL
)
952 cfg
->bulk_trigger_pps
= blobmsg_get_u32(cur
);
954 if ((cur
= tb
[CL_CONFIG_PRIO_PKT_LEN
]) != NULL
)
955 cfg
->prio_max_avg_pkt_len
= blobmsg_get_u32(cur
);
961 qosify_map_create_class(struct blob_attr
*attr
)
963 struct qosify_map_class
*class;
969 static const struct blobmsg_policy policy
[__MAP_CLASS_MAX
] = {
970 [MAP_CLASS_INGRESS
] = { "ingress", BLOBMSG_TYPE_STRING
},
971 [MAP_CLASS_EGRESS
] = { "egress", BLOBMSG_TYPE_STRING
},
973 struct blob_attr
*tb
[__MAP_CLASS_MAX
];
978 blobmsg_parse(policy
, __MAP_CLASS_MAX
, tb
,
979 blobmsg_data(attr
), blobmsg_len(attr
));
981 if (!tb
[MAP_CLASS_INGRESS
] || !tb
[MAP_CLASS_EGRESS
])
984 name
= blobmsg_name(attr
);
985 slot
= qosify_map_get_class_id(name
);
989 class = map_class
[slot
];
991 class = calloc_a(sizeof(*class), &name_buf
, strlen(name
) + 1);
992 class->name
= strcpy(name_buf
, name
);
993 map_class
[slot
] = class;
996 class->data
.flags
|= QOSIFY_CLASS_FLAG_PRESENT
;
997 if (__qosify_map_dscp_value(blobmsg_get_string(tb
[MAP_CLASS_INGRESS
]),
998 &class->data
.val
.ingress
) ||
999 __qosify_map_dscp_value(blobmsg_get_string(tb
[MAP_CLASS_EGRESS
]),
1000 &class->data
.val
.egress
)) {
1001 map_class
[slot
] = NULL
;
1009 void qosify_map_set_classes(struct blob_attr
*val
)
1011 int fd
= qosify_map_fds
[CL_MAP_CLASS
];
1012 struct qosify_class empty_data
= {};
1013 struct blob_attr
*cur
;
1017 for (i
= 0; i
< ARRAY_SIZE(map_class
); i
++)
1019 map_class
[i
]->data
.flags
&= ~QOSIFY_CLASS_FLAG_PRESENT
;
1021 blobmsg_for_each_attr(cur
, val
, rem
)
1022 qosify_map_create_class(cur
);
1024 for (i
= 0; i
< ARRAY_SIZE(map_class
); i
++) {
1026 (map_class
[i
]->data
.flags
& QOSIFY_CLASS_FLAG_PRESENT
))
1030 map_class
[i
] = NULL
;
1033 blobmsg_for_each_attr(cur
, val
, rem
) {
1034 i
= qosify_map_get_class_id(blobmsg_name(cur
));
1035 if (i
< 0 || !map_class
[i
])
1038 map_parse_flow_config(&map_class
[i
]->data
.config
, cur
, true);
1041 for (i
= 0; i
< ARRAY_SIZE(map_class
); i
++) {
1042 struct qosify_class
*data
;
1044 data
= map_class
[i
] ? &map_class
[i
]->data
: &empty_data
;
1045 bpf_map_update_elem(fd
, &i
, data
, BPF_ANY
);
1049 void qosify_map_update_config(void)
1051 int fd
= qosify_map_fds
[CL_MAP_CONFIG
];
1054 bpf_map_update_elem(fd
, &key
, &config
, BPF_ANY
);