naccyde / rpms / iproute

Forked from rpms/iproute 7 months ago
Clone

Blame SOURCES/0132-tc-actions-add-helpers-to-parse-and-print-control-ac.patch

36cfb7
From 23f1822fa8129326de4709d643f41cf26b6bae88 Mon Sep 17 00:00:00 2001
36cfb7
From: Andrea Claudi <aclaudi@redhat.com>
36cfb7
Date: Wed, 5 Jun 2019 13:09:39 +0200
36cfb7
Subject: [PATCH] tc: actions: add helpers to parse and print control actions
36cfb7
36cfb7
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1714660
36cfb7
Upstream Status: iproute2.git commit e67aba5595811
36cfb7
Conflicts: context change due to out-of-order cherry-pick of
36cfb7
           commit 73aa988868e7e ("tc/m_gact: Drop dead code")
36cfb7
36cfb7
commit e67aba559581143f9bc34f0706b0c3feeeab08fa
36cfb7
Author: Jiri Pirko <jiri@mellanox.com>
36cfb7
Date:   Tue May 16 19:29:36 2017 +0200
36cfb7
36cfb7
    tc: actions: add helpers to parse and print control actions
36cfb7
36cfb7
    Each tc action is terminated by a control action. Each action parses and
36cfb7
    prints then intividually. Introduce set of helpers and allow to share
36cfb7
    this code.
36cfb7
36cfb7
    Signed-off-by: Jiri Pirko <jiri@mellanox.com>
36cfb7
---
36cfb7
 tc/m_bpf.c        |   8 +--
36cfb7
 tc/m_connmark.c   |   4 +-
36cfb7
 tc/m_csum.c       |   9 ++-
36cfb7
 tc/m_gact.c       |  45 ++++-----------
36cfb7
 tc/m_ife.c        |  10 ++--
36cfb7
 tc/m_mirred.c     |  10 ++--
36cfb7
 tc/m_nat.c        |  11 ++--
36cfb7
 tc/m_pedit.c      |   8 +--
36cfb7
 tc/m_police.c     |  50 +++++------------
36cfb7
 tc/m_sample.c     |   4 +-
36cfb7
 tc/m_simple.c     |   3 -
36cfb7
 tc/m_skbedit.c    |   7 +--
36cfb7
 tc/m_skbmod.c     |  30 +---------
36cfb7
 tc/m_tunnel_key.c |   8 +--
36cfb7
 tc/m_vlan.c       |   9 ++-
36cfb7
 tc/tc_util.c      | 137 +++++++++++++++++++++++++++++++++++++++++++++-
36cfb7
 tc/tc_util.h      |  11 +++-
36cfb7
 17 files changed, 209 insertions(+), 155 deletions(-)
36cfb7
36cfb7
diff --git a/tc/m_bpf.c b/tc/m_bpf.c
36cfb7
index 1ddc334f2f21b..57283030a35f5 100644
36cfb7
--- a/tc/m_bpf.c
36cfb7
+++ b/tc/m_bpf.c
36cfb7
@@ -75,7 +75,7 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv,
36cfb7
 			 int tca_id, struct nlmsghdr *n)
36cfb7
 {
36cfb7
 	const char *bpf_obj = NULL, *bpf_uds_name = NULL;
36cfb7
-	struct tc_act_bpf parm = { .action = TC_ACT_PIPE };
36cfb7
+	struct tc_act_bpf parm = {};
36cfb7
 	struct bpf_cfg_in cfg = {};
36cfb7
 	bool seen_run = false;
36cfb7
 	struct rtattr *tail;
36cfb7
@@ -123,8 +123,8 @@ opt_bpf:
36cfb7
 		NEXT_ARG_FWD();
36cfb7
 	}
36cfb7
 
36cfb7
-	if (argc && !action_a2n(*argv, &parm.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &parm.action,
36cfb7
+				  false, TC_ACT_PIPE);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -186,7 +186,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
36cfb7
 				      b, sizeof(b)));
36cfb7
 	}
36cfb7
 
36cfb7
-	fprintf(f, "default-action %s\n", action_n2a(parm->action));
36cfb7
+	print_action_control(f, "default-action ", parm->action, "\n");
36cfb7
 	fprintf(f, "\tindex %u ref %d bind %d", parm->index, parm->refcnt,
36cfb7
 		parm->bindcnt);
36cfb7
 
36cfb7
diff --git a/tc/m_connmark.c b/tc/m_connmark.c
36cfb7
index 295f90d52eefd..3c2274bc0d2af 100644
36cfb7
--- a/tc/m_connmark.c
36cfb7
+++ b/tc/m_connmark.c
36cfb7
@@ -80,9 +80,7 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
36cfb7
 		}
36cfb7
 	}
36cfb7
 
36cfb7
-	sel.action = TC_ACT_PIPE;
36cfb7
-	if (argc && !action_a2n(*argv, &sel.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_PIPE);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
diff --git a/tc/m_csum.c b/tc/m_csum.c
36cfb7
index 0ee8cad3fbe4c..7b156734f64c5 100644
36cfb7
--- a/tc/m_csum.c
36cfb7
+++ b/tc/m_csum.c
36cfb7
@@ -123,8 +123,7 @@ parse_csum(struct action_util *a, int *argc_p,
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (argc && !action_a2n(*argv, &sel.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -200,10 +199,10 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg)
36cfb7
 		uflag_1 = "?empty";
36cfb7
 	}
36cfb7
 
36cfb7
-	fprintf(f, "csum (%s%s%s%s%s%s%s) action %s\n",
36cfb7
+	fprintf(f, "csum (%s%s%s%s%s%s%s) ",
36cfb7
 		uflag_1, uflag_2, uflag_3,
36cfb7
-		uflag_4, uflag_5, uflag_6, uflag_7,
36cfb7
-		action_n2a(sel->action));
36cfb7
+		uflag_4, uflag_5, uflag_6, uflag_7);
36cfb7
+	print_action_control(f, "action ", sel->action, "\n");
36cfb7
 	fprintf(f, "\tindex %u ref %d bind %d", sel->index, sel->refcnt,
36cfb7
 		sel->bindcnt);
36cfb7
 
36cfb7
diff --git a/tc/m_gact.c b/tc/m_gact.c
36cfb7
index 0cb5222fd3817..bc3860bbe4441 100644
36cfb7
--- a/tc/m_gact.c
36cfb7
+++ b/tc/m_gact.c
36cfb7
@@ -68,26 +68,13 @@ usage(void)
36cfb7
 	exit(-1);
36cfb7
 }
36cfb7
 
36cfb7
-static int
36cfb7
-get_act(char ***argv_p)
36cfb7
-{
36cfb7
-	int n;
36cfb7
-
36cfb7
-	if (action_a2n(**argv_p, &n, false)) {
36cfb7
-		fprintf(stderr, "bad action type %s\n", **argv_p);
36cfb7
-		return -10;
36cfb7
-	}
36cfb7
-	return n;
36cfb7
-}
36cfb7
-
36cfb7
 static int
36cfb7
 parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 	   int tca_id, struct nlmsghdr *n)
36cfb7
 {
36cfb7
 	int argc = *argc_p;
36cfb7
 	char **argv = *argv_p;
36cfb7
-	int action = TC_POLICE_RECLASSIFY;
36cfb7
-	struct tc_gact p = { .action = TC_POLICE_RECLASSIFY };
36cfb7
+	struct tc_gact p = { 0 };
36cfb7
 #ifdef CONFIG_GACT_PROB
36cfb7
 	int rd = 0;
36cfb7
 	struct tc_gact_p pp;
36cfb7
@@ -101,16 +88,8 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 	if (matches(*argv, "gact") == 0) {
36cfb7
 		argc--;
36cfb7
 		argv++;
36cfb7
-	} else {
36cfb7
-		action = get_act(&argv);
36cfb7
-		if (action != -10) {
36cfb7
-			p.action = action;
36cfb7
-			argc--;
36cfb7
-			argv++;
36cfb7
-		} else {
36cfb7
-			explain();
36cfb7
-			return action;
36cfb7
-		}
36cfb7
+	} else if (parse_action_control(&argc, &argv, &p.action, false) == -1) {
36cfb7
+		usage();
36cfb7
 	}
36cfb7
 
36cfb7
 #ifdef CONFIG_GACT_PROB
36cfb7
@@ -129,13 +108,9 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 				return -1;
36cfb7
 			}
36cfb7
 
36cfb7
-			action = get_act(&argv);
36cfb7
-			if (action != -10) { /* FIXME */
36cfb7
-				pp.paction = action;
36cfb7
-			} else {
36cfb7
-				explain();
36cfb7
-				return -1;
36cfb7
-			}
36cfb7
+			if (parse_action_control(&argc, &argv,
36cfb7
+						 &pp.paction, false) == -1)
36cfb7
+				usage();
36cfb7
 			argc--;
36cfb7
 			argv++;
36cfb7
 			if (get_u16(&pp.pval, *argv, 10)) {
36cfb7
@@ -204,7 +179,8 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg)
36cfb7
 	}
36cfb7
 	p = RTA_DATA(tb[TCA_GACT_PARMS]);
36cfb7
 
36cfb7
-	fprintf(f, "gact action %s", action_n2a(p->action));
36cfb7
+	fprintf(f, "gact ");
36cfb7
+	print_action_control(f, "action ", p->action, "");
36cfb7
 #ifdef CONFIG_GACT_PROB
36cfb7
 	if (tb[TCA_GACT_PROB] != NULL) {
36cfb7
 		pp = RTA_DATA(tb[TCA_GACT_PROB]);
36cfb7
@@ -213,8 +189,9 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg)
36cfb7
 		memset(&pp_dummy, 0, sizeof(pp_dummy));
36cfb7
 		pp = &pp_dummy;
36cfb7
 	}
36cfb7
-	fprintf(f, "\n\t random type %s %s val %d",
36cfb7
-		prob_n2a(pp->ptype), action_n2a(pp->paction), pp->pval);
36cfb7
+	fprintf(f, "\n\t random type %s", prob_n2a(pp->ptype));
36cfb7
+	print_action_control(f, " ", pp->paction, " ");
36cfb7
+	fprintf(f, "val %d", pp->pval);
36cfb7
 #endif
36cfb7
 	fprintf(f, "\n\t index %u ref %d bind %d", p->index, p->refcnt,
36cfb7
 		p->bindcnt);
36cfb7
diff --git a/tc/m_ife.c b/tc/m_ife.c
36cfb7
index f6131b1332324..e3521e62c178c 100644
36cfb7
--- a/tc/m_ife.c
36cfb7
+++ b/tc/m_ife.c
36cfb7
@@ -57,7 +57,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 	int argc = *argc_p;
36cfb7
 	char **argv = *argv_p;
36cfb7
 	int ok = 0;
36cfb7
-	struct tc_ife p = { .action = TC_ACT_PIPE };	/* good default */
36cfb7
+	struct tc_ife p = { 0 };
36cfb7
 	struct rtattr *tail;
36cfb7
 	struct rtattr *tail2;
36cfb7
 	char dbuf[ETH_ALEN];
36cfb7
@@ -156,8 +156,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 		argv++;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (argc && !action_a2n(*argv, &p.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -245,9 +244,8 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg)
36cfb7
 	}
36cfb7
 	p = RTA_DATA(tb[TCA_IFE_PARMS]);
36cfb7
 
36cfb7
-	fprintf(f, "ife %s action %s ",
36cfb7
-		(p->flags & IFE_ENCODE) ? "encode" : "decode",
36cfb7
-		action_n2a(p->action));
36cfb7
+	fprintf(f, "ife %s ", p->flags & IFE_ENCODE ? "encode" : "decode");
36cfb7
+	print_action_control(f, "action ", p->action, " ");
36cfb7
 
36cfb7
 	if (tb[TCA_IFE_TYPE]) {
36cfb7
 		ife_type = rta_getattr_u16(tb[TCA_IFE_TYPE]);
36cfb7
diff --git a/tc/m_mirred.c b/tc/m_mirred.c
36cfb7
index e9438904fdf50..2384bda1ff045 100644
36cfb7
--- a/tc/m_mirred.c
36cfb7
+++ b/tc/m_mirred.c
36cfb7
@@ -170,10 +170,8 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 	}
36cfb7
 
36cfb7
 
36cfb7
-	if (argc &&
36cfb7
-	    (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
36cfb7
-	    && !action_a2n(*argv, &p.action, false))
36cfb7
-		NEXT_ARG();
36cfb7
+	if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
36cfb7
+		parse_action_control(&argc, &argv, &p.action, false);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (iok && matches(*argv, "index") == 0) {
36cfb7
@@ -272,8 +270,8 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg)
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	fprintf(f, "mirred (%s to device %s) %s",
36cfb7
-		mirred_n2a(p->eaction), dev, action_n2a(p->action));
36cfb7
+	fprintf(f, "mirred (%s to device %s)", mirred_n2a(p->eaction), dev);
36cfb7
+	print_action_control(f, " ", p->action, "");
36cfb7
 
36cfb7
 	fprintf(f, "\n ");
36cfb7
 	fprintf(f, "\tindex %u ref %d bind %d", p->index, p->refcnt,
36cfb7
diff --git a/tc/m_nat.c b/tc/m_nat.c
36cfb7
index 525f185e2c082..31b68fb6bd784 100644
36cfb7
--- a/tc/m_nat.c
36cfb7
+++ b/tc/m_nat.c
36cfb7
@@ -115,8 +115,7 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (argc && !action_a2n(*argv, &sel.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -164,12 +163,12 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg)
36cfb7
 	len = ffs(sel->mask);
36cfb7
 	len = len ? 33 - len : 0;
36cfb7
 
36cfb7
-	fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
36cfb7
-					  "egress" : "ingress",
36cfb7
+	fprintf(f, " nat %s %s/%d %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
36cfb7
+				       "egress" : "ingress",
36cfb7
 		format_host_r(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)),
36cfb7
 		len,
36cfb7
-		format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)),
36cfb7
-		action_n2a(sel->action));
36cfb7
+		format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)));
36cfb7
+	print_action_control(f, " ", sel->action, "");
36cfb7
 
36cfb7
 	if (show_stats) {
36cfb7
 		if (tb[TCA_NAT_TM]) {
36cfb7
diff --git a/tc/m_pedit.c b/tc/m_pedit.c
36cfb7
index dfa6b2c4835e9..b7d26b4540beb 100644
36cfb7
--- a/tc/m_pedit.c
36cfb7
+++ b/tc/m_pedit.c
36cfb7
@@ -670,8 +670,7 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (argc && !action_a2n(*argv, &sel.sel.action, false))
36cfb7
-		NEXT_ARG();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &sel.sel.action, false, TC_ACT_OK);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -776,8 +775,9 @@ int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
36cfb7
 		}
36cfb7
 	}
36cfb7
 
36cfb7
-	fprintf(f, " pedit action %s keys %d\n ",
36cfb7
-		action_n2a(sel->action), sel->nkeys);
36cfb7
+	fprintf(f, " pedit ");
36cfb7
+	print_action_control(f, "action ", sel->action, " ");
36cfb7
+	fprintf(f,"keys %d\n ", sel->nkeys);
36cfb7
 	fprintf(f, "\t index %u ref %d bind %d", sel->index, sel->refcnt,
36cfb7
 		sel->bindcnt);
36cfb7
 
36cfb7
diff --git a/tc/m_police.c b/tc/m_police.c
36cfb7
index 226e20e4e8005..2b73969de5daf 100644
36cfb7
--- a/tc/m_police.c
36cfb7
+++ b/tc/m_police.c
36cfb7
@@ -50,27 +50,6 @@ static void explain1(char *arg)
36cfb7
 	fprintf(stderr, "Illegal \"%s\"\n", arg);
36cfb7
 }
36cfb7
 
36cfb7
-static int get_police_result(int *action, int *result, char *arg)
36cfb7
-{
36cfb7
-	char *p = strchr(arg, '/');
36cfb7
-
36cfb7
-	if (p)
36cfb7
-		*p = 0;
36cfb7
-
36cfb7
-	if (action_a2n(arg, action, true)) {
36cfb7
-		if (p)
36cfb7
-			*p = '/';
36cfb7
-		return -1;
36cfb7
-	}
36cfb7
-
36cfb7
-	if (p) {
36cfb7
-		*p = '/';
36cfb7
-		if (action_a2n(p+1, result, true))
36cfb7
-			return -1;
36cfb7
-	}
36cfb7
-	return 0;
36cfb7
-}
36cfb7
-
36cfb7
 int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 		     int tca_id, struct nlmsghdr *n)
36cfb7
 {
36cfb7
@@ -166,23 +145,19 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 				explain1("peakrate");
36cfb7
 				return -1;
36cfb7
 			}
36cfb7
-		} else if (matches(*argv, "reclassify") == 0) {
36cfb7
-			p.action = TC_POLICE_RECLASSIFY;
36cfb7
-		} else if (matches(*argv, "drop") == 0 ||
36cfb7
-			   matches(*argv, "shot") == 0) {
36cfb7
-			p.action = TC_POLICE_SHOT;
36cfb7
-		} else if (matches(*argv, "continue") == 0) {
36cfb7
-			p.action = TC_POLICE_UNSPEC;
36cfb7
-		} else if (matches(*argv, "pass") == 0) {
36cfb7
-			p.action = TC_POLICE_OK;
36cfb7
-		} else if (matches(*argv, "pipe") == 0) {
36cfb7
-			p.action = TC_POLICE_PIPE;
36cfb7
+		} else if (matches(*argv, "reclassify") == 0 ||
36cfb7
+			   matches(*argv, "drop") == 0 ||
36cfb7
+			   matches(*argv, "shot") == 0 ||
36cfb7
+			   matches(*argv, "continue") == 0 ||
36cfb7
+			   matches(*argv, "pass") == 0 ||
36cfb7
+			   matches(*argv, "pipe") == 0) {
36cfb7
+			if (parse_action_control(&argc, &argv, &p.action, false))
36cfb7
+				return -1;
36cfb7
 		} else if (strcmp(*argv, "conform-exceed") == 0) {
36cfb7
 			NEXT_ARG();
36cfb7
-			if (get_police_result(&p.action, &presult, *argv)) {
36cfb7
-				fprintf(stderr, "Illegal \"action\"\n");
36cfb7
+			if (parse_action_control_slash(&argc, &argv, &p.action,
36cfb7
+						       &presult, true))
36cfb7
 				return -1;
36cfb7
-			}
36cfb7
 		} else if (matches(*argv, "overhead") == 0) {
36cfb7
 			NEXT_ARG();
36cfb7
 			if (get_u16(&overhead, *argv, 10)) {
36cfb7
@@ -318,12 +293,13 @@ int print_police(struct action_util *a, FILE *f, struct rtattr *arg)
36cfb7
 		fprintf(f, "avrate %s ",
36cfb7
 			sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]),
36cfb7
 				    b1));
36cfb7
-	fprintf(f, "action %s", action_n2a(p->action));
36cfb7
+
36cfb7
+	print_action_control(f, "action ", p->action, "");
36cfb7
 
36cfb7
 	if (tb[TCA_POLICE_RESULT]) {
36cfb7
 		__u32 action = rta_getattr_u32(tb[TCA_POLICE_RESULT]);
36cfb7
 
36cfb7
-		fprintf(f, "/%s ", action_n2a(action));
36cfb7
+		print_action_control(f, "/", action, " ");
36cfb7
 	} else
36cfb7
 		fprintf(f, " ");
36cfb7
 
36cfb7
diff --git a/tc/m_sample.c b/tc/m_sample.c
36cfb7
index 9291109071a89..ff5ee6bd1ef63 100644
36cfb7
--- a/tc/m_sample.c
36cfb7
+++ b/tc/m_sample.c
36cfb7
@@ -98,9 +98,7 @@ static int parse_sample(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 		NEXT_ARG_FWD();
36cfb7
 	}
36cfb7
 
36cfb7
-	p.action = TC_ACT_PIPE;
36cfb7
-	if (argc && !action_a2n(*argv, &p.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
diff --git a/tc/m_simple.c b/tc/m_simple.c
36cfb7
index 65e48addf161b..f8937bcabb7ae 100644
36cfb7
--- a/tc/m_simple.c
36cfb7
+++ b/tc/m_simple.c
36cfb7
@@ -120,9 +120,6 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
36cfb7
 		}
36cfb7
 	}
36cfb7
 
36cfb7
-	if (argc && !action_a2n(*argv, &sel.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
-
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
 			NEXT_ARG();
36cfb7
diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c
36cfb7
index 638715f679d37..aa374fcb33ed9 100644
36cfb7
--- a/tc/m_skbedit.c
36cfb7
+++ b/tc/m_skbedit.c
36cfb7
@@ -120,9 +120,8 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
36cfb7
 		argv++;
36cfb7
 	}
36cfb7
 
36cfb7
-	sel.action = TC_ACT_PIPE;
36cfb7
-	if (argc && !action_a2n(*argv, &sel.action, false))
36cfb7
-		NEXT_ARG();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &sel.action,
36cfb7
+				  false, TC_ACT_PIPE);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -214,7 +213,7 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
36cfb7
 			fprintf(f, " ptype %d", *ptype);
36cfb7
 	}
36cfb7
 
36cfb7
-	fprintf(f, " %s", action_n2a(p->action));
36cfb7
+	print_action_control(f, " ", p->action, "");
36cfb7
 
36cfb7
 	fprintf(f, "\n\t index %u ref %d bind %d",
36cfb7
 		p->index, p->refcnt, p->bindcnt);
36cfb7
diff --git a/tc/m_skbmod.c b/tc/m_skbmod.c
36cfb7
index acb7771d2901b..1ccd474309348 100644
36cfb7
--- a/tc/m_skbmod.c
36cfb7
+++ b/tc/m_skbmod.c
36cfb7
@@ -61,7 +61,6 @@ static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 	char *saddr = NULL;
36cfb7
 
36cfb7
 	memset(&p, 0, sizeof(p));
36cfb7
-	p.action = TC_ACT_PIPE;	/* good default */
36cfb7
 
36cfb7
 	if (argc <= 0)
36cfb7
 		return -1;
36cfb7
@@ -123,31 +122,7 @@ static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 		argv++;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (argc) {
36cfb7
-		if (matches(*argv, "reclassify") == 0) {
36cfb7
-			p.action = TC_ACT_RECLASSIFY;
36cfb7
-			argc--;
36cfb7
-			argv++;
36cfb7
-		} else if (matches(*argv, "pipe") == 0) {
36cfb7
-			p.action = TC_ACT_PIPE;
36cfb7
-			argc--;
36cfb7
-			argv++;
36cfb7
-		} else if (matches(*argv, "drop") == 0 ||
36cfb7
-			   matches(*argv, "shot") == 0) {
36cfb7
-			p.action = TC_ACT_SHOT;
36cfb7
-			argc--;
36cfb7
-			argv++;
36cfb7
-		} else if (matches(*argv, "continue") == 0) {
36cfb7
-			p.action = TC_ACT_UNSPEC;
36cfb7
-			argc--;
36cfb7
-			argv++;
36cfb7
-		} else if (matches(*argv, "pass") == 0 ||
36cfb7
-			   matches(*argv, "ok") == 0) {
36cfb7
-			p.action = TC_ACT_OK;
36cfb7
-			argc--;
36cfb7
-			argv++;
36cfb7
-		}
36cfb7
-	}
36cfb7
+	parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -206,7 +181,8 @@ static int print_skbmod(struct action_util *au, FILE *f, struct rtattr *arg)
36cfb7
 
36cfb7
 	p = RTA_DATA(tb[TCA_SKBMOD_PARMS]);
36cfb7
 
36cfb7
-	fprintf(f, "skbmod action %s ", action_n2a(p->action));
36cfb7
+	fprintf(f, "skbmod ");
36cfb7
+	print_action_control(f, "", p->action, " ");
36cfb7
 
36cfb7
 	if (tb[TCA_SKBMOD_ETYPE]) {
36cfb7
 		skbmod_etype = rta_getattr_u16(tb[TCA_SKBMOD_ETYPE]);
36cfb7
diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
36cfb7
index 60fd1c464e531..cdde64a15b929 100644
36cfb7
--- a/tc/m_tunnel_key.c
36cfb7
+++ b/tc/m_tunnel_key.c
36cfb7
@@ -99,7 +99,7 @@ static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
36cfb7
 static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 			    int tca_id, struct nlmsghdr *n)
36cfb7
 {
36cfb7
-	struct tc_tunnel_key parm = { .action = TC_ACT_PIPE };
36cfb7
+	struct tc_tunnel_key parm = {};
36cfb7
 	char **argv = *argv_p;
36cfb7
 	int argc = *argc_p;
36cfb7
 	struct rtattr *tail;
36cfb7
@@ -194,8 +194,8 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 		NEXT_ARG_FWD();
36cfb7
 	}
36cfb7
 
36cfb7
-	if (argc && !action_a2n(*argv, &parm.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &parm.action,
36cfb7
+				  false, TC_ACT_PIPE);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -318,7 +318,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
36cfb7
 					  tb[TCA_TUNNEL_KEY_ENC_TTL]);
36cfb7
 		break;
36cfb7
 	}
36cfb7
-	fprintf(f, " %s", action_n2a(parm->action));
36cfb7
+	print_action_control(f, " ", parm->action, "");
36cfb7
 
36cfb7
 	fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt,
36cfb7
 		parm->bindcnt);
36cfb7
diff --git a/tc/m_vlan.c b/tc/m_vlan.c
36cfb7
index 44b9375966da3..2441b06847ecd 100644
36cfb7
--- a/tc/m_vlan.c
36cfb7
+++ b/tc/m_vlan.c
36cfb7
@@ -59,7 +59,7 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 	int proto_set = 0;
36cfb7
 	__u8 prio;
36cfb7
 	int prio_set = 0;
36cfb7
-	struct tc_vlan parm = { 0 };
36cfb7
+	struct tc_vlan parm = {};
36cfb7
 
36cfb7
 	if (matches(*argv, "vlan") != 0)
36cfb7
 		return -1;
36cfb7
@@ -133,9 +133,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
36cfb7
 		argv++;
36cfb7
 	}
36cfb7
 
36cfb7
-	parm.action = TC_ACT_PIPE;
36cfb7
-	if (argc && !action_a2n(*argv, &parm.action, false))
36cfb7
-		NEXT_ARG_FWD();
36cfb7
+	parse_action_control_dflt(&argc, &argv, &parm.action,
36cfb7
+				  false, TC_ACT_PIPE);
36cfb7
 
36cfb7
 	if (argc) {
36cfb7
 		if (matches(*argv, "index") == 0) {
36cfb7
@@ -224,7 +223,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
36cfb7
 		}
36cfb7
 		break;
36cfb7
 	}
36cfb7
-	fprintf(f, " %s", action_n2a(parm->action));
36cfb7
+	print_action_control(f, " ", parm->action, "");
36cfb7
 
36cfb7
 	fprintf(f, "\n\t index %u ref %d bind %d", parm->index, parm->refcnt,
36cfb7
 		parm->bindcnt);
36cfb7
diff --git a/tc/tc_util.c b/tc/tc_util.c
36cfb7
index 296825ae174e0..840222832690b 100644
36cfb7
--- a/tc/tc_util.c
36cfb7
+++ b/tc/tc_util.c
36cfb7
@@ -411,7 +411,7 @@ char *sprint_qdisc_handle(__u32 h, char *buf)
36cfb7
 	return buf;
36cfb7
 }
36cfb7
 
36cfb7
-const char *action_n2a(int action)
36cfb7
+static const char *action_n2a(int action)
36cfb7
 {
36cfb7
 	static char buf[64];
36cfb7
 
36cfb7
@@ -443,7 +443,7 @@ const char *action_n2a(int action)
36cfb7
  *
36cfb7
  * In error case, returns -1 and does not touch @result. Otherwise returns 0.
36cfb7
  */
36cfb7
-int action_a2n(char *arg, int *result, bool allow_num)
36cfb7
+static int action_a2n(char *arg, int *result, bool allow_num)
36cfb7
 {
36cfb7
 	int n;
36cfb7
 	char dummy;
36cfb7
@@ -474,6 +474,139 @@ int action_a2n(char *arg, int *result, bool allow_num)
36cfb7
 	return 0;
36cfb7
 }
36cfb7
 
36cfb7
+/* Parse action control including possible options.
36cfb7
+ *
36cfb7
+ * Parameters:
36cfb7
+ * @argc_p - pointer to argc to parse
36cfb7
+ * @argv_p - pointer to argv to parse
36cfb7
+ * @result_p - pointer to output variable
36cfb7
+ * @allow_num - whether action may be in numeric format already
36cfb7
+ *
36cfb7
+ * In error case, returns -1 and does not touch @result_1p. Otherwise returns 0.
36cfb7
+ */
36cfb7
+int parse_action_control(int *argc_p, char ***argv_p,
36cfb7
+			 int *result_p, bool allow_num)
36cfb7
+{
36cfb7
+	int argc = *argc_p;
36cfb7
+	char **argv = *argv_p;
36cfb7
+	int result;
36cfb7
+
36cfb7
+	if (!argc)
36cfb7
+		return -1;
36cfb7
+	if (action_a2n(*argv, &result, allow_num) == -1) {
36cfb7
+		fprintf(stderr, "Bad action type %s\n", *argv);
36cfb7
+		return -1;
36cfb7
+	}
36cfb7
+	NEXT_ARG_FWD();
36cfb7
+	*argc_p = argc;
36cfb7
+	*argv_p = argv;
36cfb7
+	*result_p = result;
36cfb7
+	return 0;
36cfb7
+}
36cfb7
+
36cfb7
+/* Parse action control including possible options.
36cfb7
+ *
36cfb7
+ * Parameters:
36cfb7
+ * @argc_p - pointer to argc to parse
36cfb7
+ * @argv_p - pointer to argv to parse
36cfb7
+ * @result_p - pointer to output variable
36cfb7
+ * @allow_num - whether action may be in numeric format already
36cfb7
+ * @default_result - set as a result in case of parsing error
36cfb7
+ *
36cfb7
+ * In case there is an error during parsing, the default result is used.
36cfb7
+ */
36cfb7
+void parse_action_control_dflt(int *argc_p, char ***argv_p,
36cfb7
+			       int *result_p, bool allow_num,
36cfb7
+			       int default_result)
36cfb7
+{
36cfb7
+	if (parse_action_control(argc_p, argv_p, result_p, allow_num))
36cfb7
+		*result_p = default_result;
36cfb7
+}
36cfb7
+
36cfb7
+static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p,
36cfb7
+					     int *result1_p, int *result2_p,
36cfb7
+					     bool allow_num)
36cfb7
+{
36cfb7
+	int argc = *argc_p;
36cfb7
+	char **argv = *argv_p;
36cfb7
+	int result1, result2;
36cfb7
+	int *result_p = &result1;
36cfb7
+	int ok = 0;
36cfb7
+	int ret;
36cfb7
+
36cfb7
+	while (argc > 0) {
36cfb7
+		switch (ok) {
36cfb7
+		case 1:
36cfb7
+			if (strcmp(*argv, "/") != 0)
36cfb7
+				goto out;
36cfb7
+			result_p = &result2;
36cfb7
+			NEXT_ARG();
36cfb7
+			/* fall-through */
36cfb7
+		case 0: /* fall-through */
36cfb7
+		case 2:
36cfb7
+			ret = parse_action_control(&argc, &argv,
36cfb7
+						   result_p, allow_num);
36cfb7
+			if (ret)
36cfb7
+				return ret;
36cfb7
+			ok++;
36cfb7
+			break;
36cfb7
+		default:
36cfb7
+			goto out;
36cfb7
+		}
36cfb7
+	}
36cfb7
+out:
36cfb7
+	*result1_p = result1;
36cfb7
+	if (ok == 2)
36cfb7
+		*result2_p = result2;
36cfb7
+	*argc_p = argc;
36cfb7
+	*argv_p = argv;
36cfb7
+	return 0;
36cfb7
+}
36cfb7
+
36cfb7
+/* Parse action control with slash including possible options.
36cfb7
+ *
36cfb7
+ * Parameters:
36cfb7
+ * @argc_p - pointer to argc to parse
36cfb7
+ * @argv_p - pointer to argv to parse
36cfb7
+ * @result1_p - pointer to the first (before slash) output variable
36cfb7
+ * @result2_p - pointer to the second (after slash) output variable
36cfb7
+ * @allow_num - whether action may be in numeric format already
36cfb7
+ *
36cfb7
+ * In error case, returns -1 and does not touch @result*. Otherwise returns 0.
36cfb7
+ */
36cfb7
+int parse_action_control_slash(int *argc_p, char ***argv_p,
36cfb7
+			       int *result1_p, int *result2_p, bool allow_num)
36cfb7
+{
36cfb7
+	char **argv = *argv_p;
36cfb7
+	int result1, result2;
36cfb7
+	char *p = strchr(*argv, '/');
36cfb7
+
36cfb7
+	if (!p)
36cfb7
+		return parse_action_control_slash_spaces(argc_p, argv_p,
36cfb7
+							 result1_p, result2_p,
36cfb7
+							 allow_num);
36cfb7
+	*p = 0;
36cfb7
+	if (action_a2n(*argv, &result1, allow_num)) {
36cfb7
+		if (p)
36cfb7
+			*p = '/';
36cfb7
+		return -1;
36cfb7
+	}
36cfb7
+
36cfb7
+	*p = '/';
36cfb7
+	if (action_a2n(p + 1, &result2, allow_num))
36cfb7
+		return -1;
36cfb7
+
36cfb7
+	*result1_p = result1;
36cfb7
+	*result2_p = result2;
36cfb7
+	return 0;
36cfb7
+}
36cfb7
+
36cfb7
+void print_action_control(FILE *f, const char *prefix,
36cfb7
+			  int action, const char *suffix)
36cfb7
+{
36cfb7
+	fprintf(f, "%s%s%s", prefix, action_n2a(action), suffix);
36cfb7
+}
36cfb7
+
36cfb7
 int get_linklayer(unsigned int *val, const char *arg)
36cfb7
 {
36cfb7
 	int res;
36cfb7
diff --git a/tc/tc_util.h b/tc/tc_util.h
36cfb7
index 4db26c6d5e25b..5c54ad384eae6 100644
36cfb7
--- a/tc/tc_util.h
36cfb7
+++ b/tc/tc_util.h
36cfb7
@@ -100,8 +100,15 @@ char *sprint_tc_classid(__u32 h, char *buf);
36cfb7
 int tc_print_police(FILE *f, struct rtattr *tb);
36cfb7
 int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n);
36cfb7
 
36cfb7
-const char *action_n2a(int action);
36cfb7
-int action_a2n(char *arg, int *result, bool allow_num);
36cfb7
+int parse_action_control(int *argc_p, char ***argv_p,
36cfb7
+			 int *result_p, bool allow_num);
36cfb7
+void parse_action_control_dflt(int *argc_p, char ***argv_p,
36cfb7
+			       int *result_p, bool allow_num,
36cfb7
+			       int default_result);
36cfb7
+int parse_action_control_slash(int *argc_p, char ***argv_p,
36cfb7
+			       int *result1_p, int *result2_p, bool allow_num);
36cfb7
+void print_action_control(FILE *f, const char *prefix,
36cfb7
+			  int action, const char *suffix);
36cfb7
 int act_parse_police(struct action_util *a, int *argc_p,
36cfb7
 		     char ***argv_p, int tca_id, struct nlmsghdr *n);
36cfb7
 int print_police(struct action_util *a, FILE *f, struct rtattr *tb);
36cfb7
-- 
e138d9
2.21.0
36cfb7