@@ -81,7 +81,7 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
}
sel.action = TC_ACT_PIPE;
- if (argc && !action_a2n(*argv, &sel.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &sel.action, false))
NEXT_ARG_FWD();
if (argc) {
@@ -123,7 +123,7 @@ parse_csum(struct action_util *a, int *argc_p,
return -1;
}
- if (argc && !action_a2n(*argv, &sel.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &sel.action, false))
NEXT_ARG_FWD();
if (argc) {
@@ -68,15 +68,22 @@ usage(void)
exit(-1);
}
+/* XXX: Obsolete this function */
static int
-get_act(char ***argv_p)
+get_act(int *argc_p, char ***argv_p)
{
+ char **argv = *argv_p;
+ int argc = *argc_p;
int n;
- if (action_a2n(**argv_p, &n, false)) {
+ if (action_a2n_jmp(&argc, &argv, &n, false)) {
fprintf(stderr, "bad action type %s\n", **argv_p);
return -10;
}
+
+ *argc_p = argc;
+ *argv_p = argv;
+
return n;
}
@@ -102,7 +109,7 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
if (matches(*argv, "gact") == 0) {
ok++;
} else {
- action = get_act(&argv);
+ action = get_act(&argc, &argv);
if (action != -10) {
p.action = action;
ok++;
@@ -133,13 +140,15 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
return -1;
}
- action = get_act(&argv);
+ action = get_act(&argc, &argv);
if (action != -10) { /* FIXME */
pp.paction = action;
} else {
explain();
return -1;
}
+ //XXX: remove the argc below after testing with random
+ //..
argc--;
argv++;
if (get_u16(&pp.pval, *argv, 10)) {
@@ -156,7 +156,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
argv++;
}
- if (argc && !action_a2n(*argv, &p.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &p.action, false))
NEXT_ARG_FWD();
if (argc) {
@@ -172,7 +172,7 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
if (argc &&
(p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
- && !action_a2n(*argv, &p.action, false))
+ && !action_a2n_jmp(&argc, &argv, &p.action, false))
NEXT_ARG();
if (argc) {
@@ -115,7 +115,7 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct
return -1;
}
- if (argc && !action_a2n(*argv, &sel.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &sel.action, false))
NEXT_ARG_FWD();
if (argc) {
@@ -481,7 +481,7 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
return -1;
}
- if (argc && !action_a2n(*argv, &sel.sel.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &sel.sel.action, false))
NEXT_ARG();
if (argc) {
@@ -50,24 +50,91 @@ static void explain1(char *arg)
fprintf(stderr, "Illegal \"%s\"\n", arg);
}
-static int get_police_result(int *action, int *result, char *arg)
+static int get_police_result(int *action, int *result, int *argc_p,
+ char ***argv_p)
{
- char *p = strchr(arg, '/');
+ char **argv = *argv_p;
+ int argc = *argc_p;
+ char *p = strchr(*argv, '/');
+ int skip_args = 0;
if (p)
*p = 0;
- if (action_a2n(arg, action, true)) {
+ if (action_a2n(*argv, action, true)) {
if (p)
*p = '/';
return -1;
}
+ if (*action == TC_ACT_JUMP) {
+ __u32 act_goto_cnt = 0;
+
+ argv++;
+ argc--;
+ p = strchr(*argv, '/'); /*was at "jump" */
+ if (p)
+ *p = 0;
+
+ if (get_u32(&act_goto_cnt, *argv, 10)) {
+ if (p)
+ *p = '/';
+ fprintf(stderr, "bad action jmp count %s\n",
+ *argv);
+ return -1;
+ }
+
+ if (act_goto_cnt > 32/*MAX_PRIO*/ || !act_goto_cnt) {
+ if (p)
+ *p = '/';
+ fprintf(stderr, "Bad jmp range %s: Need [1,32]\n",
+ *argv);
+ return -1;
+ }
+
+ *action |= act_goto_cnt;
+ argv++;
+ argc--;
+ skip_args += 1;
+ }
+
if (p) {
*p = '/';
if (action_a2n(p+1, result, true))
return -1;
}
+
+ if (*result == TC_ACT_JUMP) {
+ __u32 goto_cnt = 0;
+
+ if (!skip_args) {
+ argv++;
+ argc--;
+ }
+
+ if (get_u32(&goto_cnt, *argv, 10)) {
+ if (p)
+ *p = '/';
+ fprintf(stderr, "bad result jmp count %s\n",
+ *argv);
+ return -1;
+ }
+
+ if (goto_cnt > 32/*MAX_PRIO*/ || !goto_cnt) {
+ if (p)
+ *p = '/';
+ fprintf(stderr, "Bad result jmp range %s: Need[1,32]\n",
+ *argv);
+ return -1;
+ }
+
+ *result |= goto_cnt;
+ skip_args += 1;
+ }
+
+ *argc_p -= skip_args;
+ *argv_p += skip_args;
+
return 0;
}
@@ -179,7 +246,8 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p,
p.action = TC_POLICE_PIPE;
} else if (strcmp(*argv, "conform-exceed") == 0) {
NEXT_ARG();
- if (get_police_result(&p.action, &presult, *argv)) {
+ if (get_police_result(&p.action, &presult, &argc,
+ &argv)) {
fprintf(stderr, "Illegal \"action\"\n");
return -1;
}
@@ -120,7 +120,7 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
}
}
- if (argc && !action_a2n(*argv, &sel.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &sel.action, false))
NEXT_ARG_FWD();
if (argc) {
@@ -121,7 +121,7 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
}
sel.action = TC_ACT_PIPE;
- if (argc && !action_a2n(*argv, &sel.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &sel.action, false))
NEXT_ARG();
if (argc) {
@@ -158,7 +158,7 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
NEXT_ARG_FWD();
}
- if (argc && !action_a2n(*argv, &parm.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &parm.action, false))
NEXT_ARG_FWD();
if (argc) {
@@ -134,7 +134,7 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
}
parm.action = TC_ACT_PIPE;
- if (argc && !action_a2n(*argv, &parm.action, false))
+ if (argc && !action_a2n_jmp(&argc, &argv, &parm.action, false))
NEXT_ARG_FWD();
if (argc) {
@@ -429,7 +429,11 @@ const char *action_n2a(int action)
case TC_ACT_STOLEN:
return "stolen";
default:
- snprintf(buf, 64, "%d", action);
+ if (action & TC_ACT_JUMP) {
+ snprintf(buf, 64, "jump %d", action&0x1ff);
+ } else {
+ snprintf(buf, 64, "%d", action);
+ }
buf[63] = '\0';
return buf;
}
@@ -459,15 +463,18 @@ int action_a2n(char *arg, int *result, bool allow_num)
{"ok", TC_ACT_OK},
{"reclassify", TC_ACT_RECLASSIFY},
{"pipe", TC_ACT_PIPE},
+ {"jump", TC_ACT_JUMP},
{ NULL },
}, *iter;
for (iter = a2n; iter->a; iter++) {
if (matches(arg, iter->a) != 0)
continue;
+
*result = iter->n;
return 0;
}
+
if (!allow_num || sscanf(arg, "%d%c", &n, &dummy) != 1)
return -1;
@@ -475,6 +482,44 @@ int action_a2n(char *arg, int *result, bool allow_num)
return 0;
}
+int action_a2n_jmp(int *argc_p, char ***argv_p, int *result, bool allow_num)
+{
+ int n;
+ char dummy;
+ char **argv = *argv_p;
+ int argc = *argc_p;
+
+ if (action_a2n(*argv, result, false)) {
+ fprintf(stderr, "bad jmp action type %s\n", **argv_p);
+ return -10;
+ }
+
+ if (*result == TC_ACT_JUMP) {
+ __u32 goto_cnt = 0;
+
+ argv++;
+ argc--;
+ if (get_u32(&goto_cnt, *argv, 10)) {
+ fprintf(stderr, "bad action jmp count %s\n",
+ *argv);
+ return -1;
+ }
+
+ if (goto_cnt > 32/*MAX_PRIO*/ || !goto_cnt) {
+ fprintf(stderr, "Bad jmp range %s: Need [1,32]\n",
+ *argv);
+ return -1;
+ }
+
+ *result |= 1;
+ }
+
+ *argc_p = argc;
+ *argv_p = argv;
+
+ return 0;
+}
+
int get_linklayer(unsigned int *val, const char *arg)
{
int res;
@@ -102,6 +102,7 @@ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n);
const char *action_n2a(int action);
int action_a2n(char *arg, int *result, bool allow_num);
+int action_a2n_jmp(int *argc_p, char ***arg, int *result, bool allow_num);
int act_parse_police(struct action_util *a, int *argc_p,
char ***argv_p, int tca_id, struct nlmsghdr *n);
int print_police(struct action_util *a, FILE *f, struct rtattr *tb);