Blame SOURCES/0028-tc-m_tunnel_key-add-options-support-for-erpsan.patch

0ac2f3
From 2fb8c115a8031d893fff588181cc42764391e4d5 Mon Sep 17 00:00:00 2001
0ac2f3
From: Andrea Claudi <aclaudi@redhat.com>
0ac2f3
Date: Thu, 4 Jun 2020 21:43:50 +0200
0ac2f3
Subject: [PATCH] tc: m_tunnel_key: add options support for erpsan
0ac2f3
0ac2f3
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
0ac2f3
Upstream Status: unknown commit 668fd9b25d9ec
0ac2f3
0ac2f3
commit 668fd9b25d9eca3067040273239f7825db95442b
0ac2f3
Author: Xin Long <lucien.xin@gmail.com>
0ac2f3
Date:   Mon Apr 27 18:27:49 2020 +0800
0ac2f3
0ac2f3
    tc: m_tunnel_key: add options support for erpsan
0ac2f3
0ac2f3
    This patch is to add TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN's parse and
0ac2f3
    print to implement erspan options support in m_tunnel_key, like
0ac2f3
    Commit 6217917a3826 ("tc: m_tunnel_key: Add tunnel option support
0ac2f3
    to act_tunnel_key") for geneve options support.
0ac2f3
0ac2f3
    Option is expressed as version:index:dir:hwid, dir and hwid will
0ac2f3
    be parsed when version is 2, while index will be parsed when
0ac2f3
    version is 1. erspan doesn't support multiple options.
0ac2f3
0ac2f3
    With this patch, users can add and dump erspan options like:
0ac2f3
0ac2f3
      # ip link add name erspan1 type erspan external
0ac2f3
      # tc qdisc add dev eth0 ingress
0ac2f3
      # tc filter add dev eth0 protocol ip parent ffff: \
0ac2f3
          flower indev eth0 \
0ac2f3
            ip_proto udp \
0ac2f3
            action tunnel_key \
0ac2f3
              set src_ip 10.0.99.192 \
0ac2f3
              dst_ip 10.0.99.193 \
0ac2f3
              dst_port 6081 \
0ac2f3
              id 11 \
0ac2f3
              erspan_opts 1:2:0:0 \
0ac2f3
          action mirred egress redirect dev erspan1
0ac2f3
      # tc -s filter show dev eth0 parent ffff:
0ac2f3
0ac2f3
         filter protocol ip pref 49151 flower chain 0 handle 0x1
0ac2f3
           indev eth0
0ac2f3
           eth_type ipv4
0ac2f3
           ip_proto udp
0ac2f3
           not_in_hw
0ac2f3
             action order 1: tunnel_key  set
0ac2f3
             src_ip 10.0.99.192
0ac2f3
             dst_ip 10.0.99.193
0ac2f3
             key_id 11
0ac2f3
             dst_port 6081
0ac2f3
             erspan_opts 1:2:0:0
0ac2f3
             csum pipe
0ac2f3
               index 2 ref 1 bind 1
0ac2f3
             ...
0ac2f3
    v1->v2:
0ac2f3
      - no change.
0ac2f3
    v2->v3:
0ac2f3
      - no change.
0ac2f3
    v3->v4:
0ac2f3
      - keep the same format between input and output, json and non json.
0ac2f3
      - print version, index, dir and hwid as uint.
0ac2f3
0ac2f3
    Signed-off-by: Xin Long <lucien.xin@gmail.com>
0ac2f3
    Signed-off-by: David Ahern <dsahern@gmail.com>
0ac2f3
---
0ac2f3
 man/man8/tc-tunnel_key.8 |  12 +++-
0ac2f3
 tc/m_tunnel_key.c        | 117 ++++++++++++++++++++++++++++++++++++++-
0ac2f3
 2 files changed, 127 insertions(+), 2 deletions(-)
0ac2f3
0ac2f3
diff --git a/man/man8/tc-tunnel_key.8 b/man/man8/tc-tunnel_key.8
0ac2f3
index c208e2c82a181..ad9972402c0e5 100644
0ac2f3
--- a/man/man8/tc-tunnel_key.8
0ac2f3
+++ b/man/man8/tc-tunnel_key.8
0ac2f3
@@ -68,8 +68,10 @@ options.
0ac2f3
 .B dst_port
0ac2f3
 ,
0ac2f3
 .B geneve_opts
0ac2f3
-and
0ac2f3
+,
0ac2f3
 .B vxlan_opts
0ac2f3
+and
0ac2f3
+.B erspan_opts
0ac2f3
 are optional.
0ac2f3
 .RS
0ac2f3
 .TP
0ac2f3
@@ -99,6 +101,14 @@ Vxlan metatdata options.
0ac2f3
 is specified in the form GBP, as a 32bit number. Multiple options is not
0ac2f3
 supported.
0ac2f3
 .TP
0ac2f3
+.B erspan_opts
0ac2f3
+Erspan metatdata options.
0ac2f3
+.B erspan_opts
0ac2f3
+is specified in the form VERSION:INDEX:DIR:HWID, where VERSION is represented
0ac2f3
+as a 8bit number, INDEX as an 32bit number, DIR and HWID as a 8bit number.
0ac2f3
+Multiple options is not supported. Note INDEX is used when VERSION is 1,
0ac2f3
+and DIR and HWID are used when VERSION is 2.
0ac2f3
+.TP
0ac2f3
 .B tos
0ac2f3
 Outer header TOS
0ac2f3
 .TP
0ac2f3
diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
0ac2f3
index 76391d6c85fb2..a56fe24413fa0 100644
0ac2f3
--- a/tc/m_tunnel_key.c
0ac2f3
+++ b/tc/m_tunnel_key.c
0ac2f3
@@ -29,7 +29,7 @@ static void explain(void)
0ac2f3
 		"src_ip <IP> (mandatory)\n"
0ac2f3
 		"dst_ip <IP> (mandatory)\n"
0ac2f3
 		"dst_port <UDP_PORT>\n"
0ac2f3
-		"geneve_opts | vxlan_opts <OPTIONS>\n"
0ac2f3
+		"geneve_opts | vxlan_opts | erspan_opts <OPTIONS>\n"
0ac2f3
 		"csum | nocsum (default is \"csum\")\n");
0ac2f3
 }
0ac2f3
 
0ac2f3
@@ -97,6 +97,21 @@ static int tunnel_key_parse_be16(char *str, int base, int type,
0ac2f3
 	return 0;
0ac2f3
 }
0ac2f3
 
0ac2f3
+static int tunnel_key_parse_be32(char *str, int base, int type,
0ac2f3
+				 struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	__be32 value;
0ac2f3
+	int ret;
0ac2f3
+
0ac2f3
+	ret = get_be32(&value, str, base);
0ac2f3
+	if (ret)
0ac2f3
+		return ret;
0ac2f3
+
0ac2f3
+	addattr32(n, MAX_MSG, type, value);
0ac2f3
+
0ac2f3
+	return 0;
0ac2f3
+}
0ac2f3
+
0ac2f3
 static int tunnel_key_parse_u8(char *str, int base, int type,
0ac2f3
 			       struct nlmsghdr *n)
0ac2f3
 {
0ac2f3
@@ -226,6 +241,63 @@ static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
0ac2f3
 	return 0;
0ac2f3
 }
0ac2f3
 
0ac2f3
+static int tunnel_key_parse_erspan_opt(char *str, struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	char *token, *saveptr = NULL;
0ac2f3
+	struct rtattr *encap, *nest;
0ac2f3
+	int i, ret;
0ac2f3
+
0ac2f3
+	encap = addattr_nest(n, MAX_MSG,
0ac2f3
+			     TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
0ac2f3
+	nest = addattr_nest(n, MAX_MSG,
0ac2f3
+			    TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED);
0ac2f3
+
0ac2f3
+	token = strtok_r(str, ":", &saveptr);
0ac2f3
+	i = 1;
0ac2f3
+	while (token) {
0ac2f3
+		switch (i) {
0ac2f3
+		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER:
0ac2f3
+		{
0ac2f3
+			ret = tunnel_key_parse_u8(token, 0, i, n);
0ac2f3
+			if (ret)
0ac2f3
+				return ret;
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX:
0ac2f3
+		{
0ac2f3
+			ret = tunnel_key_parse_be32(token, 0, i, n);
0ac2f3
+			if (ret)
0ac2f3
+				return ret;
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR:
0ac2f3
+		{
0ac2f3
+			ret = tunnel_key_parse_u8(token, 0, i, n);
0ac2f3
+			if (ret)
0ac2f3
+				return ret;
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID:
0ac2f3
+		{
0ac2f3
+			ret = tunnel_key_parse_u8(token, 0, i, n);
0ac2f3
+			if (ret)
0ac2f3
+				return ret;
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+		default:
0ac2f3
+			return -1;
0ac2f3
+		}
0ac2f3
+
0ac2f3
+		token = strtok_r(NULL, ":", &saveptr);
0ac2f3
+		i++;
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	addattr_nest_end(n, nest);
0ac2f3
+	addattr_nest_end(n, encap);
0ac2f3
+
0ac2f3
+	return 0;
0ac2f3
+}
0ac2f3
+
0ac2f3
 static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
0ac2f3
 {
0ac2f3
 	int ret;
0ac2f3
@@ -330,6 +402,13 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
0ac2f3
 				fprintf(stderr, "Illegal \"vxlan_opts\"\n");
0ac2f3
 				return -1;
0ac2f3
 			}
0ac2f3
+		} else if (matches(*argv, "erspan_opts") == 0) {
0ac2f3
+			NEXT_ARG();
0ac2f3
+
0ac2f3
+			if (tunnel_key_parse_erspan_opt(*argv, n)) {
0ac2f3
+				fprintf(stderr, "Illegal \"erspan_opts\"\n");
0ac2f3
+				return -1;
0ac2f3
+			}
0ac2f3
 		} else if (matches(*argv, "tos") == 0) {
0ac2f3
 			NEXT_ARG();
0ac2f3
 			ret = tunnel_key_parse_tos_ttl(*argv,
0ac2f3
@@ -517,6 +596,39 @@ static void tunnel_key_print_vxlan_options(struct rtattr *attr)
0ac2f3
 	close_json_array(PRINT_JSON, name);
0ac2f3
 }
0ac2f3
 
0ac2f3
+static void tunnel_key_print_erspan_options(struct rtattr *attr)
0ac2f3
+{
0ac2f3
+	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
0ac2f3
+	struct rtattr *i = RTA_DATA(attr);
0ac2f3
+	int rem = RTA_PAYLOAD(attr);
0ac2f3
+	char *name = "erspan_opts";
0ac2f3
+	__u8 ver, hwid, dir;
0ac2f3
+	__u32 idx;
0ac2f3
+
0ac2f3
+	parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, i, rem);
0ac2f3
+	ver = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]);
0ac2f3
+	if (ver == 1) {
0ac2f3
+		idx = rta_getattr_be32(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]);
0ac2f3
+		dir = 0;
0ac2f3
+		hwid = 0;
0ac2f3
+	} else {
0ac2f3
+		idx = 0;
0ac2f3
+		dir = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]);
0ac2f3
+		hwid = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]);
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	print_nl();
0ac2f3
+	print_string(PRINT_FP, name, "\t%s ", name);
0ac2f3
+	open_json_array(PRINT_JSON, name);
0ac2f3
+	open_json_object(NULL);
0ac2f3
+	print_uint(PRINT_ANY, "ver", "%u", ver);
0ac2f3
+	print_uint(PRINT_ANY, "index", ":%u", idx);
0ac2f3
+	print_uint(PRINT_ANY, "dir", ":%u", dir);
0ac2f3
+	print_uint(PRINT_ANY, "hwid", ":%u", hwid);
0ac2f3
+	close_json_object();
0ac2f3
+	close_json_array(PRINT_JSON, name);
0ac2f3
+}
0ac2f3
+
0ac2f3
 static void tunnel_key_print_key_opt(struct rtattr *attr)
0ac2f3
 {
0ac2f3
 	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
0ac2f3
@@ -531,6 +643,9 @@ static void tunnel_key_print_key_opt(struct rtattr *attr)
0ac2f3
 	else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN])
0ac2f3
 		tunnel_key_print_vxlan_options(
0ac2f3
 			tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]);
0ac2f3
+	else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN])
0ac2f3
+		tunnel_key_print_erspan_options(
0ac2f3
+			tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]);
0ac2f3
 }
0ac2f3
 
0ac2f3
 static void tunnel_key_print_tos_ttl(FILE *f, char *name,
0ac2f3
-- 
0ac2f3
2.26.2
0ac2f3