/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * m_gact.c generic actions module * * Authors: J Hadi Salim (hadi@cyberus.ca) */ #include #include #include #include #include #include #include #include #include "utils.h" #include "tc_util.h" #include /* define to turn on probability stuff */ #ifdef CONFIG_GACT_PROB static const char *prob_n2a(int p) { if (p == PGACT_NONE) return "none"; if (p == PGACT_NETRAND) return "netrand"; if (p == PGACT_DETERM) return "determ"; return "none"; } #endif static void explain(void) { #ifdef CONFIG_GACT_PROB fprintf(stderr, "Usage: ... gact [RAND] [INDEX]\n"); fprintf(stderr, "Where: \tACTION := reclassify | drop | continue | pass | pipe |\n" " \t goto chain | jump \n" "\tRAND := random \n" "\tRANDTYPE := netrand | determ\n" "\tVAL : = value not exceeding 10000\n" "\tJUMP_COUNT := Absolute jump from start of action list\n" "\tINDEX := index value used\n" "\n"); #else fprintf(stderr, "Usage: ... gact [INDEX]\n" "Where: \tACTION := reclassify | drop | continue | pass | pipe |\n" " \t goto chain | jump \n" "\tINDEX := index value used\n" "\tJUMP_COUNT := Absolute jump from start of action list\n" "\n"); #endif } static void usage(void) { explain(); exit(-1); } static int parse_gact(const struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; struct tc_gact p = { 0 }; #ifdef CONFIG_GACT_PROB int rd = 0; struct tc_gact_p pp; #endif struct rtattr *tail; if (argc < 0) return -1; if (!matches(*argv, "gact")) NEXT_ARG(); /* we're binding existing gact action to filter by index. */ if (!matches(*argv, "index")) goto skip_args; if (parse_action_control(&argc, &argv, &p.action, false)) usage(); /* does not return */ #ifdef CONFIG_GACT_PROB if (argc > 0) { if (matches(*argv, "random") == 0) { rd = 1; NEXT_ARG(); if (matches(*argv, "netrand") == 0) { NEXT_ARG(); pp.ptype = PGACT_NETRAND; } else if (matches(*argv, "determ") == 0) { NEXT_ARG(); pp.ptype = PGACT_DETERM; } else { fprintf(stderr, "Illegal \"random type\"\n"); return -1; } if (parse_action_control(&argc, &argv, &pp.paction, false) == -1) usage(); if (get_u16(&pp.pval, *argv, 10)) { fprintf(stderr, "Illegal probability val 0x%x\n", pp.pval); return -1; } if (pp.pval > 10000) { fprintf(stderr, "Illegal probability val 0x%x\n", pp.pval); return -1; } argc--; argv++; } else if (matches(*argv, "help") == 0) { usage(); } } #endif if (argc > 0) { if (matches(*argv, "index") == 0) { skip_args: NEXT_ARG(); if (get_u32(&p.index, *argv, 10)) { fprintf(stderr, "Illegal \"index\"\n"); return -1; } argc--; argv++; } else if (matches(*argv, "help") == 0) { usage(); } } tail = addattr_nest(n, MAX_MSG, tca_id); addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p)); #ifdef CONFIG_GACT_PROB if (rd) addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp)); #endif addattr_nest_end(n, tail); *argc_p = argc; *argv_p = argv; return 0; } static int print_gact(const struct action_util *au, FILE *f, struct rtattr *arg) { #ifdef CONFIG_GACT_PROB struct tc_gact_p *pp = NULL; struct tc_gact_p pp_dummy; #endif struct tc_gact *p = NULL; struct rtattr *tb[TCA_GACT_MAX + 1]; print_string(PRINT_ANY, "kind", "%s ", "gact"); if (arg == NULL) return 0; parse_rtattr_nested(tb, TCA_GACT_MAX, arg); if (tb[TCA_GACT_PARMS] == NULL) { fprintf(stderr, "Missing gact parameters\n"); return -1; } p = RTA_DATA(tb[TCA_GACT_PARMS]); print_action_control(f, "action ", p->action, ""); #ifdef CONFIG_GACT_PROB if (tb[TCA_GACT_PROB] != NULL) { pp = RTA_DATA(tb[TCA_GACT_PROB]); } else { /* need to keep consistent output */ memset(&pp_dummy, 0, sizeof(pp_dummy)); pp = &pp_dummy; } open_json_object("prob"); print_nl(); print_string(PRINT_ANY, "random_type", "\t random type %s", prob_n2a(pp->ptype)); print_action_control(f, " ", pp->paction, " "); print_int(PRINT_ANY, "val", "val %d", pp->pval); close_json_object(); #endif print_nl(); print_uint(PRINT_ANY, "index", "\t index %u", p->index); print_int(PRINT_ANY, "ref", " ref %d", p->refcnt); print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt); if (show_stats) { if (tb[TCA_GACT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_GACT_TM]); print_tm(f, tm); } } print_nl(); return 0; } struct action_util gact_action_util = { .id = "gact", .parse_aopt = parse_gact, .print_aopt = print_gact, };