Blame SOURCES/0026-iproute_lwtunnel-add-options-support-for-erspan-meta.patch

07a51b
From 3628115b53f7b693f623638fb5ec71bc292a3a00 Mon Sep 17 00:00:00 2001
07a51b
From: Andrea Claudi <aclaudi@redhat.com>
07a51b
Date: Thu, 4 Jun 2020 21:43:01 +0200
07a51b
Subject: [PATCH] iproute_lwtunnel: add options support for erspan metadata
07a51b
07a51b
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
07a51b
Upstream Status: unknown commit 39fa047938fbe
07a51b
07a51b
commit 39fa047938fbef6cd08687b0daa4d86afbfdc61c
07a51b
Author: Xin Long <lucien.xin@gmail.com>
07a51b
Date:   Mon Apr 27 18:27:47 2020 +0800
07a51b
07a51b
    iproute_lwtunnel: add options support for erspan metadata
07a51b
07a51b
    This patch is to add LWTUNNEL_IP_OPTS_ERSPAN's parse and print to implement
07a51b
    erspan options support in iproute_lwtunnel.
07a51b
07a51b
    Option is expressed as version:index:dir:hwid, dir and hwid will be parsed
07a51b
    when version is 2, while index will be parsed when version is 1. All of
07a51b
    these are numbers. erspan doesn't support multiple options.
07a51b
07a51b
    With this patch, users can add and dump erspan options like:
07a51b
07a51b
      # ip netns add a
07a51b
      # ip netns add b
07a51b
      # ip -n a link add eth0 type veth peer name eth0 netns b
07a51b
      # ip -n a link set eth0 up
07a51b
      # ip -n b link set eth0 up
07a51b
      # ip -n a addr add 10.1.0.1/24 dev eth0
07a51b
      # ip -n b addr add 10.1.0.2/24 dev eth0
07a51b
      # ip -n b link add erspan1 type erspan key 1 seq erspan 123 \
07a51b
        local 10.1.0.2 remote 10.1.0.1
07a51b
      # ip -n b addr add 1.1.1.1/24 dev erspan1
07a51b
      # ip -n b link set erspan1 up
07a51b
      # ip -n b route add 2.1.1.0/24 dev erspan1
07a51b
      # ip -n a link add erspan1 type erspan key 1 seq local 10.1.0.1 external
07a51b
      # ip -n a addr add 2.1.1.1/24 dev erspan1
07a51b
      # ip -n a link set erspan1 up
07a51b
      # ip -n a route add 1.1.1.0/24 encap ip id 1 \
07a51b
        erspan_opts 2:123:1:2 dst 10.1.0.2 dev erspan1
07a51b
      # ip -n a route show
07a51b
      # ip netns exec a ping 1.1.1.1 -c 1
07a51b
07a51b
       1.1.1.0/24  encap ip id 1 src 0.0.0.0 dst 10.1.0.2 ttl 0 tos 0
07a51b
         erspan_opts 2:0:1:2 dev erspan1 scope link
07a51b
07a51b
       PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
07a51b
       64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.124 ms
07a51b
07a51b
    v1->v2:
07a51b
      - improve the changelog.
07a51b
      - use PRINT_ANY to support dumping with json format.
07a51b
    v2->v3:
07a51b
      - implement proper JSON object for opts instead of just bunch of strings.
07a51b
    v3->v4:
07a51b
      - keep the same format between input and output, json and non json.
07a51b
      - print version, index, dir and hwid as uint.
07a51b
07a51b
    Signed-off-by: Xin Long <lucien.xin@gmail.com>
07a51b
    Signed-off-by: David Ahern <dsahern@gmail.com>
07a51b
---
07a51b
 ip/iproute_lwtunnel.c | 140 ++++++++++++++++++++++++++++++++++++++++++
07a51b
 1 file changed, 140 insertions(+)
07a51b
07a51b
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
07a51b
index 17514dcad9219..7e145768c111f 100644
07a51b
--- a/ip/iproute_lwtunnel.c
07a51b
+++ b/ip/iproute_lwtunnel.c
07a51b
@@ -350,6 +350,38 @@ static void lwtunnel_print_vxlan_opts(struct rtattr *attr)
07a51b
 	close_json_array(PRINT_JSON, name);
07a51b
 }
07a51b
 
07a51b
+static void lwtunnel_print_erspan_opts(struct rtattr *attr)
07a51b
+{
07a51b
+	struct rtattr *tb[LWTUNNEL_IP_OPT_ERSPAN_MAX + 1];
07a51b
+	struct rtattr *i = RTA_DATA(attr);
07a51b
+	char *name = "erspan_opts";
07a51b
+	__u8 ver, hwid, dir;
07a51b
+	__u32 idx;
07a51b
+
07a51b
+	parse_rtattr(tb, LWTUNNEL_IP_OPT_ERSPAN_MAX, i, RTA_PAYLOAD(attr));
07a51b
+	ver = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_VER]);
07a51b
+	if (ver == 1) {
07a51b
+		idx = rta_getattr_be32(tb[LWTUNNEL_IP_OPT_ERSPAN_INDEX]);
07a51b
+		dir = 0;
07a51b
+		hwid = 0;
07a51b
+	} else {
07a51b
+		idx = 0;
07a51b
+		dir = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_DIR]);
07a51b
+		hwid = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_HWID]);
07a51b
+	}
07a51b
+
07a51b
+	print_nl();
07a51b
+	print_string(PRINT_FP, name, "\t%s ", name);
07a51b
+	open_json_array(PRINT_JSON, name);
07a51b
+	open_json_object(NULL);
07a51b
+	print_uint(PRINT_ANY, "ver", "%u", ver);
07a51b
+	print_uint(PRINT_ANY, "index", ":%u", idx);
07a51b
+	print_uint(PRINT_ANY, "dir", ":%u", dir);
07a51b
+	print_uint(PRINT_ANY, "hwid", ":%u ", hwid);
07a51b
+	close_json_object();
07a51b
+	close_json_array(PRINT_JSON, name);
07a51b
+}
07a51b
+
07a51b
 static void lwtunnel_print_opts(struct rtattr *attr)
07a51b
 {
07a51b
 	struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1];
07a51b
@@ -359,6 +391,8 @@ static void lwtunnel_print_opts(struct rtattr *attr)
07a51b
 		lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]);
07a51b
 	else if (tb_opt[LWTUNNEL_IP_OPTS_VXLAN])
07a51b
 		lwtunnel_print_vxlan_opts(tb_opt[LWTUNNEL_IP_OPTS_VXLAN]);
07a51b
+	else if (tb_opt[LWTUNNEL_IP_OPTS_ERSPAN])
07a51b
+		lwtunnel_print_erspan_opts(tb_opt[LWTUNNEL_IP_OPTS_ERSPAN]);
07a51b
 }
07a51b
 
07a51b
 static void print_encap_ip(FILE *fp, struct rtattr *encap)
07a51b
@@ -973,6 +1007,82 @@ static int lwtunnel_parse_vxlan_opts(char *str, size_t len, struct rtattr *rta)
07a51b
 	return 0;
07a51b
 }
07a51b
 
07a51b
+static int lwtunnel_parse_erspan_opts(char *str, size_t len, struct rtattr *rta)
07a51b
+{
07a51b
+	struct rtattr *nest;
07a51b
+	char *token;
07a51b
+	int i, err;
07a51b
+
07a51b
+	nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_ERSPAN | NLA_F_NESTED);
07a51b
+	i = 1;
07a51b
+	token = strsep(&str, ":");
07a51b
+	while (token) {
07a51b
+		switch (i) {
07a51b
+		case LWTUNNEL_IP_OPT_ERSPAN_VER:
07a51b
+		{
07a51b
+			__u8 opt_type;
07a51b
+
07a51b
+			if (!strlen(token))
07a51b
+				break;
07a51b
+			err = get_u8(&opt_type, token, 0);
07a51b
+			if (err)
07a51b
+				return err;
07a51b
+
07a51b
+			rta_addattr8(rta, len, i, opt_type);
07a51b
+			break;
07a51b
+		}
07a51b
+		case LWTUNNEL_IP_OPT_ERSPAN_INDEX:
07a51b
+		{
07a51b
+			__be32 opt_class;
07a51b
+
07a51b
+			if (!strlen(token))
07a51b
+				break;
07a51b
+			err = get_be32(&opt_class, token, 0);
07a51b
+			if (err)
07a51b
+				return err;
07a51b
+
07a51b
+			rta_addattr32(rta, len, i, opt_class);
07a51b
+			break;
07a51b
+		}
07a51b
+		case LWTUNNEL_IP_OPT_ERSPAN_DIR:
07a51b
+		{
07a51b
+			__u8 opt_type;
07a51b
+
07a51b
+			if (!strlen(token))
07a51b
+				break;
07a51b
+			err = get_u8(&opt_type, token, 0);
07a51b
+			if (err)
07a51b
+				return err;
07a51b
+
07a51b
+			rta_addattr8(rta, len, i, opt_type);
07a51b
+			break;
07a51b
+		}
07a51b
+		case LWTUNNEL_IP_OPT_ERSPAN_HWID:
07a51b
+		{
07a51b
+			__u8 opt_type;
07a51b
+
07a51b
+			if (!strlen(token))
07a51b
+				break;
07a51b
+			err = get_u8(&opt_type, token, 0);
07a51b
+			if (err)
07a51b
+				return err;
07a51b
+
07a51b
+			rta_addattr8(rta, len, i, opt_type);
07a51b
+			break;
07a51b
+		}
07a51b
+		default:
07a51b
+			fprintf(stderr, "Unknown \"geneve_opts\" type\n");
07a51b
+			return -1;
07a51b
+		}
07a51b
+
07a51b
+		token = strsep(&str, ":");
07a51b
+		i++;
07a51b
+	}
07a51b
+
07a51b
+	rta_nest_end(rta, nest);
07a51b
+	return 0;
07a51b
+}
07a51b
+
07a51b
 static int parse_encap_ip(struct rtattr *rta, size_t len,
07a51b
 			  int *argcp, char ***argvp)
07a51b
 {
07a51b
@@ -1059,6 +1169,21 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
07a51b
 				invarg("\"vxlan_opts\" value is invalid\n",
07a51b
 				       *argv);
07a51b
 			rta_nest_end(rta, nest);
07a51b
+		} else if (strcmp(*argv, "erspan_opts") == 0) {
07a51b
+			struct rtattr *nest;
07a51b
+
07a51b
+			if (opts_ok++)
07a51b
+				duparg2("opts", *argv);
07a51b
+
07a51b
+			NEXT_ARG();
07a51b
+
07a51b
+			nest = rta_nest(rta, len,
07a51b
+					LWTUNNEL_IP_OPTS | NLA_F_NESTED);
07a51b
+			ret = lwtunnel_parse_erspan_opts(*argv, len, rta);
07a51b
+			if (ret)
07a51b
+				invarg("\"erspan_opts\" value is invalid\n",
07a51b
+				       *argv);
07a51b
+			rta_nest_end(rta, nest);
07a51b
 		} else if (strcmp(*argv, "key") == 0) {
07a51b
 			if (key_ok++)
07a51b
 				duparg2("key", *argv);
07a51b
@@ -1258,6 +1383,21 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
07a51b
 				invarg("\"vxlan_opts\" value is invalid\n",
07a51b
 				       *argv);
07a51b
 			rta_nest_end(rta, nest);
07a51b
+		} else if (strcmp(*argv, "erspan_opts") == 0) {
07a51b
+			struct rtattr *nest;
07a51b
+
07a51b
+			if (opts_ok++)
07a51b
+				duparg2("opts", *argv);
07a51b
+
07a51b
+			NEXT_ARG();
07a51b
+
07a51b
+			nest = rta_nest(rta, len,
07a51b
+					LWTUNNEL_IP_OPTS | NLA_F_NESTED);
07a51b
+			ret = lwtunnel_parse_erspan_opts(*argv, len, rta);
07a51b
+			if (ret)
07a51b
+				invarg("\"erspan_opts\" value is invalid\n",
07a51b
+				       *argv);
07a51b
+			rta_nest_end(rta, nest);
07a51b
 		} else if (strcmp(*argv, "key") == 0) {
07a51b
 			if (key_ok++)
07a51b
 				duparg2("key", *argv);
07a51b
-- 
07a51b
2.26.2
07a51b