summaryrefslogtreecommitdiff
path: root/tc
Commit message (Collapse)AuthorAgeFilesLines
* tc/prio: handle possible truncated kernel responseStephen Hemminger2023-05-131-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Reported by -fanalyzer. If kernel did not send full qdisc info, then uninitialized or null data could be referenced. q_prio.c: In function ‘prio_print_opt’: q_prio.c:105:57: warning: dereference of NULL ‘0’ [CWE-476] [-Wanalyzer-null-dereference] 105 | print_uint(PRINT_ANY, "bands", "bands %u ", qopt->bands); | ~~~~^~~~~~~ ‘prio_print_opt’: event 1 | | 98 | if (opt == NULL) | | ^ | | | | | (1) following ‘false’ branch (when ‘opt’ is non-NULL)... | ‘prio_print_opt’: event 2 | |../include/uapi/linux/rtnetlink.h:228:38: | 228 | #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) | | ~~~~~~^~~~~~~~~~ | | | | | (2) ...to here ../include/libnetlink.h:236:19: note: in expansion of macro ‘RTA_PAYLOAD’ | 236 | ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ | | ^~~~~~~~~~~ q_prio.c:101:13: note: in expansion of macro ‘parse_rtattr_nested_compat’ | 101 | if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~ | ‘prio_print_opt’: event 3 | |../include/libnetlink.h:236:59: | 236 | ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ q_prio.c:101:13: note: in expansion of macro ‘parse_rtattr_nested_compat’ | 101 | if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~ | ‘prio_print_opt’: events 4-5 | | 105 | print_uint(PRINT_ANY, "bands", "bands %u ", qopt->bands); | | ~~~~^~~~~~~ | | | | | (4) ...to here | | (5) dereference of NULL ‘<unknown>’ | Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* netem: fix NULL deref on allocation failureStephen Hemminger2023-05-131-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | q_netem.c: In function ‘get_distribution’: q_netem.c:159:35: warning: dereference of possibly-NULL ‘data’ [CWE-690] [-Wanalyzer-possible-null-dereference] 159 | data[n++] = x; | ~~~~~~~~~~^~~ ‘netem_parse_opt’: events 1-24 | | 192 | static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, | | ^~~~~~~~~~~~~~~ | | | | | (1) entry to ‘netem_parse_opt’ |...... | 212 | for ( ; argc > 0; --argc, ++argv) { | | ~~~~~~~~ | | | | | (2) following ‘true’ branch (when ‘argc > 0’)... | 213 | if (matches(*argv, "limit") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(3) ...to here | | (4) following ‘true’ branch... |...... | 219 | } else if (matches(*argv, "latency") == 0 || | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | || | | | |(5) ...to here (8) following ‘true’ branch... | | (6) following ‘true’ branch... | 220 | matches(*argv, "delay") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (7) ...to here |...... | 243 | } else if (matches(*argv, "loss") == 0 || | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | || | | | |(9) ...to here (12) following ‘true’ branch... | | (10) following ‘true’ branch... | 244 | matches(*argv, "drop") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (11) ...to here |...... | 366 | } else if (matches(*argv, "ecn") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(13) ...to here | | (14) following ‘true’ branch... | 367 | present[TCA_NETEM_ECN] = 1; | 368 | } else if (matches(*argv, "reorder") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(15) ...to here | | (16) following ‘true’ branch... |...... | 383 | } else if (matches(*argv, "corrupt") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(17) ...to here | | (18) following ‘true’ branch... |...... | 398 | } else if (matches(*argv, "gap") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(19) ...to here | | (20) following ‘true’ branch... |...... | 404 | } else if (matches(*argv, "duplicate") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(21) ...to here | | (22) following ‘true’ branch... |...... | 417 | } else if (matches(*argv, "distribution") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(23) ...to here | | (24) following ‘false’ branch... | ‘netem_parse_opt’: event 25 | |../include/utils.h:50:29: | 50 | #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0) | | ~~~~^~ | | | | | (25) ...to here q_netem.c:418:25: note: in expansion of macro ‘NEXT_ARG’ | 418 | NEXT_ARG(); | | ^~~~~~~~ | ‘netem_parse_opt’: event 26 | |../include/utils.h:50:36: | 50 | #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0) | | ^ | | | | | (26) following ‘false’ branch (when ‘argc != 0’)... q_netem.c:418:25: note: in expansion of macro ‘NEXT_ARG’ | 418 | NEXT_ARG(); | | ^~~~~~~~ | ‘netem_parse_opt’: events 27-29 | | 419 | dist_data = calloc(sizeof(dist_data[0]), MAX_DIST); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (27) ...to here | | (28) this call could return NULL | 420 | dist_size = get_distribution(*argv, dist_data, MAX_DIST); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (29) calling ‘get_distribution’ from ‘netem_parse_opt’ | +--> ‘get_distribution’: events 30-31 | | 124 | static int get_distribution(const char *type, __s16 *data, int maxdata) | | ^~~~~~~~~~~~~~~~ | | | | | (30) entry to ‘get_distribution’ |...... | 135 | if (f == NULL) { | | ~ | | | | | (31) following ‘false’ branch (when ‘f’ is non-NULL)... | ‘get_distribution’: event 32 | |cc1: | (32): ...to here | ‘get_distribution’: events 33-35 | | 142 | while (getline(&line, &len, f) != -1) { | | ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ | | | | | (33) following ‘true’ branch... |...... | 145 | if (*line == '\n' || *line == '#') | | ~~~~~~ | | || | | |(34) ...to here | | (35) following ‘false’ branch... | ‘get_distribution’: event 36 | |cc1: | (36): ...to here | ‘get_distribution’: events 37-41 | | 150 | if (endp == p) | | ^ | | | | | (37) following ‘false’ branch... |...... | 153 | if (n >= maxdata) { | | ~ | | | | | (38) ...to here | | (39) following ‘false’ branch (when ‘n < maxdata’)... |...... | 159 | data[n++] = x; | | ~~~~~~~~~~~~~ | | | | | | | (41) ‘data + (long unsigned int)n * 2’ could be NULL: unchecked value from (28) | | (40) ...to here | Fixes: c1b81cb5fe92 ("netem potential dist table overflow") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* m_action: fix warning of overwrite of const stringStephen Hemminger2023-05-131-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The function get_action_kind() searches first for the given action, then rescans on failure for "gact". In the process, it would overwrite the argument. Avoid the warning by using a const argument and not copying. The problem dates back to pre-git history. m_action.c: In function ‘get_action_kind’: m_action.c:126:17: warning: write to string literal [-Wanalyzer-write-to-string-literal] 126 | strcpy(str, "gact"); | ^~~~~~~~~~~~~~~~~~~ ‘do_action’: events 1-6 | | 853 | int do_action(int argc, char **argv) | | ^~~~~~~~~ | | | | | (1) entry to ‘do_action’ |...... | 858 | while (argc > 0) { | | ~~~~~~~~ | | | | | (2) following ‘true’ branch... | 859 | | 860 | if (matches(*argv, "add") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(3) ...to here | | (4) following ‘false’ branch... | 861 | ret = tc_action_modify(RTM_NEWACTION, | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | | (6) calling ‘tc_action_modify’ from ‘do_action’ | 862 | NLM_F_EXCL | NLM_F_CREATE, | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 863 | &argc, &argv); | | ~~~~~~~~~~~~~ | +--> ‘tc_action_modify’: events 7-8 | | 715 | static int tc_action_modify(int cmd, unsigned int flags, | | ^~~~~~~~~~~~~~~~ | | | | | (7) entry to ‘tc_action_modify’ |...... | 735 | if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (8) calling ‘parse_action’ from ‘tc_action_modify’ | +--> ‘parse_action’: events 9-18 | | 203 | int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) | | ^~~~~~~~~~~~ | | | | | (9) entry to ‘parse_action’ |...... | 217 | if (argc <= 0) | | ~ | | | | | (10) following ‘false’ branch... |...... | 220 | tail2 = addattr_nest(n, MAX_MSG, tca_id); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (11) ...to here | 221 | | 222 | while (argc > 0) { | | ~~~~~~~~ | | | | | (12) following ‘true’ branch... | 223 | | 224 | memset(k, 0, sizeof(k)); | | ~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (13) ...to here | 225 | | 226 | if (strcmp(*argv, "action") == 0) { | | ~ | | | | | (14) following ‘true’ branch (when the strings are equal)... | 227 | argc--; | | ~~~~~~ | | | | | (15) ...to here |...... | 231 | if (!gact_ld) | | ~ | | | | | (16) following ‘true’ branch... | 232 | get_action_kind("gact"); | | ~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (17) ...to here | | (18) calling ‘get_action_kind’ from ‘parse_action’ | +--> ‘get_action_kind’: events 19-24 | | 86 | static struct action_util *get_action_kind(char *str) | | ^~~~~~~~~~~~~~~ | | | | | (19) entry to ‘get_action_kind’ |...... | 114 | if (a == NULL) | | ~ | | | | | (20) following ‘true’ branch (when ‘a’ is NULL)... | 115 | goto noexist; | | ~~~~ | | | | | (21) ...to here |...... | 124 | if (!looked4gact) { | | ~ | | | | | (22) following ‘true’ branch (when ‘looked4gact == 0’)... | 125 | looked4gact = 1; | 126 | strcpy(str, "gact"); | | ~~~~~~~~~~~~~~~~~~~ | | | | | (23) ...to here | | (24) write to string literal here | Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc_exec: don't dereference NULL on calloc failureStephen Hemminger2023-05-131-0/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Reported as: tc_exec.c: In function ‘do_exec’: tc_exec.c:103:18: warning: dereference of NULL ‘eu’ [CWE-476] [-Wanalyzer-null-dereference] 103 | return eu->parse_eopt(eu, argc, argv); | ~~^~~~~~~~~~~~ ‘do_exec’: events 1-6 | | 81 | int do_exec(int argc, char **argv) | | ^~~~~~~ | | | | | (1) entry to ‘do_exec’ |...... | 86 | if (argc < 1) { | | ~ | | | | | (2) following ‘false’ branch (when ‘argc > 0’)... |...... | 91 | if (matches(*argv, "help") == 0) { | | ~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(3) ...to here | | (4) following ‘true’ branch... |...... | 96 | strncpy(kind, *argv, sizeof(kind) - 1); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | 97 | | 98 | eu = get_exec_kind(kind); | | ~~~~~~~~~~~~~~~~~~~ | | | | | (6) calling ‘get_exec_kind’ from ‘do_exec’ | +--> ‘get_exec_kind’: events 7-10 | | 40 | static struct exec_util *get_exec_kind(const char *name) | | ^~~~~~~~~~~~~ | | | | | (7) entry to ‘get_exec_kind’ |...... | 63 | if (eu == NULL) | | ~ | | | | | (8) following ‘true’ branch (when ‘eu’ is NULL)... | 64 | goto noexist; | | ~~~~ | | | | | (9) ...to here |...... | 72 | if (eu) { | | ~ | | | | | (10) following ‘false’ branch (when ‘eu’ is NULL)... | ‘get_exec_kind’: event 11 | |cc1: | (11): ...to here | <------+ | ‘do_exec’: events 12-13 | | 98 | eu = get_exec_kind(kind); | | ^~~~~~~~~~~~~~~~~~~ | | | | | (12) return of NULL to ‘do_exec’ from ‘get_exec_kind’ |...... | 103 | return eu->parse_eopt(eu, argc, argv); | | ~~~~~~~~~~~~~~ | | | | | (13) dereference of NULL ‘eu’ | Fixes: 4bd624467bc6 ("tc: built-in eBPF exec proxy") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc_util fix unitialized warningStephen Hemminger2023-05-131-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | tc_util.c: In function ‘parse_action_control_slash_spaces’: tc_util.c:488:28: warning: use of uninitialized value ‘result2’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value] 488 | *result2_p = result2; | ~~~~~~~~~~~^~~~~~~~~ ‘parse_action_control_slash_spaces’: events 1-5 | | 455 | static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (1) entry to ‘parse_action_control_slash_spaces’ |...... | 461 | int result1 = -1, result2; | | ~~~~~~~ | | | | | (2) region created on stack here | | (3) capacity: 4 bytes |...... | 467 | switch (ok) { | | ~~~~~~ | | | | | (4) following ‘case 0:’ branch... |...... | 475 | ret = parse_action_control(&argc, &argv, | | ~ | | | | | (5) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’ | +--> ‘parse_action_control’: events 6-7 | | 432 | return __parse_action_control(argc_p, argv_p, result_p, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) ...to here | | (7) calling ‘__parse_action_control’ from ‘parse_action_control_slash_spaces’ | 433 | allow_num, false); | | ~~~~~~~~~~~~~~~~~ | ‘__parse_action_control’: events 8-11 | | 371 | static int __parse_action_control(int *argc_p, char ***argv_p, int *result_p, | | ^~~~~~~~~~~~~~~~~~~~~~ | | | | | (8) entry to ‘__parse_action_control’ |...... | 378 | if (!argc) | | ~ | | | | | (9) following ‘false’ branch (when ‘argc != 0’)... | 379 | return -1; | 380 | if (action_a2n(*argv, &result, allow_num) == -1) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (10) ...to here | | (11) calling ‘action_a2n’ from ‘__parse_action_control’ | +--> ‘action_a2n’: events 12-16 | | 335 | int action_a2n(char *arg, int *result, bool allow_num) | | ^~~~~~~~~~ | | | | | (12) entry to ‘action_a2n’ |...... | 356 | for (iter = a2n; iter->a; iter++) { | | ~~~~ | | | | | (13) following ‘true’ branch... | 357 | if (matches(arg, iter->a) != 0) | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (14) ...to here |...... | 366 | if (result) | | ~ | | | | | (15) following ‘true’ branch (when ‘result’ is non-NULL)... | 367 | *result = n; | | ~~~~~~~~~~~ | | | | | (16) ...to here | <------+ | ‘__parse_action_control’: event 17 | | 380 | if (action_a2n(*argv, &result, allow_num) == -1) { | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (17) returning to ‘__parse_action_control’ from ‘action_a2n’ | <------+ | ‘parse_action_control_slash_spaces’: event 18 | | 475 | ret = parse_action_control(&argc, &argv, | | ^ | | | | | (18) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’ | +--> ‘parse_action_control’: event 19 | | 432 | return __parse_action_control(argc_p, argv_p, result_p, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (19) returning to ‘parse_action_control_slash_spaces’ from ‘__parse_action_control’ | 433 | allow_num, false); | | ~~~~~~~~~~~~~~~~~ | <------+ | ‘parse_action_control_slash_spaces’: events 20-24 | | 477 | if (ret) | | ^ | | | | | (20) following ‘false’ branch... | 478 | return ret; | 479 | ok++; | | ~~~~ | | | | | (21) ...to here |...... | 487 | if (ok == 2) | | ~ | | | | | (22) following ‘true’ branch (when ‘ok == 2’)... | 488 | *result2_p = result2; | | ~~~~~~~~~~~~~~~~~~~~ | | | | | (23) ...to here | | (24) use of uninitialized value ‘result2’ here | tc_util.c:488:28: warning: use of uninitialized value ‘result2’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value] 488 | *result2_p = result2; | ~~~~~~~~~~~^~~~~~~~~ ‘parse_action_control_slash’: events 1-5 | | 505 | int parse_action_control_slash(int *argc_p, char ***argv_p, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (1) entry to ‘parse_action_control_slash’ |...... | 510 | char *p = strchr(*argv, '/'); | | ~~~~~~~~~~~~~~~~~~ | | | | | (2) when ‘strchr’ returns NULL | 511 | | 512 | if (!p) | | ~ | | | | | (3) following ‘true’ branch (when ‘p’ is NULL)... | 513 | return parse_action_control_slash_spaces(argc_p, argv_p, | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (4) ...to here | | (5) calling ‘parse_action_control_slash_spaces’ from ‘parse_action_control_slash’ | 514 | result1_p, result2_p, | | ~~~~~~~~~~~~~~~~~~~~~ | 515 | allow_num); | | ~~~~~~~~~~ | +--> ‘parse_action_control_slash_spaces’: events 6-10 | | 455 | static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) entry to ‘parse_action_control_slash_spaces’ |...... | 461 | int result1 = -1, result2; | | ~~~~~~~ | | | | | (7) region created on stack here | | (8) capacity: 4 bytes |...... | 467 | switch (ok) { | | ~~~~~~ | | | | | (9) following ‘case 0:’ branch... |...... | 475 | ret = parse_action_control(&argc, &argv, | | ~ | | | | | (10) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’ | +--> ‘parse_action_control’: events 11-12 | | 432 | return __parse_action_control(argc_p, argv_p, result_p, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (11) ...to here | | (12) calling ‘__parse_action_control’ from ‘parse_action_control_slash_spaces’ | 433 | allow_num, false); | | ~~~~~~~~~~~~~~~~~ | ‘__parse_action_control’: events 13-16 | | 371 | static int __parse_action_control(int *argc_p, char ***argv_p, int *result_p, | | ^~~~~~~~~~~~~~~~~~~~~~ | | | | | (13) entry to ‘__parse_action_control’ |...... | 378 | if (!argc) | | ~ | | | | | (14) following ‘false’ branch (when ‘argc != 0’)... | 379 | return -1; | 380 | if (action_a2n(*argv, &result, allow_num) == -1) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (15) ...to here | | (16) calling ‘action_a2n’ from ‘__parse_action_control’ | +--> ‘action_a2n’: events 17-21 | | 335 | int action_a2n(char *arg, int *result, bool allow_num) | | ^~~~~~~~~~ | | | | | (17) entry to ‘action_a2n’ |...... | 356 | for (iter = a2n; iter->a; iter++) { | | ~~~~ | | | | | (18) following ‘true’ branch... | 357 | if (matches(arg, iter->a) != 0) | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (19) ...to here |...... | 366 | if (result) | | ~ | | | | | (20) following ‘true’ branch (when ‘result’ is non-NULL)... | 367 | *result = n; | | ~~~~~~~~~~~ | | | | | (21) ...to here | <------+ | ‘__parse_action_control’: event 22 | | 380 | if (action_a2n(*argv, &result, allow_num) == -1) { | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (22) returning to ‘__parse_action_control’ from ‘action_a2n’ | <------+ | ‘parse_action_control_slash_spaces’: event 23 | | 475 | ret = parse_action_control(&argc, &argv, | | ^ | | | | | (23) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’ | +--> ‘parse_action_control’: event 24 | | 432 | return __parse_action_control(argc_p, argv_p, result_p, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (24) returning to ‘parse_action_control_slash_spaces’ from ‘__parse_action_control’ | 433 | allow_num, false); | | ~~~~~~~~~~~~~~~~~ | <------+ | ‘parse_action_control_slash_spaces’: events 25-29 | | 477 | if (ret) | | ^ | | | | | (25) following ‘false’ branch... | 478 | return ret; | 479 | ok++; | | ~~~~ | | | | | (26) ...to here |...... | 487 | if (ok == 2) | | ~ | | | | | (27) following ‘true’ branch (when ‘ok == 2’)... | 488 | *result2_p = result2; | | ~~~~~~~~~~~~~~~~~~~~ | | | | | (28) ...to here | | (29) use of uninitialized value ‘result2’ here | Fixes: e67aba559581 ("tc: actions: add helpers to parse and print control actions") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc_filter: fix unitialized warningStephen Hemminger2023-05-131-3/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When run with -fanalyzer. tc_filter.c: In function ‘tc_filter_list’: tc_filter.c:718:17: warning: use of uninitialized value ‘chain_index’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value] 718 | addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ‘do_chain’: events 1-4 | | 772 | int do_chain(int argc, char **argv) | | ^~~~~~~~ | | | | | (1) entry to ‘do_chain’ | 773 | { | 774 | if (argc < 1) | | ~ | | | | | (2) following ‘true’ branch (when ‘argc <= 0’)... | 775 | return tc_filter_list(RTM_GETCHAIN, 0, NULL); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (3) ...to here | | (4) calling ‘tc_filter_list’ from ‘do_chain’ | +--> ‘tc_filter_list’: events 5-8 | | 582 | static int tc_filter_list(int cmd, int argc, char **argv) | | ^~~~~~~~~~~~~~ | | | | | (5) entry to ‘tc_filter_list’ |...... | 597 | __u32 chain_index; | | ~~~~~~~~~~~ | | | | | (6) region created on stack here | | (7) capacity: 4 bytes |...... | 601 | while (argc > 0) { | | ~~~~~~~~ | | | | | (8) following ‘false’ branch (when ‘argc <= 0’)... | ‘tc_filter_list’: event 9 | |../include/uapi/linux/pkt_sched.h:72:35: | 72 | #define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK)) | | ~~~~~~^~~~~~~~~~~~~~~ | | | | | (9) ...to here tc_filter.c:698:26: note: in expansion of macro ‘TC_H_MAKE’ | 698 | req.t.tcm_info = TC_H_MAKE(prio<<16, protocol); | | ^~~~~~~~~ | ‘tc_filter_list’: events 10-16 | | 702 | if (d[0]) { | | ^ | | | | | (10) following ‘false’ branch... |...... | 707 | } else if (block_index) { | | ~~~~~~~~~~~~ | | || | | |(11) ...to here | | (12) following ‘false’ branch... |...... | 717 | if (filter_chain_index_set) | | ~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(13) ...to here | | (14) following ‘true’ branch... | 718 | addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (15) ...to here | | (16) use of uninitialized value ‘chain_index’ here | tc_filter.c:718:17: warning: use of uninitialized value ‘chain_index’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value] 718 | addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ‘do_filter’: events 1-4 | | 744 | int do_filter(int argc, char **argv) | | ^~~~~~~~~ | | | | | (1) entry to ‘do_filter’ | 745 | { | 746 | if (argc < 1) | | ~ | | | | | (2) following ‘true’ branch (when ‘argc <= 0’)... | 747 | return tc_filter_list(RTM_GETTFILTER, 0, NULL); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (3) ...to here | | (4) calling ‘tc_filter_list’ from ‘do_filter’ | +--> ‘tc_filter_list’: events 5-8 | | 582 | static int tc_filter_list(int cmd, int argc, char **argv) | | ^~~~~~~~~~~~~~ | | | | | (5) entry to ‘tc_filter_list’ |...... | 597 | __u32 chain_index; | | ~~~~~~~~~~~ | | | | | (6) region created on stack here | | (7) capacity: 4 bytes |...... | 601 | while (argc > 0) { | | ~~~~~~~~ | | | | | (8) following ‘false’ branch (when ‘argc <= 0’)... | ‘tc_filter_list’: event 9 | |../include/uapi/linux/pkt_sched.h:72:35: | 72 | #define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK)) | | ~~~~~~^~~~~~~~~~~~~~~ | | | | | (9) ...to here tc_filter.c:698:26: note: in expansion of macro ‘TC_H_MAKE’ | 698 | req.t.tcm_info = TC_H_MAKE(prio<<16, protocol); | | ^~~~~~~~~ | ‘tc_filter_list’: events 10-16 | | 702 | if (d[0]) { | | ^ | | | | | (10) following ‘false’ branch... |...... | 707 | } else if (block_index) { | | ~~~~~~~~~~~~ | | || | | |(11) ...to here | | (12) following ‘false’ branch... |...... | 717 | if (filter_chain_index_set) | | ~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(13) ...to here | | (14) following ‘true’ branch... | 718 | addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (15) ...to here | | (16) use of uninitialized value ‘chain_index’ here | Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* iproute2: optimize code and fix some mem-leak riskzhaoshuang2023-05-113-0/+3
| | | | | | Signed-off-by: zhaoshuang <izhaoshuang@163.com> Reviewed-by: Pawel Chmielewski <pawel.chmielewski@intel.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* remove unnecessary checks for NULL before calling free()Stephen Hemminger2023-05-104-8/+4
| | | | | | | | | The function free() handles the case wher argument is NULL by doing nothing. So the extra checks are not needed. Found by modified version of kernel coccinelle script. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc/taprio: add support for preemptible traffic classesVladimir Oltean2023-04-241-24/+76
| | | | | | | | | | Add support for the same kind of "fp" array argument as in mqprio, except here we already have some handling for per-tc entries (max-sdu). We just need to expand that logic such that we also add (and parse) the FP adminStatus property of each traffic class. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David Ahern <dsahern@kernel.org>
* tc/mqprio: add support for preemptible traffic classesVladimir Oltean2023-04-241-0/+99
| | | | | | | | | | | Add support for the "fp" argument in tc-mqprio, which takes an array of letters "E" (for express) or "P" (for preemptible), one per traffic class, and transforms them into TCA_MQPRIO_TC_ENTRY_FP u32 attributes of the TCA_MQPRIO_TC_ENTRY nest. We also dump these new netlink attributes when they come from the kernel. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David Ahern <dsahern@kernel.org>
* Merge remote-tracking branch 'main/main' into nextDavid Ahern2023-04-241-4/+4
|\ | | | | | | Signed-off-by: David Ahern <dsahern@kernel.org>
| * tc/taprio: break up help text into multiple linesVladimir Oltean2023-04-241-4/+4
| | | | | | | | | | | | | | | | | | | | Currently, the output of "tc qdisc add dev lo taprio help" looks absolutely horrible, it looks better in the source code. Put new lines in the output everywhere where the text switches to a new line in the source code. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* | Merge branch 'main' into nextDavid Ahern2023-04-227-20/+32
|\ \ | |/ | | | | Signed-off-by: David Ahern <dsahern@kernel.org>
| * whitespace cleanupStephen Hemminger2023-04-211-1/+1
| | | | | | | | | | | | Remove trailing blanks. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: m_action: fix parsing of TCA_EXT_WARN_MSG by using different enumHangbin Liu2023-03-181-1/+7
| | | | | | | | | | | | | | | | | | | | | | | | We can't use TCA_EXT_WARN_MSG directly in tc action as it's using different enum with filter. Let's use a new TCA_ROOT_EXT_WARN_MSG for tc action specifically. Fixes: 6035995665b7 ("tc: add new attr TCA_EXT_WARN_MSG") Reviewed-by: Andrea Claudi <aclaudi@redhat.com> Reported-and-tested-by: Davide Caratti <dcaratti@redhat.com> Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * Revert "tc: m_action: fix parsing of TCA_EXT_WARN_MSG"Hangbin Liu2023-03-181-1/+1
| | | | | | | | | | | | | | | | | | | | | | This reverts commit 70b9ebae63ce7e6f9911bdfbcf47a6d18f24159a. The TCA_EXT_WARN_MSG is not sit within the TCA_ACT_TAB hierarchy. It's belong to the TCA_MAX namespace. I will fix the issue in another patch. Reviewed-by: Andrea Claudi <aclaudi@redhat.com> Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: m_nat: parse index argument correctlyPedro Tammela2023-03-051-1/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 'action nat index 1' is a valid cli according to TC's architecture. Fix the grammar parsing to accept it. tdc tests: 1..28 ok 1 7565 - Add nat action on ingress with default control action ok 2 fd79 - Add nat action on ingress with pipe control action ok 3 eab9 - Add nat action on ingress with continue control action ok 4 c53a - Add nat action on ingress with reclassify control action ok 5 76c9 - Add nat action on ingress with jump control action ok 6 24c6 - Add nat action on ingress with drop control action ok 7 2120 - Add nat action on ingress with maximum index value ok 8 3e9d - Add nat action on ingress with invalid index value ok 9 f6c9 - Add nat action on ingress with invalid IP address ok 10 be25 - Add nat action on ingress with invalid argument ok 11 a7bd - Add nat action on ingress with DEFAULT IP address ok 12 ee1e - Add nat action on ingress with ANY IP address ok 13 1de8 - Add nat action on ingress with ALL IP address ok 14 8dba - Add nat action on egress with default control action ok 15 19a7 - Add nat action on egress with pipe control action ok 16 f1d9 - Add nat action on egress with continue control action ok 17 6d4a - Add nat action on egress with reclassify control action ok 18 b313 - Add nat action on egress with jump control action ok 19 d9fc - Add nat action on egress with drop control action ok 20 a895 - Add nat action on egress with DEFAULT IP address ok 21 2572 - Add nat action on egress with ANY IP address ok 22 37f3 - Add nat action on egress with ALL IP address ok 23 6054 - Add nat action on egress with cookie ok 24 79d6 - Add nat action on ingress with cookie ok 25 4b12 - Replace nat action with invalid goto chain control ok 26 b811 - Delete nat action with valid index ok 27 a521 - Delete nat action with invalid index ok 28 2c81 - Reference nat action object in filter Fixes: fc2d02069b52 ("Add NAT action") Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Pedro Tammela <pctammela@mojatatu.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: m_mpls: parse index argument correctlyPedro Tammela2023-03-051-0/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 'action mpls index 1' is a valid cli according to TC's architecture. Fix the grammar parsing to accept it. tdc tests: 1..54 ok 1 a933 - Add MPLS dec_ttl action with pipe opcode ok 2 08d1 - Add mpls dec_ttl action with pass opcode ok 3 d786 - Add mpls dec_ttl action with drop opcode ok 4 f334 - Add mpls dec_ttl action with reclassify opcode ok 5 29bd - Add mpls dec_ttl action with continue opcode ok 6 48df - Add mpls dec_ttl action with jump opcode ok 7 62eb - Add mpls dec_ttl action with trap opcode ok 8 09d2 - Add mpls dec_ttl action with opcode and cookie ok 9 c170 - Add mpls dec_ttl action with opcode and cookie of max length ok 10 9118 - Add mpls dec_ttl action with invalid opcode ok 11 6ce1 - Add mpls dec_ttl action with label (invalid) ok 12 352f - Add mpls dec_ttl action with tc (invalid) ok 13 fa1c - Add mpls dec_ttl action with ttl (invalid) ok 14 6b79 - Add mpls dec_ttl action with bos (invalid) ok 15 d4c4 - Add mpls pop action with ip proto ok 16 91fb - Add mpls pop action with ip proto and cookie ok 17 92fe - Add mpls pop action with mpls proto ok 18 7e23 - Add mpls pop action with no protocol (invalid) ok 19 6182 - Add mpls pop action with label (invalid) ok 20 6475 - Add mpls pop action with tc (invalid) ok 21 067b - Add mpls pop action with ttl (invalid) ok 22 7316 - Add mpls pop action with bos (invalid) ok 23 38cc - Add mpls push action with label ok 24 c281 - Add mpls push action with mpls_mc protocol ok 25 5db4 - Add mpls push action with label, tc and ttl ok 26 7c34 - Add mpls push action with label, tc ttl and cookie of max length ok 27 16eb - Add mpls push action with label and bos ok 28 d69d - Add mpls push action with no label (invalid) ok 29 e8e4 - Add mpls push action with ipv4 protocol (invalid) ok 30 ecd0 - Add mpls push action with out of range label (invalid) ok 31 d303 - Add mpls push action with out of range tc (invalid) ok 32 fd6e - Add mpls push action with ttl of 0 (invalid) ok 33 19e9 - Add mpls mod action with mpls label ok 34 1fde - Add mpls mod action with max mpls label ok 35 0c50 - Add mpls mod action with mpls label exceeding max (invalid) ok 36 10b6 - Add mpls mod action with mpls label of MPLS_LABEL_IMPLNULL (invalid) ok 37 57c9 - Add mpls mod action with mpls min tc ok 38 6872 - Add mpls mod action with mpls max tc ok 39 a70a - Add mpls mod action with mpls tc exceeding max (invalid) ok 40 6ed5 - Add mpls mod action with mpls ttl ok 41 77c1 - Add mpls mod action with mpls ttl and cookie ok 42 b80f - Add mpls mod action with mpls max ttl ok 43 8864 - Add mpls mod action with mpls min ttl ok 44 6c06 - Add mpls mod action with mpls ttl of 0 (invalid) ok 45 b5d8 - Add mpls mod action with mpls ttl exceeding max (invalid) ok 46 451f - Add mpls mod action with mpls max bos ok 47 a1ed - Add mpls mod action with mpls min bos ok 48 3dcf - Add mpls mod action with mpls bos exceeding max (invalid) ok 49 db7c - Add mpls mod action with protocol (invalid) ok 50 b070 - Replace existing mpls push action with new ID ok 51 95a9 - Replace existing mpls push action with new label, tc, ttl and cookie ok 52 6cce - Delete mpls pop action ok 53 d138 - Flush mpls actions ok 54 7a70 - Reference mpls action object in filter Fixes: fb57b0920f06 ("tc: add mpls actions") Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Pedro Tammela <pctammela@mojatatu.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: m_csum: parse index argument correctlyPedro Tammela2023-03-051-1/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 'action csum index 1' is a valid cli according to TC's architecture. Fix the grammar parsing to accept it. tdc tests: 1..24 ok 1 6d84 - Add csum iph action ok 2 1862 - Add csum ip4h action ok 3 15c6 - Add csum ipv4h action ok 4 bf47 - Add csum icmp action ok 5 cc1d - Add csum igmp action ok 6 bccc - Add csum foobar action ok 7 3bb4 - Add csum tcp action ok 8 759c - Add csum udp action ok 9 bdb6 - Add csum udp xor iph action ok 10 c220 - Add csum udplite action ok 11 8993 - Add csum sctp action ok 12 b138 - Add csum ip & icmp action ok 13 eeda - Add csum ip & sctp action ok 14 0017 - Add csum udp or tcp action ok 15 b10b - Add all 7 csum actions ok 16 ce92 - Add csum udp action with cookie ok 17 912f - Add csum icmp action with large cookie ok 18 879b - Add batch of 32 csum tcp actions ok 19 b4e9 - Delete batch of 32 csum actions ok 20 0015 - Add batch of 32 csum tcp actions with large cookies ok 21 989e - Delete batch of 32 csum actions with large cookies ok 22 d128 - Replace csum action with invalid goto chain control ok 23 eaf0 - Add csum iph action with no_percpu flag ok 24 c619 - Reference csum action object in filter Fixes: 3822cc986cc3 ("tc: add ACT_CSUM action support (csum)") Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Pedro Tammela <pctammela@mojatatu.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: f_u32: fix json object leakHangbin Liu2023-03-051-14/+10
| | | | | | | | | | | | | | | | | | | | | | | | Previously, the code returned directly within the switch statement in the functions print_{ipv4, ipv6}. While this approach was functional, after the commit 721435dc, we can no longer return directly because we need to close the match object. To resolve this issue, replace the return statement with break. Fixes: 721435dcfd92 ("tc: u32: add json support in `print_raw`, `print_ipv4`, `print_ipv6`") Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * u32: fix TC_U32_TERMINAL printingHangbin Liu2023-03-051-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We previously printed an asterisk if there was no 'sel' or 'TC_U32_TERMINAL' flag. However, commit 1ff227545ce1 ("u32: fix json formatting of flowid") changed the logic to print an asterisk only if there is a 'TC_U32_TERMINAL' flag. Therefore, we need to fix this regression. Before the fix, the tdc u32 test failed: 1..11 not ok 1 afa9 - Add u32 with source match Could not match regex pattern. Verify command output: filter protocol ip pref 1 u32 chain 0 filter protocol ip pref 1 u32 chain 0 fh 800: ht divisor 1 filter protocol ip pref 1 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 *flowid 1:1 not_in_hw match 7f000001/ffffffff at 12 action order 1: gact action pass random type none pass val 0 index 1 ref 1 bind 1 After fix, the test passed: 1..11 ok 1 afa9 - Add u32 with source match Fixes: 1ff227545ce1 ("u32: fix json formatting of flowid") Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Reviewed-by: Victor Nogueira <victor@mojatatu.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: m_action: fix parsing of TCA_EXT_WARN_MSGPedro Tammela2023-02-241-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | It should sit within the TCA_ACT_TAB hierarchy, otherwise the access to tb is out of bounds: ./tc action ls action csum total acts 1 action order 0: csum (?empty) action pass index 1 ref 1 bind 0 not_in_hw Segmentation fault (core dumped) Fixes: 60359956 ("tc: add new attr TCA_EXT_WARN_MSG") Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Pedro Tammela <pctammela@mojatatu.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: add missing separatorChristian Hesse2023-02-241-1/+1
| | | | | | | | | | | | | | | | | | This is missing a separator, that was accidently removed when JSON was added. Fixes: 010a8388aea1 ("tc: Add JSON output to tc-class") Signed-off-by: Christian Hesse <mail@eworm.de> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* | tc: m_tunnel_key: support code for "nofrag" tunnelsDavide Caratti2023-04-071-11/+37
|/ | | | | | | | | add control plane for setting TCA_TUNNEL_KEY_NO_FRAG flag on act_tunnel_key actions. Signed-off-by: Davide Caratti <dcaratti@redhat.com> Reviewed-by: Simon Horman <simon.horman@corigine.com> Signed-off-by: David Ahern <dsahern@kernel.org>
* tc: m_ct: add support for helperXin Long2023-02-181-1/+52
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch is to add the setup and dump for helper in tc ct action in userspace, and the support in kernel was added in: https://lore.kernel.org/netdev/cover.1667766782.git.lucien.xin@gmail.com/ here is an example for usage: # ip link add dummy0 type dummy # tc qdisc add dev dummy0 ingress # tc filter add dev dummy0 ingress proto ip flower ip_proto \ tcp dst_port 21 ct_state -trk action ct helper ipv4-tcp-ftp # tc filter show dev dummy0 ingress filter protocol ip pref 49152 flower chain 0 handle 0x1 eth_type ipv4 ip_proto tcp dst_port 21 ct_state -trk not_in_hw action order 1: ct zone 0 helper ipv4-tcp-ftp pipe index 1 ref 1 bind v1->v2: - add dst_port 21 in the example tc flower rule in changelog as Marcele noticed. - use snprintf to avoid possible string overflows as Stephen suggested in ct_print_helper(). Signed-off-by: Xin Long <lucien.xin@gmail.com> Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David Ahern <dsahern@kernel.org>
* tc: add new attr TCA_EXT_WARN_MSGHangbin Liu2023-01-225-0/+15
| | | | | | | | | | | | | | | | | | | | | Currently, when the rule is not to be exclusively executed by the hardware, extack is not passed along and offloading failures don't get logged. Add a new attr TCA_EXT_WARN_MSG to log the extack message so we can monitor the HW failures. e.g. # tc monitor added chain dev enp3s0f1np1 parent ffff: chain 0 added filter dev enp3s0f1np1 ingress protocol all pref 49152 flower chain 0 handle 0x1 ct_state +trk+new not_in_hw action order 1: gact action drop random type none pass val 0 index 1 ref 1 bind 1 mlx5_core: matching on ct_state +new isn't supported. Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Signed-off-by: David Ahern <dsahern@kernel.org>
* Revert "tc/tc_monitor: print netlink extack message"Hangbin Liu2023-01-221-3/+0
| | | | | | | | This reverts commit 0cc5533b ("tc/tc_monitor: print netlink extack message") as the commit mentioned is not applied to upstream. Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Signed-off-by: David Ahern <dsahern@kernel.org>
* tc: use SPDXStephen Hemminger2023-01-1481-467/+79
| | | | | | Replace GPL boilerplate with SPDX. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc: replace GPL-BSD boilerplate in codel and fqStephen Hemminger2023-01-143-93/+3
| | | | | | | Replace legal boilerplate with SPDX instead. These algorithms are dual licensed. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc: remove support for rr qdiscStephen Hemminger2023-01-112-120/+0
| | | | | | | The Round-Robin qdisc was removed in kernel version 2.6.27. Remove code and man page references from iproute. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc/htb: add SPDX commentStephen Hemminger2023-01-091-9/+3
| | | | | | | The standard way is to use SPDX to refer to license, instead of per-file boilerplate text. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc/htb: break long linesStephen Hemminger2023-01-091-2/+4
| | | | | | Style guidelines is 100 characters Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* tc: Add JSON output to tc-classMax Tottenham2023-01-092-27/+37
| | | | | | | | * Add JSON formatted output to the `tc class show ...` command. * Add JSON formatted output for the htb qdisc classes. Signed-off-by: Max Tottenham <mtottenh@akamai.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* Merge branch 'main' into nextDavid Ahern2022-12-165-8/+9
|\ | | | | | | | | | | | | Conflicts: devlink/devlink.c Signed-off-by: David Ahern <dsahern@kernel.org>
| * tc: make prefix constStephen Hemminger2022-12-122-5/+6
| | | | | | | | | | | | Tcstats functions have prefix argument that can be made const. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: print errors on stderrStephen Hemminger2022-12-092-2/+2
| | | | | | | | | | | | Don't mix output and errors. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: ct: Fix invalid pointer dereferenceRoi Dayan2022-12-071-1/+1
| | | | | | | | | | | | | | | | | | | | | | Using macro NEXT_ARG_FWD does not validate argc. Use macro NEXT_ARG which validates argc while parsing args in the same loop iteration. Fixes: c8a494314c40 ("tc: Introduce tc ct action") Signed-off-by: Roi Dayan <roid@nvidia.com> Reviewed-by: Paul Blakey <paulb@nvidia.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* | Merge branch 'main' into nextDavid Ahern2022-12-028-62/+28
|\ \ | |/ | | | | Signed-off-by: David Ahern <dsahern@kernel.org>
| * tc/basic: fix json output filterStephen Hemminger2022-12-011-4/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The flowid and handle in basic were not using JSON routines to print. To reproduce the issue: $ tc qdisc add dev eth1 handle ffff: ingress $ tc filter add dev eth1 parent ffff: prio 20 protocol all u32 match ip dport 22 \ 0xffff action police conform-exceed drop/ok rate 100000 burst 15k flowid ffff:1 $ tc filter add dev eth1 parent ffff: prio 255 protocol all basic action police \ conform-exceed drop/ok rate 100000 burst 15k flowid ffff:3 Reported-by: Christian Pössinger <christian@poessinger.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: put size table options in json objectStephen Hemminger2022-11-251-0/+2
| | | | | | | | | | | | | | Missed this part from earlier change. Fixes: 6af6f02cce42 ("tc: add json support to size table") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc_util: Change datatype for maj to avoid overflow issueLai Peter Jun Ann2022-11-231-1/+1
| | | | | | | | | | | | | | | | | | The return value by stroul() is unsigned long int. Hence the datatype for maj should defined as unsigned long to avoid overflow issue. Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com> Signed-off-by: Lai Peter Jun Ann <jun.ann.lai@intel.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc_util: Fix no error return when large parent id usedLai Peter Jun Ann2022-11-231-1/+1
| | | | | | | | | | | | | | | | | | | | | | This patch is to fix the issue where there is no error return when large value of parent ID is being used. The return value by stroul() is unsigned long int. Hence the datatype for maj and min should defined as unsigned long to avoid overflow issue. Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com> Signed-off-by: Lai Peter Jun Ann <jun.ann.lai@intel.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc: add json support to size tableStephen Hemminger2022-11-223-10/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fix the JSON output if size addaption table is used. Example: [ { "kind": "fq_codel", "handle": "1:", "dev": "enp2s0", "root": true, "refcnt": 2, "options": { "limit": 10240, "flows": 1024, "quantum": 1514, "target": 4999, "interval": 99999, "memory_limit": 33554432, "ecn": true, "drop_batch": 64 }, "stab": { "overhead": 30, "mpu": 68, "mtu": 2047, "tsize": 512 } } ] Remove fixed prefix arg and no longer needed fp arg. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * remove #if 0 codeStephen Hemminger2022-11-223-30/+1
| | | | | | | | | | | | | | Let's not keep unused code. The YAGNI means that this dead code doesn't work now, and if it did it would have to change. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
| * tc_stab: remove dead codeStephen Hemminger2022-11-211-16/+0
| | | | | | | | | | | | | | This code to print the STAB table is not supportable, not converting to JSON. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* | taprio: fix wrong for loop condition in add_tc_entries()Tan Tee Min2022-12-021-1/+1
| | | | | | | | | | | | | | | | | | | | The for loop in add_tc_entries() mistakenly included the last entry index+1. Fix it to correctly loop the max_sdu entry between tc=0 and num_max_sdu_entries-1. Fixes: b10a6509c195 ("taprio: support dumping and setting per-tc max SDU") Signed-off-by: Tan Tee Min <tee.min.tan@linux.intel.com> Signed-off-by: David Ahern <dsahern@kernel.org>
* | Merge branch 'main' into nextDavid Ahern2022-11-131-5/+7
|\ \ | |/ | | | | | | | | | | Conflicts: include/uapi/linux/bpf.h Signed-off-by: David Ahern <dsahern@kernel.org>
| * u32: fix json formatting of flowidStephen Hemminger2022-10-131-5/+7
| | | | | | | | | | | | | | The code to print json was not done for the flow id. This would lead to incorrect JSON format output. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
* | taprio: support dumping and setting per-tc max SDUVladimir Oltean2022-10-311-0/+95
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The 802.1Q queueMaxSDU table is technically implemented in Linux as the TCA_TAPRIO_TC_ENTRY_MAX_SDU attribute of the TCA_TAPRIO_ATTR_TC_ENTRY nest. Multiple TCA_TAPRIO_ATTR_TC_ENTRY nests may appear in the netlink message, one per traffic class. Other configuration items that are per traffic class are also supposed to go there. This is done for future extensibility of the netlink interface (I have the feeling that the struct tc_mqprio_qopt passed through TCA_TAPRIO_ATTR_PRIOMAP is not exactly extensible, which kind of defeats the purpose of using netlink). But otherwise, the max-sdu is parsed from the user, and printed, just like any other fixed-size 16 element array. I've modified the example for a fully offloaded configuration (flags 2) to also show a max-sdu use case. The gate intervals were 0x80 (for TC 7), 0xa0 (for TCs 7 and 5) and 0xdf (for TCs 7, 6, 4, 3, 2, 1, 0). I modified the last gate to exclude TC 7 (df -> 5f), so that TC 7 now only interferes with TC 5. Output after running the full offload command from the man page example (the new attribute is "max-sdu"): $ tc qdisc show dev swp0 root qdisc taprio 8002: root tc 8 map 0 1 2 3 4 5 6 7 0 0 0 0 0 0 0 0 queues offset 0 count 1 offset 1 count 1 offset 2 count 1 offset 3 count 1 offset 4 count 1 offset 5 count 1 offset 6 count 1 offset 7 count 1 flags 0x2 base-time 200 cycle-time 100000 cycle-time-extension 0 index 0 cmd S gatemask 0x80 interval 20000 index 1 cmd S gatemask 0xa0 interval 20000 index 2 cmd S gatemask 0x5f interval 60000 max-sdu 0 0 0 0 0 200 0 0 0 0 0 0 0 0 0 0 $ tc -j -p qdisc show dev eno0 root [ { "kind": "taprio", "handle": "8002:", "root": true, "options": { "tc": 8, "map": [ 0,1,2,3,4,5,6,7,0,0,0,0,0,0,0,0 ], "queues": [ { "offset": 0, "count": 1 },{ "offset": 1, "count": 1 },{ "offset": 2, "count": 1 },{ "offset": 3, "count": 1 },{ "offset": 4, "count": 1 },{ "offset": 5, "count": 1 },{ "offset": 6, "count": 1 },{ "offset": 7, "count": 1 } ], "flags": "0x2", "base_time": 200, "cycle_time": 100000, "cycle_time_extension": 0, "schedule": [ { "index": 0, "cmd": "S", "gatemask": "0x80", "interval": 20000 },{ "index": 1, "cmd": "S", "gatemask": "0xa0", "interval": 20000 },{ "index": 2, "cmd": "S", "gatemask": "0x5f", "interval": 60000 } ], "max-sdu": [ 0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0 ] } } ] Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David Ahern <dsahern@kernel.org>
* | f_flower: Introduce L2TPv3 supportWojciech Drewek2022-10-091-1/+47
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Add support for matching on L2TPv3 session ID. Session ID can be specified only when ip proto was set to IPPROTO_L2TP. L2TPv3 might be transported over IP or over UDP, this implementation is only about L2TPv3 over IP. IPv6 is also supported, in this case next header is set to IPPROTO_L2TP. Example filter: # tc filter add dev eth0 ingress prio 1 protocol ip \ flower \ ip_proto l2tp \ l2tpv3_sid 1234 \ skip_sw \ action drop Reviewed-by: Guillaume Nault <gnault@redhat.com> Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com> Signed-off-by: David Ahern <dsahern@kernel.org>