diff mbox series

[iproute2,1/1] tc: introduce skbhash classifier

Message ID 20200807223110.24857-1-jhs@emojatatu.com
State Deferred
Delegated to: David Miller
Headers show
Series [iproute2,1/1] tc: introduce skbhash classifier | expand

Commit Message

Jamal Hadi Salim Aug. 7, 2020, 10:31 p.m. UTC
From: Jamal Hadi Salim <hadi@mojatatu.com>

This classifier - in the same spirit as the tc skb mark classifier - provides
a generic (fast lookup) approach to filter on the hash value and optional
mask.

like skb->mark, skb->hash could be set by multiple entities in the datapath
including but not limited to hardware offloaded classification policies,
hardware RSS (which already sets it today), XDP, ebpf programs
and even by other tc actions like skbedit and IFE.

Example use:

$TC qdisc add  dev $DEV1 ingress
... offloaded to hardware using flower ...
$TC filter add dev $DEV1 ingress protocol ip prio 1 flower hash 0x1f/0xff skip_sw flowid 1:1 \
action ok
... and when it shows up in s/w tagged from hardware, do something funky...
$TC filter add dev $DEV1 parent ffff: protocol ip prio 2 handle 0x11/0xff skbhash flowid 1:11 \
action mirred egress redirect dev $DEV2
$TC filter add dev $DEV1 parent ffff: protocol ip prio 3 handle 0x12 skbhash flowid 1:12 \
action mirred egress redirect dev $DEV3

Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/uapi/linux/pkt_cls.h |  13 ++++
 tc/Makefile                  |   1 +
 tc/f_skbhash.c               | 140 +++++++++++++++++++++++++++++++++++
 3 files changed, 154 insertions(+)
 create mode 100644 tc/f_skbhash.c
diff mbox series

Patch

diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 7576209d..da22bf87 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -767,4 +767,17 @@  enum {
 	TCF_EM_OPND_LT
 };
 
+/* skbhash filter */
+
+enum {
+	TCA_SKBHASH_UNSPEC,
+	TCA_SKBHASH_CLASSID,
+	TCA_SKBHASH_POLICE,
+	TCA_SKBHASH_ACT,
+	TCA_SKBHASH_MASK,
+	__TCA_SKBHASH_MAX
+};
+
+#define TCA_SKBHASH_MAX (__TCA_SKBHASH_MAX - 1)
+
 #endif
diff --git a/tc/Makefile b/tc/Makefile
index 79c9c1dd..8c78f922 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -29,6 +29,7 @@  TCMODULES += f_bpf.o
 TCMODULES += f_flow.o
 TCMODULES += f_cgroup.o
 TCMODULES += f_flower.o
+TCMODULES += f_skbhash.o
 TCMODULES += q_dsmark.o
 TCMODULES += q_gred.o
 TCMODULES += f_tcindex.o
diff --git a/tc/f_skbhash.c b/tc/f_skbhash.c
new file mode 100644
index 00000000..b2537acd
--- /dev/null
+++ b/tc/f_skbhash.c
@@ -0,0 +1,140 @@ 
+/*
+ * f_skbhash.c		SKBHASH filter.
+ *
+ *		This program is free software; you can redistribute 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 <jhs@mojatatu.com>
+ *
+ */
+
+#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 <linux/if.h> /* IFNAMSIZ */
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+	fprintf(stderr,
+		"Usage: ... skbhash [ classid CLASSID ] [ indev DEV ] [ action ACTION_SPEC ]\n"
+		"	CLASSID := Push matching packets to the class identified by CLASSID with format X:Y\n"
+		"		CLASSID is parsed as hexadecimal input.\n"
+		"	ACTION_SPEC := Apply an action on matching packets.\n"
+		"	NOTE: handle is represented as HANDLE[/SKBHASHMASK].\n"
+		"		SKBHASHMASK is 0xffffffff by default.\n");
+}
+
+static int skbhash_parse_opt(struct filter_util *qu, char *handle, int argc,
+			     char **argv, struct nlmsghdr *n)
+{
+	struct tcmsg *t = NLMSG_DATA(n);
+	struct rtattr *tail;
+	__u32 mask = 0;
+	int mask_set = 0;
+
+	if (handle) {
+		char *slash;
+
+		if ((slash = strchr(handle, '/')) != NULL)
+			*slash = '\0';
+		if (get_u32(&t->tcm_handle, handle, 0)) {
+			fprintf(stderr, "Illegal \"handle\"\n");
+			return -1;
+		}
+		if (slash) {
+			if (get_u32(&mask, slash+1, 0)) {
+				fprintf(stderr, "Illegal \"handle\" mask\n");
+				return -1;
+			}
+			mask_set = 1;
+		}
+	}
+
+	if (argc == 0)
+		return 0;
+
+	tail = addattr_nest(n, 4096, TCA_OPTIONS);
+
+	if (mask_set)
+		addattr32(n, MAX_MSG, TCA_SKBHASH_MASK, mask);
+
+	while (argc > 0) {
+		if (matches(*argv, "classid") == 0 ||
+		    matches(*argv, "flowid") == 0) {
+			unsigned int handle;
+
+			NEXT_ARG();
+			if (get_tc_classid(&handle, *argv)) {
+				fprintf(stderr, "Illegal \"classid\"\n");
+				return -1;
+			}
+			addattr_l(n, 4096, TCA_SKBHASH_CLASSID, &handle, 4);
+		} else if (matches(*argv, "action") == 0) {
+			NEXT_ARG();
+			if (parse_action(&argc, &argv, TCA_SKBHASH_ACT, n)) {
+				fprintf(stderr, "Illegal skbhash \"action\"\n");
+				return -1;
+			}
+			continue;
+		} else if (strcmp(*argv, "help") == 0) {
+			explain();
+			return -1;
+		} else {
+			fprintf(stderr, "What is \"%s\"?\n", *argv);
+			explain();
+			return -1;
+		}
+		argc--; argv++;
+	}
+	addattr_nest_end(n, tail);
+	return 0;
+}
+
+static int skbhash_print_opt(struct filter_util *qu, FILE *f,
+			     struct rtattr *opt, __u32 handle)
+{
+	struct rtattr *tb[TCA_SKBHASH_MAX+1];
+
+	if (opt == NULL)
+		return 0;
+
+	parse_rtattr_nested(tb, TCA_SKBHASH_MAX, opt);
+
+	if (handle || tb[TCA_SKBHASH_MASK]) {
+		__u32 mark = 0, mask = 0;
+
+		if (handle)
+			mark = handle;
+		if (tb[TCA_SKBHASH_MASK] &&
+		    (mask = rta_getattr_u32(tb[TCA_SKBHASH_MASK])) != 0xFFFFFFFF)
+			fprintf(f, "handle 0x%x/0x%x ", mark, mask);
+		else
+			fprintf(f, "handle 0x%x ", handle);
+	}
+
+	if (tb[TCA_SKBHASH_CLASSID]) {
+		SPRINT_BUF(b1);
+		fprintf(f, "classid %s ", sprint_tc_classid(rta_getattr_u32(tb[TCA_SKBHASH_CLASSID]), b1));
+	}
+
+	if (tb[TCA_SKBHASH_ACT]) {
+		fprintf(f, "\n");
+		tc_print_action(f, tb[TCA_SKBHASH_ACT], 0);
+	}
+	return 0;
+}
+
+struct filter_util skbhash_filter_util = {
+	.id = "skbhash",
+	.parse_fopt = skbhash_parse_opt,
+	.print_fopt = skbhash_print_opt,
+};