naccyde / rpms / iproute

Forked from rpms/iproute 10 months ago
Clone

Blame SOURCES/0030-tc-f_flower-add-options-support-for-erspan.patch

0ac2f3
From 6784a916b142c3bd5cf7c20a30b23e362bd4908a Mon Sep 17 00:00:00 2001
0ac2f3
From: Andrea Claudi <aclaudi@redhat.com>
0ac2f3
Date: Thu, 4 Jun 2020 21:44:22 +0200
0ac2f3
Subject: [PATCH] tc: f_flower: add options support for erspan
0ac2f3
0ac2f3
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
0ac2f3
Upstream Status: unknown commit 4e578c78fedfe
0ac2f3
0ac2f3
commit 4e578c78fedfe6ffa5fa5fde56778b264485829b
0ac2f3
Author: Xin Long <lucien.xin@gmail.com>
0ac2f3
Date:   Mon Apr 27 18:27:51 2020 +0800
0ac2f3
0ac2f3
    tc: f_flower: add options support for erspan
0ac2f3
0ac2f3
    This patch is to add TCA_FLOWER_KEY_ENC_OPTS_ERSPAN's parse and
0ac2f3
    print to implement erspan options support in m_tunnel_key, like
0ac2f3
    Commit 56155d4df86d ("tc: f_flower: add geneve option match
0ac2f3
    support to flower") 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 erspan1 ingress
0ac2f3
      # tc filter add dev erspan1 protocol ip parent ffff: \
0ac2f3
          flower \
0ac2f3
            enc_src_ip 10.0.99.192 \
0ac2f3
            enc_dst_ip 10.0.99.193 \
0ac2f3
            enc_key_id 11 \
0ac2f3
            erspan_opts 1:2:0:0/1:255:0:0 \
0ac2f3
            ip_proto udp \
0ac2f3
            action mirred egress redirect dev eth1
0ac2f3
      # tc -s filter show dev erspan1 parent ffff:
0ac2f3
0ac2f3
         filter protocol ip pref 49152 flower chain 0 handle 0x1
0ac2f3
           eth_type ipv4
0ac2f3
           ip_proto udp
0ac2f3
           enc_dst_ip 10.0.99.193
0ac2f3
           enc_src_ip 10.0.99.192
0ac2f3
           enc_key_id 11
0ac2f3
           erspan_opts 1:2:0:0/1:255:0:0
0ac2f3
           not_in_hw
0ac2f3
             action order 1: mirred (Egress Redirect to device eth1) stolen
0ac2f3
             index 1 ref 1 bind 1
0ac2f3
             Action statistics:
0ac2f3
             Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
0ac2f3
             backlog 0b 0p requeues 0
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-flower.8 |  13 ++++
0ac2f3
 tc/f_flower.c        | 171 +++++++++++++++++++++++++++++++++++++++++++
0ac2f3
 2 files changed, 184 insertions(+)
0ac2f3
0ac2f3
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
0ac2f3
index 0efacbfdf9a95..f41b0f7f1ef13 100644
0ac2f3
--- a/man/man8/tc-flower.8
0ac2f3
+++ b/man/man8/tc-flower.8
0ac2f3
@@ -85,6 +85,8 @@ flower \- flow based traffic control filter
0ac2f3
 .B geneve_opts
0ac2f3
 |
0ac2f3
 .B vxlan_opts
0ac2f3
+|
0ac2f3
+.B erspan_opts
0ac2f3
 }
0ac2f3
 .IR OPTIONS " | "
0ac2f3
 .BR ip_flags
0ac2f3
@@ -296,6 +298,8 @@ bits is assumed.
0ac2f3
 .BI geneve_opts " OPTIONS"
0ac2f3
 .TQ
0ac2f3
 .BI vxlan_opts " OPTIONS"
0ac2f3
+.TQ
0ac2f3
+.BI erspan_opts " OPTIONS"
0ac2f3
 Match on IP tunnel metadata. Key id
0ac2f3
 .I NUMBER
0ac2f3
 is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel).
0ac2f3
@@ -322,6 +326,15 @@ doesn't support multiple options, and it consists of a key followed by a slash
0ac2f3
 and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length
0ac2f3
 match. The option can be described in the form GBP/GBP_MASK, where GBP is
0ac2f3
 represented as a 32bit number.
0ac2f3
+erspan_opts
0ac2f3
+.I OPTIONS
0ac2f3
+doesn't support multiple options, and it consists of a key followed by a slash
0ac2f3
+and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length
0ac2f3
+match. The option can be described in the form
0ac2f3
+VERSION:INDEX:DIR:HWID/VERSION:INDEX_MASK:DIR_MASK:HWID_MASK, where VERSION is
0ac2f3
+represented as a 8bit number, INDEX as an 32bit number, DIR and HWID as a 8bit
0ac2f3
+number. Multiple options is not supported. Note INDEX/INDEX_MASK is used when
0ac2f3
+VERSION is 1, and DIR/DIR_MASK and HWID/HWID_MASK are used when VERSION is 2.
0ac2f3
 .TP
0ac2f3
 .BI ip_flags " IP_FLAGS"
0ac2f3
 .I IP_FLAGS
0ac2f3
diff --git a/tc/f_flower.c b/tc/f_flower.c
0ac2f3
index 09079cd2c2280..691541ec59d4c 100644
0ac2f3
--- a/tc/f_flower.c
0ac2f3
+++ b/tc/f_flower.c
0ac2f3
@@ -82,6 +82,7 @@ static void explain(void)
0ac2f3
 		"			enc_ttl MASKED-IP_TTL |\n"
0ac2f3
 		"			geneve_opts MASKED-OPTIONS |\n"
0ac2f3
 		"			vxlan_opts MASKED-OPTIONS |\n"
0ac2f3
+		"                       erspan_opts MASKED-OPTIONS |\n"
0ac2f3
 		"			ip_flags IP-FLAGS | \n"
0ac2f3
 		"			enc_dst_port [ port_number ] }\n"
0ac2f3
 		"	FILTERID := X:Y:Z\n"
0ac2f3
@@ -738,6 +739,84 @@ static int flower_parse_vxlan_opt(char *str, struct nlmsghdr *n)
0ac2f3
 	return 0;
0ac2f3
 }
0ac2f3
 
0ac2f3
+static int flower_parse_erspan_opt(char *str, struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	struct rtattr *nest;
0ac2f3
+	char *token;
0ac2f3
+	int i, err;
0ac2f3
+
0ac2f3
+	nest = addattr_nest(n, MAX_MSG,
0ac2f3
+			    TCA_FLOWER_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED);
0ac2f3
+
0ac2f3
+	i = 1;
0ac2f3
+	token = strsep(&str, ":");
0ac2f3
+	while (token) {
0ac2f3
+		switch (i) {
0ac2f3
+		case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER:
0ac2f3
+		{
0ac2f3
+			__u8 opt_type;
0ac2f3
+
0ac2f3
+			if (!strlen(token))
0ac2f3
+				break;
0ac2f3
+			err = get_u8(&opt_type, token, 0);
0ac2f3
+			if (err)
0ac2f3
+				return err;
0ac2f3
+
0ac2f3
+			addattr8(n, MAX_MSG, i, opt_type);
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+		case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX:
0ac2f3
+		{
0ac2f3
+			__be32 opt_index;
0ac2f3
+
0ac2f3
+			if (!strlen(token))
0ac2f3
+				break;
0ac2f3
+			err = get_be32(&opt_index, token, 0);
0ac2f3
+			if (err)
0ac2f3
+				return err;
0ac2f3
+
0ac2f3
+			addattr32(n, MAX_MSG, i, opt_index);
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+		case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR:
0ac2f3
+		{
0ac2f3
+			__u8 opt_type;
0ac2f3
+
0ac2f3
+			if (!strlen(token))
0ac2f3
+				break;
0ac2f3
+			err = get_u8(&opt_type, token, 0);
0ac2f3
+			if (err)
0ac2f3
+				return err;
0ac2f3
+
0ac2f3
+			addattr8(n, MAX_MSG, i, opt_type);
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+		case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID:
0ac2f3
+		{
0ac2f3
+			__u8 opt_type;
0ac2f3
+
0ac2f3
+			if (!strlen(token))
0ac2f3
+				break;
0ac2f3
+			err = get_u8(&opt_type, token, 0);
0ac2f3
+			if (err)
0ac2f3
+				return err;
0ac2f3
+
0ac2f3
+			addattr8(n, MAX_MSG, i, opt_type);
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+		default:
0ac2f3
+			fprintf(stderr, "Unknown \"geneve_opts\" type\n");
0ac2f3
+			return -1;
0ac2f3
+		}
0ac2f3
+
0ac2f3
+		token = strsep(&str, ":");
0ac2f3
+		i++;
0ac2f3
+	}
0ac2f3
+	addattr_nest_end(n, nest);
0ac2f3
+
0ac2f3
+	return 0;
0ac2f3
+}
0ac2f3
+
0ac2f3
 static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n)
0ac2f3
 {
0ac2f3
 	char *token;
0ac2f3
@@ -878,6 +957,49 @@ static int flower_parse_enc_opts_vxlan(char *str, struct nlmsghdr *n)
0ac2f3
 	return 0;
0ac2f3
 }
0ac2f3
 
0ac2f3
+static int flower_parse_enc_opts_erspan(char *str, struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	char key[XATTR_SIZE_MAX], mask[XATTR_SIZE_MAX];
0ac2f3
+	struct rtattr *nest;
0ac2f3
+	char *slash;
0ac2f3
+	int err;
0ac2f3
+
0ac2f3
+
0ac2f3
+	slash = strchr(str, '/');
0ac2f3
+	if (slash) {
0ac2f3
+		*slash++ = '\0';
0ac2f3
+		if (strlen(slash) > XATTR_SIZE_MAX)
0ac2f3
+			return -1;
0ac2f3
+		strcpy(mask, slash);
0ac2f3
+	} else {
0ac2f3
+		int index;
0ac2f3
+
0ac2f3
+		slash = strchr(str, ':');
0ac2f3
+		index = (int)(slash - str);
0ac2f3
+		memcpy(mask, str, index);
0ac2f3
+		strcpy(mask + index, ":0xffffffff:0xff:0xff");
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	if (strlen(str) > XATTR_SIZE_MAX)
0ac2f3
+		return -1;
0ac2f3
+	strcpy(key, str);
0ac2f3
+
0ac2f3
+	nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS | NLA_F_NESTED);
0ac2f3
+	err = flower_parse_erspan_opt(key, n);
0ac2f3
+	if (err)
0ac2f3
+		return err;
0ac2f3
+	addattr_nest_end(n, nest);
0ac2f3
+
0ac2f3
+	nest = addattr_nest(n, MAX_MSG,
0ac2f3
+			    TCA_FLOWER_KEY_ENC_OPTS_MASK | NLA_F_NESTED);
0ac2f3
+	err = flower_parse_erspan_opt(mask, n);
0ac2f3
+	if (err)
0ac2f3
+		return err;
0ac2f3
+	addattr_nest_end(n, nest);
0ac2f3
+
0ac2f3
+	return 0;
0ac2f3
+}
0ac2f3
+
0ac2f3
 static int flower_parse_opt(struct filter_util *qu, char *handle,
0ac2f3
 			    int argc, char **argv, struct nlmsghdr *n)
0ac2f3
 {
0ac2f3
@@ -1344,6 +1466,13 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
0ac2f3
 				fprintf(stderr, "Illegal \"vxlan_opts\"\n");
0ac2f3
 				return -1;
0ac2f3
 			}
0ac2f3
+		} else if (matches(*argv, "erspan_opts") == 0) {
0ac2f3
+			NEXT_ARG();
0ac2f3
+			ret = flower_parse_enc_opts_erspan(*argv, n);
0ac2f3
+			if (ret < 0) {
0ac2f3
+				fprintf(stderr, "Illegal \"erspan_opts\"\n");
0ac2f3
+				return -1;
0ac2f3
+			}
0ac2f3
 		} else if (matches(*argv, "action") == 0) {
0ac2f3
 			NEXT_ARG();
0ac2f3
 			ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n);
0ac2f3
@@ -1727,6 +1856,38 @@ static void flower_print_vxlan_opts(const char *name, struct rtattr *attr,
0ac2f3
 	sprintf(strbuf, "%u", gbp);
0ac2f3
 }
0ac2f3
 
0ac2f3
+static void flower_print_erspan_opts(const char *name, struct rtattr *attr,
0ac2f3
+				     char *strbuf)
0ac2f3
+{
0ac2f3
+	struct rtattr *tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1];
0ac2f3
+	__u8 ver, hwid, dir;
0ac2f3
+	__u32 idx;
0ac2f3
+
0ac2f3
+	parse_rtattr(tb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, RTA_DATA(attr),
0ac2f3
+		     RTA_PAYLOAD(attr));
0ac2f3
+	ver = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]);
0ac2f3
+	if (ver == 1) {
0ac2f3
+		idx = rta_getattr_be32(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]);
0ac2f3
+		hwid = 0;
0ac2f3
+		dir = 0;
0ac2f3
+	} else {
0ac2f3
+		idx = 0;
0ac2f3
+		hwid = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]);
0ac2f3
+		dir = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]);
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	open_json_array(PRINT_JSON, name);
0ac2f3
+	open_json_object(NULL);
0ac2f3
+	print_uint(PRINT_JSON, "ver", NULL, ver);
0ac2f3
+	print_uint(PRINT_JSON, "index", NULL, idx);
0ac2f3
+	print_uint(PRINT_JSON, "dir", NULL, dir);
0ac2f3
+	print_uint(PRINT_JSON, "hwid", NULL, hwid);
0ac2f3
+	close_json_object();
0ac2f3
+	close_json_array(PRINT_JSON, name);
0ac2f3
+
0ac2f3
+	sprintf(strbuf, "%u:%u:%u:%u", ver, idx, dir, hwid);
0ac2f3
+}
0ac2f3
+
0ac2f3
 static void flower_print_enc_parts(const char *name, const char *namefrm,
0ac2f3
 				   struct rtattr *attr, char *key, char *mask)
0ac2f3
 {
0ac2f3
@@ -1792,6 +1953,16 @@ static void flower_print_enc_opts(const char *name, struct rtattr *attr,
0ac2f3
 
0ac2f3
 		flower_print_enc_parts(name, "  vxlan_opts %s", attr, key,
0ac2f3
 				       msk);
0ac2f3
+	} else if (key_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN]) {
0ac2f3
+		flower_print_erspan_opts("erspan_opt_key",
0ac2f3
+				key_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN], key);
0ac2f3
+
0ac2f3
+		if (msk_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN])
0ac2f3
+			flower_print_erspan_opts("erspan_opt_mask",
0ac2f3
+				msk_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN], msk);
0ac2f3
+
0ac2f3
+		flower_print_enc_parts(name, "  erspan_opts %s", attr, key,
0ac2f3
+				       msk);
0ac2f3
 	}
0ac2f3
 
0ac2f3
 	free(msk);
0ac2f3
-- 
0ac2f3
2.26.2
0ac2f3