Blob Blame History Raw
From 080a2a99ff48cb30a5efb105dba3d1040dac6e21 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 17 Mar 2017 13:21:33 +0100
Subject: [PATCH] tc: flower: Add skip_{hw|sw} support

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1422629
Upstream Status: iproute2.git commit cfcabf18d84a2

commit cfcabf18d84a2f4908cb5b4489f67c2cd3f70426
Author: Amir Vadai <amirva@mellanox.com>
Date:   Mon Jul 4 10:34:11 2016 +0300

    tc: flower: Add skip_{hw|sw} support

    On devices that support TC flower offloads, these flags enable a filter to be
    added only to HW or only to SW. skip_sw and skip_hw are mutually exclusive
    flags. By default without any flags, the filter is added to both HW and SW,
    but no error checks are done in case of failure to add to HW.
    With skip-sw, failure to add to HW is treated as an error.

    Here is a sample script that adds 2 filters, one with skip_sw and the other
    with skip_hw flag.

       # add ingress qdisc
       tc qdisc add dev enp0s9 ingress

       # enable hw tc offload.
       ethtool -K enp0s9 hw-tc-offload on

       # add a flower filter with skip-sw flag.
       tc filter add dev enp0s9 protocol ip parent ffff: flower \
               ip_proto 1 indev enp0s9 skip_sw \
               action drop

       # add a flower filter with skip-hw flag.
       tc filter add dev enp0s9 protocol ip parent ffff: flower \
               ip_proto 3 indev enp0s9 skip_hw \
               action drop

    Signed-off-by: Amir Vadai <amirva@mellanox.com>
    Acked-by: Jiri Pirko <jiri@mellanox.com>
---
 man/man8/tc-flower.8 | 11 ++++++++++-
 tc/f_flower.c        | 17 +++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
index df4d8e1..9ae10e6 100644
--- a/man/man8/tc-flower.8
+++ b/man/man8/tc-flower.8
@@ -18,7 +18,9 @@ flower \- flow based traffic control filter
 .ti -8
 .IR MATCH " := { "
 .B indev
-.IR ifname " | { "
+.IR ifname " | "
+.BR skip_sw " | " skip_hw
+.R " | { "
 .BR dst_mac " | " src_mac " } "
 .IR mac_address " | "
 .BR eth_type " { " ipv4 " | " ipv6 " | "
@@ -55,6 +57,13 @@ is the name of an interface which must exist at the time of
 .B tc
 invocation.
 .TP
+.BI skip_sw
+Do not process filter by software. If hardware has no offload support for this
+filter, or TC offload is not enabled for the interface, operation will fail.
+.TP
+.BI skip_hw
+Do not process filter by hardware.
+.TP
 .BI dst_mac " mac_address"
 .TQ
 .BI src_mac " mac_address"
diff --git a/tc/f_flower.c b/tc/f_flower.c
index 11e6242..01527c8 100644
--- a/tc/f_flower.c
+++ b/tc/f_flower.c
@@ -25,6 +25,7 @@
 static void explain(void)
 {
 	fprintf(stderr, "Usage: ... flower [ MATCH-LIST ]\n");
+	fprintf(stderr, "                  [ skip_sw | skip_hw ]\n");
 	fprintf(stderr, "                  [ action ACTION-SPEC ] [ classid CLASSID ]\n");
 	fprintf(stderr, "\n");
 	fprintf(stderr, "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n");
@@ -167,6 +168,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
 	struct rtattr *tail;
 	__be16 eth_type = TC_H_MIN(t->tcm_info);
 	__u8 ip_proto = 0xff;
+	__u32 flags = 0;
 
 	if (handle) {
 		ret = get_u32(&t->tcm_handle, handle, 0);
@@ -196,6 +198,10 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
 				return -1;
 			}
 			addattr_l(n, MAX_MSG, TCA_FLOWER_CLASSID, &handle, 4);
+		} else if (matches(*argv, "skip_hw") == 0) {
+			flags |= TCA_CLS_FLAGS_SKIP_HW;
+		} else if (matches(*argv, "skip_sw") == 0) {
+			flags |= TCA_CLS_FLAGS_SKIP_SW;
 		} else if (matches(*argv, "indev") == 0) {
 			char ifname[IFNAMSIZ];
 
@@ -294,6 +300,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
 	}
 
 parse_done:
+	addattr32(n, MAX_MSG, TCA_FLOWER_FLAGS, flags);
+
 	ret = addattr16(n, MAX_MSG, TCA_FLOWER_KEY_ETH_TYPE, eth_type);
 	if (ret) {
 		fprintf(stderr, "Illegal \"eth_type\"(0x%x)\n",
@@ -498,6 +506,15 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
 			  tb[TCA_FLOWER_KEY_TCP_SRC],
 			  tb[TCA_FLOWER_KEY_UDP_SRC]);
 
+	if (tb[TCA_FLOWER_FLAGS])  {
+		__u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]);
+
+		if (flags & TCA_CLS_FLAGS_SKIP_HW)
+			fprintf(f, "\n  skip_hw");
+		if (flags & TCA_CLS_FLAGS_SKIP_SW)
+			fprintf(f, "\n  skip_sw");
+	}
+
 	if (tb[TCA_FLOWER_ACT]) {
 		tc_print_action(f, tb[TCA_FLOWER_ACT]);
 	}
-- 
1.8.3.1