mirror_iproute2/tc/m_gact.c
Roman Mashak fa49588973 tc: Fix binding of gact action by index.
The following operation fails:
% sudo tc actions add action pipe index 1
% sudo tc filter add dev lo parent ffff: \
       protocol ip pref 10 u32 match ip src 127.0.0.2 \
       flowid 1:10 action gact index 1

Bad action type index
Usage: ... gact <ACTION> [RAND] [INDEX]
Where:  ACTION := reclassify | drop | continue | pass | pipe |
                  goto chain <CHAIN_INDEX> | jump <JUMP_COUNT>
        RAND := random <RANDTYPE> <ACTION> <VAL>
        RANDTYPE := netrand | determ
        VAL : = value not exceeding 10000
        JUMP_COUNT := Absolute jump from start of action list
        INDEX := index value used

However, passing a control action of gact rule during filter binding works:

% sudo tc filter add dev lo parent ffff: \
       protocol ip pref 10 u32 match ip src 127.0.0.2 \
       flowid 1:10 action gact pipe index 1

Binding by reference, i.e. by index, has to consistently work with
any tc action.

Since tc is sensitive to the order of keywords passed on the command line,
we can teach gact to skip parsing arguments as soon as it sees 'gact'
followed by 'index' keyword.

Signed-off-by: Roman Mashak <mrv@mojatatu.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2019-06-06 14:41:31 -07:00

222 lines
5.0 KiB
C

/*
* m_gact.c generic actions module
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: J Hadi Salim (hadi@cyberus.ca)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "utils.h"
#include "tc_util.h"
#include <linux/tc_act/tc_gact.h>
/* define to turn on probablity 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 <ACTION> [RAND] [INDEX]\n");
fprintf(stderr,
"Where: \tACTION := reclassify | drop | continue | pass | pipe |\n"
" \t goto chain <CHAIN_INDEX> | jump <JUMP_COUNT>\n"
"\tRAND := random <RANDTYPE> <ACTION> <VAL>\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 <ACTION> [INDEX]\n");
fprintf(stderr,
"Where: \tACTION := reclassify | drop | continue | pass | pipe |\n"
" \t goto chain <CHAIN_INDEX> | jump <JUMP_COUNT>\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(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_FWD();
/* 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(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];
if (arg == NULL)
return -1;
parse_rtattr_nested(tb, TCA_GACT_MAX, arg);
if (tb[TCA_GACT_PARMS] == NULL) {
print_string(PRINT_FP, NULL, "%s", "[NULL gact parameters]");
return -1;
}
p = RTA_DATA(tb[TCA_GACT_PARMS]);
print_string(PRINT_ANY, "kind", "%s ", "gact");
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_string(PRINT_ANY, "random_type", "\n\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_uint(PRINT_ANY, "index", "\n\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_string(PRINT_FP, NULL, "%s", "\n");
return 0;
}
struct action_util gact_action_util = {
.id = "gact",
.parse_aopt = parse_gact,
.print_aopt = print_gact,
};