map.c 22 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
  4. */
  5. #include <arpa/inet.h>
  6. #include <errno.h>
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <stdlib.h>
  10. #include <time.h>
  11. #include <fnmatch.h>
  12. #include <glob.h>
  13. #include <libubox/uloop.h>
  14. #include <libubox/avl-cmp.h>
  15. #include "qosify.h"
  16. struct qosify_map_class;
  17. static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr);
  18. static int qosify_map_fds[__CL_MAP_MAX];
  19. static AVL_TREE(map_data, qosify_map_entry_cmp, false, NULL);
  20. static LIST_HEAD(map_files);
  21. static struct qosify_map_class *map_class[QOSIFY_MAX_CLASS_ENTRIES];
  22. static uint32_t next_timeout;
  23. static uint8_t qosify_dscp_default[2] = { 0xff, 0xff };
  24. int qosify_map_timeout;
  25. int qosify_active_timeout;
  26. struct qosify_config config;
  27. struct qosify_flow_config flow_config;
  28. static uint32_t map_dns_seq;
  29. struct qosify_map_file {
  30. struct list_head list;
  31. char filename[];
  32. };
  33. struct qosify_map_class {
  34. const char *name;
  35. struct qosify_class data;
  36. };
  37. static const struct {
  38. const char *name;
  39. const char *type_name;
  40. } qosify_map_info[] = {
  41. [CL_MAP_TCP_PORTS] = { "tcp_ports", "tcp_port" },
  42. [CL_MAP_UDP_PORTS] = { "udp_ports", "udp_port" },
  43. [CL_MAP_IPV4_ADDR] = { "ipv4_map", "ipv4_addr" },
  44. [CL_MAP_IPV6_ADDR] = { "ipv6_map", "ipv6_addr" },
  45. [CL_MAP_CONFIG] = { "config", "config" },
  46. [CL_MAP_CLASS] = { "class_map", "class" },
  47. [CL_MAP_DNS] = { "dns", "dns" },
  48. };
  49. static const struct {
  50. const char name[5];
  51. uint8_t val;
  52. } codepoints[] = {
  53. { "CS0", 0 },
  54. { "CS1", 8 },
  55. { "CS2", 16 },
  56. { "CS3", 24 },
  57. { "CS4", 32 },
  58. { "CS5", 40 },
  59. { "CS6", 48 },
  60. { "CS7", 56 },
  61. { "AF11", 10 },
  62. { "AF12", 12 },
  63. { "AF13", 14 },
  64. { "AF21", 18 },
  65. { "AF22", 20 },
  66. { "AF23", 22 },
  67. { "AF31", 26 },
  68. { "AF32", 28 },
  69. { "AF33", 30 },
  70. { "AF41", 34 },
  71. { "AF42", 36 },
  72. { "AF43", 38 },
  73. { "EF", 46 },
  74. { "VA", 44 },
  75. { "LE", 1 },
  76. { "DF", 0 },
  77. };
  78. static void qosify_map_timer_cb(struct uloop_timeout *t)
  79. {
  80. qosify_map_gc();
  81. }
  82. static struct uloop_timeout qosify_map_timer = {
  83. .cb = qosify_map_timer_cb,
  84. };
  85. static uint32_t qosify_gettime(void)
  86. {
  87. struct timespec ts;
  88. clock_gettime(CLOCK_MONOTONIC, &ts);
  89. return ts.tv_sec;
  90. }
  91. static const char *
  92. qosify_map_path(enum qosify_map_id id)
  93. {
  94. static char path[128];
  95. const char *name;
  96. if (id >= ARRAY_SIZE(qosify_map_info))
  97. return NULL;
  98. name = qosify_map_info[id].name;
  99. if (!name)
  100. return NULL;
  101. snprintf(path, sizeof(path), "%s/%s", CLASSIFY_DATA_PATH, name);
  102. return path;
  103. }
  104. static int qosify_map_get_fd(enum qosify_map_id id)
  105. {
  106. const char *path = qosify_map_path(id);
  107. int fd;
  108. if (!path)
  109. return -1;
  110. fd = bpf_obj_get(path);
  111. if (fd < 0)
  112. fprintf(stderr, "Failed to open map %s: %s\n", path, strerror(errno));
  113. return fd;
  114. }
  115. static void qosify_map_clear_list(enum qosify_map_id id)
  116. {
  117. int fd = qosify_map_fds[id];
  118. __u32 key[4] = {};
  119. while (bpf_map_get_next_key(fd, &key, &key) == 0)
  120. bpf_map_delete_elem(fd, &key);
  121. }
  122. static void __qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val)
  123. {
  124. struct qosify_map_data data = {
  125. .id = id,
  126. };
  127. struct qosify_class class = {
  128. .val.ingress = val,
  129. .val.egress = val,
  130. };
  131. uint32_t key;
  132. int fd;
  133. int i;
  134. if (!(val & QOSIFY_DSCP_CLASS_FLAG)) {
  135. if (id == CL_MAP_TCP_PORTS)
  136. key = QOSIFY_MAX_CLASS_ENTRIES;
  137. else if (id == CL_MAP_UDP_PORTS)
  138. key = QOSIFY_MAX_CLASS_ENTRIES + 1;
  139. else
  140. return;
  141. fd = qosify_map_fds[CL_MAP_CLASS];
  142. memcpy(&class.config, &flow_config, sizeof(class.config));
  143. bpf_map_update_elem(fd, &key, &class, BPF_ANY);
  144. val = key | QOSIFY_DSCP_CLASS_FLAG;
  145. }
  146. fd = qosify_map_fds[id];
  147. for (i = 0; i < (1 << 16); i++) {
  148. data.addr.port = htons(i);
  149. if (avl_find(&map_data, &data))
  150. continue;
  151. bpf_map_update_elem(fd, &data.addr, &val, BPF_ANY);
  152. }
  153. }
  154. void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val)
  155. {
  156. bool udp;
  157. if (id == CL_MAP_TCP_PORTS)
  158. udp = false;
  159. else if (id == CL_MAP_UDP_PORTS)
  160. udp = true;
  161. else
  162. return;
  163. if (val != 0xff) {
  164. if (qosify_dscp_default[udp] == val)
  165. return;
  166. qosify_dscp_default[udp] = val;
  167. }
  168. __qosify_map_set_dscp_default(id, qosify_dscp_default[udp]);
  169. }
  170. int qosify_map_init(void)
  171. {
  172. int i;
  173. for (i = 0; i < CL_MAP_DNS; i++) {
  174. qosify_map_fds[i] = qosify_map_get_fd(i);
  175. if (qosify_map_fds[i] < 0)
  176. return -1;
  177. }
  178. qosify_map_clear_list(CL_MAP_IPV4_ADDR);
  179. qosify_map_clear_list(CL_MAP_IPV6_ADDR);
  180. qosify_map_reset_config();
  181. return 0;
  182. }
  183. static char *str_skip(char *str, bool space)
  184. {
  185. while (*str && isspace(*str) == space)
  186. str++;
  187. return str;
  188. }
  189. static int
  190. qosify_map_codepoint(const char *val)
  191. {
  192. int i;
  193. for (i = 0; i < ARRAY_SIZE(codepoints); i++)
  194. if (!strcmp(codepoints[i].name, val))
  195. return codepoints[i].val;
  196. return 0xff;
  197. }
  198. static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr)
  199. {
  200. const struct qosify_map_data *d1 = k1;
  201. const struct qosify_map_data *d2 = k2;
  202. if (d1->id != d2->id)
  203. return d2->id - d1->id;
  204. if (d1->id == CL_MAP_DNS)
  205. return strcmp(d1->addr.dns.pattern, d2->addr.dns.pattern);
  206. return memcmp(&d1->addr, &d2->addr, sizeof(d1->addr));
  207. }
  208. static struct qosify_map_entry *
  209. __qosify_map_alloc_entry(struct qosify_map_data *data)
  210. {
  211. struct qosify_map_entry *e;
  212. char *pattern;
  213. char *c;
  214. if (data->id < CL_MAP_DNS) {
  215. e = calloc(1, sizeof(*e));
  216. memcpy(&e->data.addr, &data->addr, sizeof(e->data.addr));
  217. return e;
  218. }
  219. e = calloc_a(sizeof(*e), &pattern, strlen(data->addr.dns.pattern) + 1);
  220. strcpy(pattern, data->addr.dns.pattern);
  221. e->data.addr.dns.pattern = pattern;
  222. for (c = pattern; *c; c++)
  223. *c = tolower(*c);
  224. if (pattern[0] == '/' &&
  225. regcomp(&e->data.addr.dns.regex, pattern + 1,
  226. REG_EXTENDED | REG_NOSUB)) {
  227. free(e);
  228. return NULL;
  229. }
  230. return e;
  231. }
  232. void __qosify_map_set_entry(struct qosify_map_data *data)
  233. {
  234. int fd = qosify_map_fds[data->id];
  235. struct qosify_map_entry *e;
  236. bool file = data->file;
  237. uint8_t prev_dscp = 0xff;
  238. int32_t delta = 0;
  239. bool add = data->dscp != 0xff;
  240. e = avl_find_element(&map_data, data, e, avl);
  241. if (!e) {
  242. if (!add)
  243. return;
  244. e = __qosify_map_alloc_entry(data);
  245. if (!e)
  246. return;
  247. e->avl.key = &e->data;
  248. e->data.id = data->id;
  249. avl_insert(&map_data, &e->avl);
  250. } else {
  251. prev_dscp = e->data.dscp;
  252. }
  253. if (file)
  254. e->data.file = add;
  255. else
  256. e->data.user = add;
  257. if (add) {
  258. if (file)
  259. e->data.file_dscp = data->dscp;
  260. if (!e->data.user || !file)
  261. e->data.dscp = data->dscp;
  262. } else if (e->data.file && !file) {
  263. e->data.dscp = e->data.file_dscp;
  264. }
  265. if (e->data.dscp != prev_dscp && data->id < CL_MAP_DNS) {
  266. struct qosify_ip_map_val val = {
  267. .dscp = e->data.dscp,
  268. .seen = 1,
  269. };
  270. bpf_map_update_elem(fd, &data->addr, &val, BPF_ANY);
  271. }
  272. if (data->id == CL_MAP_DNS)
  273. e->data.addr.dns.seq = ++map_dns_seq;
  274. if (add) {
  275. if (qosify_map_timeout == ~0 || file) {
  276. e->timeout = ~0;
  277. return;
  278. }
  279. e->timeout = qosify_gettime() + qosify_map_timeout;
  280. delta = e->timeout - next_timeout;
  281. if (next_timeout && delta >= 0)
  282. return;
  283. }
  284. uloop_timeout_set(&qosify_map_timer, 1);
  285. }
  286. static int
  287. qosify_map_set_port(struct qosify_map_data *data, const char *str)
  288. {
  289. unsigned long start_port, end_port;
  290. char *err;
  291. int i;
  292. start_port = end_port = strtoul(str, &err, 0);
  293. if (err && *err) {
  294. if (*err == '-')
  295. end_port = strtoul(err + 1, &err, 0);
  296. if (*err)
  297. return -1;
  298. }
  299. if (!start_port || end_port < start_port ||
  300. end_port >= 65535)
  301. return -1;
  302. for (i = start_port; i <= end_port; i++) {
  303. data->addr.port = htons(i);
  304. __qosify_map_set_entry(data);
  305. }
  306. return 0;
  307. }
  308. static int
  309. qosify_map_fill_ip(struct qosify_map_data *data, const char *str)
  310. {
  311. int af;
  312. if (data->id == CL_MAP_IPV6_ADDR)
  313. af = AF_INET6;
  314. else
  315. af = AF_INET;
  316. if (inet_pton(af, str, &data->addr) != 1)
  317. return -1;
  318. return 0;
  319. }
  320. int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str,
  321. uint8_t dscp)
  322. {
  323. struct qosify_map_data data = {
  324. .id = id,
  325. .file = file,
  326. .dscp = dscp,
  327. };
  328. switch (id) {
  329. case CL_MAP_DNS:
  330. data.addr.dns.pattern = str;
  331. if (str[-2] == 'c')
  332. data.addr.dns.only_cname = 1;
  333. break;
  334. case CL_MAP_TCP_PORTS:
  335. case CL_MAP_UDP_PORTS:
  336. return qosify_map_set_port(&data, str);
  337. case CL_MAP_IPV4_ADDR:
  338. case CL_MAP_IPV6_ADDR:
  339. if (qosify_map_fill_ip(&data, str))
  340. return -1;
  341. break;
  342. default:
  343. return -1;
  344. }
  345. __qosify_map_set_entry(&data);
  346. return 0;
  347. }
  348. static int
  349. __qosify_map_dscp_value(const char *val, uint8_t *dscp_val)
  350. {
  351. unsigned long dscp;
  352. bool fallback = false;
  353. char *err;
  354. if (*val == '+') {
  355. fallback = true;
  356. val++;
  357. }
  358. dscp = strtoul(val, &err, 0);
  359. if (err && *err)
  360. dscp = qosify_map_codepoint(val);
  361. if (dscp >= 64)
  362. return -1;
  363. *dscp_val = dscp | (fallback << 6);
  364. return 0;
  365. }
  366. static int
  367. qosify_map_check_class(const char *val, uint8_t *dscp_val)
  368. {
  369. int i;
  370. for (i = 0; i < ARRAY_SIZE(map_class); i++) {
  371. if (map_class[i] && !strcmp(val, map_class[i]->name)) {
  372. *dscp_val = i | QOSIFY_DSCP_CLASS_FLAG;
  373. return 0;
  374. }
  375. }
  376. return -1;
  377. }
  378. int qosify_map_dscp_value(const char *val, uint8_t *dscp_val)
  379. {
  380. uint8_t fallback = 0;
  381. if (*val == '+') {
  382. fallback = QOSIFY_DSCP_FALLBACK_FLAG;
  383. val++;
  384. }
  385. if (qosify_map_check_class(val, dscp_val) &&
  386. __qosify_map_dscp_value(val, dscp_val))
  387. return -1;
  388. *dscp_val |= fallback;
  389. return 0;
  390. }
  391. static void
  392. qosify_map_dscp_codepoint_str(char *dest, int len, uint8_t dscp)
  393. {
  394. int i;
  395. if (dscp & QOSIFY_DSCP_FALLBACK_FLAG) {
  396. *(dest++) = '+';
  397. len--;
  398. dscp &= ~QOSIFY_DSCP_FALLBACK_FLAG;
  399. }
  400. for (i = 0; i < ARRAY_SIZE(codepoints); i++) {
  401. if (codepoints[i].val != dscp)
  402. continue;
  403. snprintf(dest, len, "%s", codepoints[i].name);
  404. return;
  405. }
  406. snprintf(dest, len, "0x%x", dscp);
  407. }
  408. static void
  409. qosify_map_parse_line(char *str)
  410. {
  411. const char *key, *value;
  412. uint8_t dscp;
  413. str = str_skip(str, true);
  414. key = str;
  415. str = str_skip(str, false);
  416. if (!*str)
  417. return;
  418. *(str++) = 0;
  419. str = str_skip(str, true);
  420. value = str;
  421. if (qosify_map_dscp_value(value, &dscp))
  422. return;
  423. if (!strncmp(key, "dns:", 4))
  424. qosify_map_set_entry(CL_MAP_DNS, true, key + 4, dscp);
  425. if (!strncmp(key, "dns_q:", 6) || !strncmp(key, "dns_c:", 6))
  426. qosify_map_set_entry(CL_MAP_DNS, true, key + 6, dscp);
  427. if (!strncmp(key, "tcp:", 4))
  428. qosify_map_set_entry(CL_MAP_TCP_PORTS, true, key + 4, dscp);
  429. else if (!strncmp(key, "udp:", 4))
  430. qosify_map_set_entry(CL_MAP_UDP_PORTS, true, key + 4, dscp);
  431. else if (strchr(key, ':'))
  432. qosify_map_set_entry(CL_MAP_IPV6_ADDR, true, key, dscp);
  433. else if (strchr(key, '.'))
  434. qosify_map_set_entry(CL_MAP_IPV4_ADDR, true, key, dscp);
  435. }
  436. static void
  437. __qosify_map_load_file_data(FILE *f)
  438. {
  439. char line[1024];
  440. char *cur;
  441. while (fgets(line, sizeof(line), f)) {
  442. cur = strchr(line, '#');
  443. if (cur)
  444. *cur = 0;
  445. cur = line + strlen(line);
  446. if (cur == line)
  447. continue;
  448. while (cur > line && isspace(cur[-1]))
  449. cur--;
  450. *cur = 0;
  451. qosify_map_parse_line(line);
  452. }
  453. }
  454. static int
  455. __qosify_map_load_file(const char *file)
  456. {
  457. glob_t gl;
  458. FILE *f;
  459. int i;
  460. if (!file)
  461. return 0;
  462. glob(file, 0, NULL, &gl);
  463. for (i = 0; i < gl.gl_pathc; i++) {
  464. f = fopen(file, "r");
  465. if (!f)
  466. continue;
  467. __qosify_map_load_file_data(f);
  468. fclose(f);
  469. }
  470. globfree(&gl);
  471. return 0;
  472. }
  473. int qosify_map_load_file(const char *file)
  474. {
  475. struct qosify_map_file *f;
  476. if (!file)
  477. return 0;
  478. f = calloc(1, sizeof(*f) + strlen(file) + 1);
  479. strcpy(f->filename, file);
  480. list_add_tail(&f->list, &map_files);
  481. return __qosify_map_load_file(file);
  482. }
  483. static void qosify_map_reset_file_entries(void)
  484. {
  485. struct qosify_map_entry *e;
  486. map_dns_seq = 0;
  487. avl_for_each_element(&map_data, e, avl)
  488. e->data.file = false;
  489. }
  490. void qosify_map_clear_files(void)
  491. {
  492. struct qosify_map_file *f, *tmp;
  493. qosify_map_reset_file_entries();
  494. list_for_each_entry_safe(f, tmp, &map_files, list) {
  495. list_del(&f->list);
  496. free(f);
  497. }
  498. }
  499. void qosify_map_reset_config(void)
  500. {
  501. qosify_map_clear_files();
  502. qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, 0);
  503. qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, 0);
  504. qosify_map_timeout = 3600;
  505. qosify_active_timeout = 300;
  506. memset(&config, 0, sizeof(config));
  507. flow_config.dscp_prio = 0xff;
  508. flow_config.dscp_bulk = 0xff;
  509. config.dscp_icmp = 0xff;
  510. }
  511. void qosify_map_reload(void)
  512. {
  513. struct qosify_map_file *f;
  514. qosify_map_reset_file_entries();
  515. list_for_each_entry(f, &map_files, list)
  516. __qosify_map_load_file(f->filename);
  517. qosify_map_gc();
  518. qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, 0xff);
  519. qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, 0xff);
  520. }
  521. static void qosify_map_free_entry(struct qosify_map_entry *e)
  522. {
  523. int fd = qosify_map_fds[e->data.id];
  524. avl_delete(&map_data, &e->avl);
  525. if (e->data.id < CL_MAP_DNS)
  526. bpf_map_delete_elem(fd, &e->data.addr);
  527. free(e);
  528. }
  529. static bool
  530. qosify_map_entry_refresh_timeout(struct qosify_map_entry *e)
  531. {
  532. struct qosify_ip_map_val val;
  533. int fd = qosify_map_fds[e->data.id];
  534. if (e->data.id != CL_MAP_IPV4_ADDR &&
  535. e->data.id != CL_MAP_IPV6_ADDR)
  536. return false;
  537. if (bpf_map_lookup_elem(fd, &e->data.addr, &val))
  538. return false;
  539. if (!val.seen)
  540. return false;
  541. e->timeout = qosify_gettime() + qosify_active_timeout;
  542. val.seen = 0;
  543. bpf_map_update_elem(fd, &e->data.addr, &val, BPF_ANY);
  544. return true;
  545. }
  546. void qosify_map_gc(void)
  547. {
  548. struct qosify_map_entry *e, *tmp;
  549. int32_t timeout = 0;
  550. uint32_t cur_time = qosify_gettime();
  551. next_timeout = 0;
  552. avl_for_each_element_safe(&map_data, e, avl, tmp) {
  553. int32_t cur_timeout;
  554. if (e->data.user && e->timeout != ~0) {
  555. cur_timeout = e->timeout - cur_time;
  556. if (cur_timeout <= 0 &&
  557. qosify_map_entry_refresh_timeout(e))
  558. cur_timeout = e->timeout - cur_time;
  559. if (cur_timeout <= 0) {
  560. e->data.user = false;
  561. e->data.dscp = e->data.file_dscp;
  562. } else if (!timeout || cur_timeout < timeout) {
  563. timeout = cur_timeout;
  564. next_timeout = e->timeout;
  565. }
  566. }
  567. if (e->data.file || e->data.user)
  568. continue;
  569. qosify_map_free_entry(e);
  570. }
  571. if (!timeout)
  572. return;
  573. uloop_timeout_set(&qosify_map_timer, timeout * 1000);
  574. }
  575. int qosify_map_lookup_dns_entry(char *host, bool cname, uint8_t *dscp, uint32_t *seq)
  576. {
  577. struct qosify_map_data data = {
  578. .id = CL_MAP_DNS,
  579. .addr.dns.pattern = "",
  580. };
  581. struct qosify_map_entry *e;
  582. bool ret = -1;
  583. char *c;
  584. e = avl_find_ge_element(&map_data, &data, e, avl);
  585. if (!e)
  586. return -1;
  587. for (c = host; *c; c++)
  588. *c = tolower(*c);
  589. avl_for_element_to_last(&map_data, e, e, avl) {
  590. regex_t *regex = &e->data.addr.dns.regex;
  591. if (e->data.id != CL_MAP_DNS)
  592. break;
  593. if (!cname && e->data.addr.dns.only_cname)
  594. continue;
  595. if (e->data.addr.dns.pattern[0] == '/') {
  596. if (regexec(regex, host, 0, NULL, 0) != 0)
  597. continue;
  598. } else {
  599. if (fnmatch(e->data.addr.dns.pattern, host, 0))
  600. continue;
  601. }
  602. if (*dscp == 0xff || e->data.addr.dns.seq < *seq) {
  603. *dscp = e->data.dscp;
  604. *seq = e->data.addr.dns.seq;
  605. }
  606. ret = 0;
  607. }
  608. return ret;
  609. }
  610. int qosify_map_add_dns_host(char *host, const char *addr, const char *type, int ttl)
  611. {
  612. struct qosify_map_data data = {
  613. .dscp = 0xff
  614. };
  615. int prev_timeout = qosify_map_timeout;
  616. uint32_t lookup_seq = 0;
  617. if (qosify_map_lookup_dns_entry(host, false, &data.dscp, &lookup_seq))
  618. return 0;
  619. data.user = true;
  620. if (!strcmp(type, "A"))
  621. data.id = CL_MAP_IPV4_ADDR;
  622. else if (!strcmp(type, "AAAA"))
  623. data.id = CL_MAP_IPV6_ADDR;
  624. else
  625. return 0;
  626. if (qosify_map_fill_ip(&data, addr))
  627. return -1;
  628. if (ttl)
  629. qosify_map_timeout = ttl;
  630. __qosify_map_set_entry(&data);
  631. qosify_map_timeout = prev_timeout;
  632. return 0;
  633. }
  634. static void
  635. blobmsg_add_dscp(struct blob_buf *b, const char *name, uint8_t dscp)
  636. {
  637. int buf_len = 8;
  638. char *buf;
  639. if (dscp & QOSIFY_DSCP_CLASS_FLAG) {
  640. const char *val;
  641. int idx;
  642. idx = dscp & QOSIFY_DSCP_VALUE_MASK;
  643. if (map_class[idx])
  644. val = map_class[idx]->name;
  645. else
  646. val = "<invalid>";
  647. blobmsg_printf(b, name, "%s%s",
  648. (dscp & QOSIFY_DSCP_FALLBACK_FLAG) ? "+" : "", val);
  649. return;
  650. }
  651. buf = blobmsg_alloc_string_buffer(b, name, buf_len);
  652. qosify_map_dscp_codepoint_str(buf, buf_len, dscp);
  653. blobmsg_add_string_buffer(b);
  654. }
  655. void qosify_map_dump(struct blob_buf *b)
  656. {
  657. struct qosify_map_entry *e;
  658. uint32_t cur_time = qosify_gettime();
  659. int buf_len = INET6_ADDRSTRLEN + 1;
  660. char *buf;
  661. void *a;
  662. int af;
  663. a = blobmsg_open_array(b, "entries");
  664. avl_for_each_element(&map_data, e, avl) {
  665. void *c;
  666. if (!e->data.file && !e->data.user)
  667. continue;
  668. c = blobmsg_open_table(b, NULL);
  669. if (e->data.user && e->timeout != ~0) {
  670. int32_t cur_timeout = e->timeout - cur_time;
  671. if (cur_timeout < 0)
  672. cur_timeout = 0;
  673. blobmsg_add_u32(b, "timeout", cur_timeout);
  674. }
  675. blobmsg_add_u8(b, "file", e->data.file);
  676. blobmsg_add_u8(b, "user", e->data.user);
  677. blobmsg_add_dscp(b, "dscp", e->data.dscp);
  678. blobmsg_add_string(b, "type", qosify_map_info[e->data.id].type_name);
  679. switch (e->data.id) {
  680. case CL_MAP_TCP_PORTS:
  681. case CL_MAP_UDP_PORTS:
  682. blobmsg_printf(b, "addr", "%d", ntohs(e->data.addr.port));
  683. break;
  684. case CL_MAP_IPV4_ADDR:
  685. case CL_MAP_IPV6_ADDR:
  686. buf = blobmsg_alloc_string_buffer(b, "addr", buf_len);
  687. af = e->data.id == CL_MAP_IPV6_ADDR ? AF_INET6 : AF_INET;
  688. inet_ntop(af, &e->data.addr, buf, buf_len);
  689. blobmsg_add_string_buffer(b);
  690. break;
  691. case CL_MAP_DNS:
  692. blobmsg_add_string(b, "addr", e->data.addr.dns.pattern);
  693. break;
  694. default:
  695. break;
  696. }
  697. blobmsg_close_table(b, c);
  698. }
  699. blobmsg_close_array(b, a);
  700. }
  701. void qosify_map_stats(struct blob_buf *b, bool reset)
  702. {
  703. struct qosify_class data;
  704. uint32_t i;
  705. for (i = 0; i < ARRAY_SIZE(map_class); i++) {
  706. void *c;
  707. if (!map_class[i])
  708. continue;
  709. if (bpf_map_lookup_elem(qosify_map_fds[CL_MAP_CLASS], &i, &data) < 0)
  710. continue;
  711. c = blobmsg_open_table(b, map_class[i]->name);
  712. blobmsg_add_u64(b, "packets", data.packets);
  713. blobmsg_close_table(b, c);
  714. if (!reset)
  715. continue;
  716. data.packets = 0;
  717. bpf_map_update_elem(qosify_map_fds[CL_MAP_CLASS], &i, &data, BPF_ANY);
  718. }
  719. }
  720. static int32_t
  721. qosify_map_get_class_id(const char *name)
  722. {
  723. int i;
  724. for (i = 0; i < ARRAY_SIZE(map_class); i++)
  725. if (map_class[i] && !strcmp(map_class[i]->name, name))
  726. return i;
  727. for (i = 0; i < ARRAY_SIZE(map_class); i++)
  728. if (!map_class[i])
  729. return i;
  730. for (i = 0; i < ARRAY_SIZE(map_class); i++) {
  731. if (!(map_class[i]->data.flags & QOSIFY_CLASS_FLAG_PRESENT)) {
  732. free(map_class[i]);
  733. map_class[i] = NULL;
  734. return i;
  735. }
  736. }
  737. return -1;
  738. }
  739. int map_fill_dscp_value(uint8_t *dest, struct blob_attr *attr, bool reset)
  740. {
  741. if (reset)
  742. *dest = 0xff;
  743. if (!attr)
  744. return 0;
  745. if (qosify_map_dscp_value(blobmsg_get_string(attr), dest))
  746. return -1;
  747. return 0;
  748. }
  749. int map_parse_flow_config(struct qosify_flow_config *cfg, struct blob_attr *attr,
  750. bool reset)
  751. {
  752. enum {
  753. CL_CONFIG_DSCP_PRIO,
  754. CL_CONFIG_DSCP_BULK,
  755. CL_CONFIG_BULK_TIMEOUT,
  756. CL_CONFIG_BULK_PPS,
  757. CL_CONFIG_PRIO_PKT_LEN,
  758. __CL_CONFIG_MAX
  759. };
  760. static const struct blobmsg_policy policy[__CL_CONFIG_MAX] = {
  761. [CL_CONFIG_DSCP_PRIO] = { "dscp_prio", BLOBMSG_TYPE_STRING },
  762. [CL_CONFIG_DSCP_BULK] = { "dscp_bulk", BLOBMSG_TYPE_STRING },
  763. [CL_CONFIG_BULK_TIMEOUT] = { "bulk_trigger_timeout", BLOBMSG_TYPE_INT32 },
  764. [CL_CONFIG_BULK_PPS] = { "bulk_trigger_pps", BLOBMSG_TYPE_INT32 },
  765. [CL_CONFIG_PRIO_PKT_LEN] = { "prio_max_avg_pkt_len", BLOBMSG_TYPE_INT32 },
  766. };
  767. struct blob_attr *tb[__CL_CONFIG_MAX];
  768. struct blob_attr *cur;
  769. if (reset)
  770. memset(cfg, 0, sizeof(*cfg));
  771. blobmsg_parse(policy, __CL_CONFIG_MAX, tb, blobmsg_data(attr), blobmsg_len(attr));
  772. if (map_fill_dscp_value(&cfg->dscp_prio, tb[CL_CONFIG_DSCP_PRIO], reset) ||
  773. map_fill_dscp_value(&cfg->dscp_bulk, tb[CL_CONFIG_DSCP_BULK], reset))
  774. return -1;
  775. if ((cur = tb[CL_CONFIG_BULK_TIMEOUT]) != NULL)
  776. cfg->bulk_trigger_timeout = blobmsg_get_u32(cur);
  777. if ((cur = tb[CL_CONFIG_BULK_PPS]) != NULL)
  778. cfg->bulk_trigger_pps = blobmsg_get_u32(cur);
  779. if ((cur = tb[CL_CONFIG_PRIO_PKT_LEN]) != NULL)
  780. cfg->prio_max_avg_pkt_len = blobmsg_get_u32(cur);
  781. return 0;
  782. }
  783. static int
  784. qosify_map_create_class(struct blob_attr *attr)
  785. {
  786. struct qosify_map_class *class;
  787. enum {
  788. MAP_CLASS_INGRESS,
  789. MAP_CLASS_EGRESS,
  790. __MAP_CLASS_MAX
  791. };
  792. static const struct blobmsg_policy policy[__MAP_CLASS_MAX] = {
  793. [MAP_CLASS_INGRESS] = { "ingress", BLOBMSG_TYPE_STRING },
  794. [MAP_CLASS_EGRESS] = { "egress", BLOBMSG_TYPE_STRING },
  795. };
  796. struct blob_attr *tb[__MAP_CLASS_MAX];
  797. const char *name;
  798. char *name_buf;
  799. int32_t slot;
  800. blobmsg_parse(policy, __MAP_CLASS_MAX, tb,
  801. blobmsg_data(attr), blobmsg_len(attr));
  802. if (!tb[MAP_CLASS_INGRESS] || !tb[MAP_CLASS_EGRESS])
  803. return -1;
  804. name = blobmsg_name(attr);
  805. slot = qosify_map_get_class_id(name);
  806. if (slot < 0)
  807. return -1;
  808. class = map_class[slot];
  809. if (!class) {
  810. class = calloc_a(sizeof(*class), &name_buf, strlen(name) + 1);
  811. class->name = strcpy(name_buf, name);
  812. map_class[slot] = class;
  813. }
  814. class->data.flags |= QOSIFY_CLASS_FLAG_PRESENT;
  815. if (__qosify_map_dscp_value(blobmsg_get_string(tb[MAP_CLASS_INGRESS]),
  816. &class->data.val.ingress) ||
  817. __qosify_map_dscp_value(blobmsg_get_string(tb[MAP_CLASS_EGRESS]),
  818. &class->data.val.egress)) {
  819. map_class[slot] = NULL;
  820. free(class);
  821. return -1;
  822. }
  823. return 0;
  824. }
  825. void qosify_map_set_classes(struct blob_attr *val)
  826. {
  827. int fd = qosify_map_fds[CL_MAP_CLASS];
  828. struct qosify_class empty_data = {};
  829. struct blob_attr *cur;
  830. int32_t i;
  831. int rem;
  832. for (i = 0; i < ARRAY_SIZE(map_class); i++)
  833. if (map_class[i])
  834. map_class[i]->data.flags &= ~QOSIFY_CLASS_FLAG_PRESENT;
  835. blobmsg_for_each_attr(cur, val, rem)
  836. qosify_map_create_class(cur);
  837. for (i = 0; i < ARRAY_SIZE(map_class); i++) {
  838. if (map_class[i] &&
  839. (map_class[i]->data.flags & QOSIFY_CLASS_FLAG_PRESENT))
  840. continue;
  841. free(map_class[i]);
  842. map_class[i] = NULL;
  843. }
  844. blobmsg_for_each_attr(cur, val, rem) {
  845. i = qosify_map_get_class_id(blobmsg_name(cur));
  846. if (i < 0 || !map_class[i])
  847. continue;
  848. map_parse_flow_config(&map_class[i]->data.config, cur, true);
  849. }
  850. for (i = 0; i < ARRAY_SIZE(map_class); i++) {
  851. struct qosify_class *data;
  852. data = map_class[i] ? &map_class[i]->data : &empty_data;
  853. bpf_map_update_elem(fd, &i, data, BPF_ANY);
  854. }
  855. }
  856. void qosify_map_update_config(void)
  857. {
  858. int fd = qosify_map_fds[CL_MAP_CONFIG];
  859. uint32_t key = 0;
  860. bpf_map_update_elem(fd, &key, &config, BPF_ANY);
  861. }