naccyde / rpms / iproute

Forked from rpms/iproute 9 months ago
Clone

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

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