Origin: upstream, https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=d5cbf3ff0561b6c8158c3538c7fe1946add9dec3
Bug-Ubuntu: https://bugs.launchpad.net/bugs/1642514
From: Yotam Gigi <yotamg@mellanox.com>
Date: Wed, 31 Aug 2016 09:28:26 +0200
Subject: [PATCH] tc: Add support for the matchall traffic classifier.

The matchall classifier matches every packet and allows the user to apply
actions on it. In addition, it supports the skip_sw and skip_hw (as can
be found on u32 and flower filter) that direct the kernel to skip the
software/hardware processing of the actions.

This filter is very useful in usecases where every packet should be
matched. For example, packet mirroring (SPAN) can be setup very easily
using that filter.

Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>

(backported from commit d5cbf3ff0561b6c8158c3538c7fe1946add9dec3 iproute2)
[smb: Add kernel definitions and merged printing skip flags]
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
---
 tc/Makefile     |   1 +
 tc/f_matchall.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+)
 create mode 100644 tc/f_matchall.c

Index: iproute2/tc/Makefile
===================================================================
--- iproute2.orig/tc/Makefile
+++ iproute2/tc/Makefile
@@ -65,6 +65,7 @@ TCMODULES += q_fq.o
 TCMODULES += q_pie.o
 TCMODULES += q_hhf.o
 TCMODULES += e_bpf.o
+TCMODULES += f_matchall.o
 
 ifeq ($(TC_CONFIG_IPSET), y)
   ifeq ($(TC_CONFIG_XT), y)
Index: iproute2/tc/f_matchall.c
===================================================================
--- /dev/null
+++ iproute2/tc/f_matchall.c
@@ -0,0 +1,152 @@
+/*
+ * f_matchall.c		Match-all Classifier
+ *
+ *		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:	Jiri Pirko <jiri@mellanox.com>, Yotam Gigi <yotamg@mellanox.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <linux/if.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+	fprintf(stderr, "Usage: ... matchall [skip_sw | skip_hw]\n");
+	fprintf(stderr, "                 [ action ACTION_SPEC ] [ classid CLASSID ]\n");
+	fprintf(stderr, "\n");
+	fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
+	fprintf(stderr, "       FILTERID := X:Y:Z\n");
+	fprintf(stderr, "       ACTION_SPEC := ... look at individual actions\n");
+	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
+}
+
+static int matchall_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 flags = 0;
+	long h = 0;
+
+	if (handle) {
+		h = strtol(handle, NULL, 0);
+		if (h == LONG_MIN || h == LONG_MAX) {
+			fprintf(stderr, "Illegal handle \"%s\", must be numeric.\n",
+			    handle);
+			return -1;
+		}
+	}
+	t->tcm_handle = h;
+
+	if (argc == 0)
+		return 0;
+
+	tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len));
+	addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
+
+	while (argc > 0) {
+		if (matches(*argv, "classid") == 0 ||
+			   strcmp(*argv, "flowid") == 0) {
+			unsigned int handle;
+
+			NEXT_ARG();
+			if (get_tc_classid(&handle, *argv)) {
+				fprintf(stderr, "Illegal \"classid\"\n");
+				return -1;
+			}
+			addattr_l(n, MAX_MSG, TCA_MATCHALL_CLASSID, &handle, 4);
+		} else if (matches(*argv, "action") == 0) {
+			NEXT_ARG();
+			if (parse_action(&argc, &argv, TCA_MATCHALL_ACT, n)) {
+				fprintf(stderr, "Illegal \"action\"\n");
+				return -1;
+			}
+			continue;
+
+		} else if (strcmp(*argv, "skip_hw") == 0) {
+			NEXT_ARG();
+			flags |= TCA_CLS_FLAGS_SKIP_HW;
+			continue;
+		} else if (strcmp(*argv, "skip_sw") == 0) {
+			NEXT_ARG();
+			flags |= TCA_CLS_FLAGS_SKIP_SW;
+			continue;
+		} else if (strcmp(*argv, "help") == 0) {
+			explain();
+			return -1;
+		} else {
+			fprintf(stderr, "What is \"%s\"?\n", *argv);
+			explain();
+			return -1;
+		}
+		argc--; argv++;
+	}
+
+	if (flags) {
+		if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW |
+			       TCA_CLS_FLAGS_SKIP_SW))) {
+			fprintf(stderr,
+				"skip_hw and skip_sw are mutually exclusive\n");
+			return -1;
+		}
+		addattr_l(n, MAX_MSG, TCA_MATCHALL_FLAGS, &flags, 4);
+	}
+
+	tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail;
+	return 0;
+}
+
+static int matchall_print_opt(struct filter_util *qu, FILE *f,
+			   struct rtattr *opt, __u32 handle)
+{
+	struct rtattr *tb[TCA_MATCHALL_MAX+1];
+
+	if (opt == NULL)
+		return 0;
+
+	parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt);
+
+	if (handle)
+		fprintf(f, "handle 0x%x ", handle);
+
+	if (tb[TCA_MATCHALL_CLASSID]) {
+		SPRINT_BUF(b1);
+		fprintf(f, "flowid %s ",
+			sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1));
+	}
+
+	if (tb[TCA_MATCHALL_FLAGS]) {
+		__u32 flags = rta_getattr_u32(tb[TCA_MATCHALL_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_MATCHALL_ACT])
+		tc_print_action(f, tb[TCA_MATCHALL_ACT]);
+
+	return 0;
+}
+
+struct filter_util matchall_filter_util = {
+	.id = "matchall",
+	.parse_fopt = matchall_parse_opt,
+	.print_fopt = matchall_print_opt,
+};
Index: iproute2/include/linux/pkt_cls.h
===================================================================
--- iproute2.orig/include/linux/pkt_cls.h
+++ iproute2/include/linux/pkt_cls.h
@@ -95,6 +95,10 @@ enum {
 
 #define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1)
 
+/* tca flags definitions */
+#define TCA_CLS_FLAGS_SKIP_HW   (1 << 0) /* don't offload filter to HW */
+#define TCA_CLS_FLAGS_SKIP_SW   (1 << 1) /* don't use filter in SW */
+
 /* U32 filters */
 
 #define TC_U32_HTID(h) ((h)&0xFFF00000)
@@ -363,6 +367,18 @@ enum {
 
 #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
 
+/* Match-all classifier */
+
+enum {
+	TCA_MATCHALL_UNSPEC,
+	TCA_MATCHALL_CLASSID,
+	TCA_MATCHALL_ACT,
+	TCA_MATCHALL_FLAGS,
+	__TCA_MATCHALL_MAX,
+};
+
+#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1)
+
 /* Extended Matches */
 
 struct tcf_ematch_tree_hdr {
