naccyde / rpms / iproute

Forked from rpms/iproute 9 months ago
Clone

Blame SOURCES/0044-tc-m_tunnel_key-Add-tunnel-option-support-to-act_tun.patch

7e752c
From d75736d332f6aa0fcd12352e2d2a5c1aa65c6464 Mon Sep 17 00:00:00 2001
7e752c
From: Phil Sutter <psutter@redhat.com>
7e752c
Date: Thu, 31 Jan 2019 17:13:07 +0100
7e752c
Subject: [PATCH] tc: m_tunnel_key: Add tunnel option support to act_tunnel_key
7e752c
7e752c
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1654761
7e752c
Upstream Status: iproute2.git commit 6217917a38268
7e752c
Conflicts: Context change due to previous backport of tos and ttl
7e752c
           support.
7e752c
7e752c
commit 6217917a382682d8e8a7ecdeb0c6626f701a0933
7e752c
Author: Simon Horman <simon.horman@netronome.com>
7e752c
Date:   Thu Jul 5 17:12:00 2018 -0700
7e752c
7e752c
    tc: m_tunnel_key: Add tunnel option support to act_tunnel_key
7e752c
7e752c
    Allow setting tunnel options using the act_tunnel_key action.
7e752c
7e752c
    Options are expressed as class:type:data and multiple options
7e752c
    may be listed using a comma delimiter.
7e752c
7e752c
     # ip link add name geneve0 type geneve dstport 0 external
7e752c
     # tc qdisc add dev eth0 ingress
7e752c
     # tc filter add dev eth0 protocol ip parent ffff: \
7e752c
         flower indev eth0 \
7e752c
            ip_proto udp \
7e752c
            action tunnel_key \
7e752c
                set src_ip 10.0.99.192 \
7e752c
                dst_ip 10.0.99.193 \
7e752c
                dst_port 6081 \
7e752c
                id 11 \
7e752c
                geneve_opts 0102:80:00800022,0102:80:00800022 \
7e752c
        action mirred egress redirect dev geneve0
7e752c
7e752c
    Signed-off-by: Simon Horman <simon.horman@netronome.com>
7e752c
    Signed-off-by: Pieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
7e752c
    Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
7e752c
    Signed-off-by: David Ahern <dsahern@gmail.com>
7e752c
---
7e752c
 man/man8/tc-tunnel_key.8 |  12 +++-
7e752c
 tc/m_tunnel_key.c        | 177 +++++++++++++++++++++++++++++++++++++++++++++++
7e752c
 2 files changed, 188 insertions(+), 1 deletion(-)
7e752c
7e752c
diff --git a/man/man8/tc-tunnel_key.8 b/man/man8/tc-tunnel_key.8
7e752c
index 71cee5b..1e09362 100644
7e752c
--- a/man/man8/tc-tunnel_key.8
7e752c
+++ b/man/man8/tc-tunnel_key.8
7e752c
@@ -66,7 +66,9 @@ and
7e752c
 .B dst_ip
7e752c
 options.
7e752c
 .B dst_port
7e752c
-is optional.
7e752c
+and
7e752c
+.B geneve_opts
7e752c
+are optional.
7e752c
 .RS
7e752c
 .TP
7e752c
 .B id
7e752c
@@ -81,6 +83,14 @@ Outer header destination IP address (IPv4 or IPv6)
7e752c
 .B dst_port
7e752c
 Outer header destination UDP port
7e752c
 .TP
7e752c
+.B geneve_opts
7e752c
+Geneve variable length options.
7e752c
+.B geneve_opts
7e752c
+is specified in the form CLASS:TYPE:DATA, where CLASS is represented as a
7e752c
+16bit hexadecimal value, TYPE as an 8bit hexadecimal value and DATA as a
7e752c
+variable length hexadecimal value. Additionally multiple options may be
7e752c
+listed using a comma delimiter.
7e752c
+.TP
7e752c
 .B tos
7e752c
 Outer header TOS
7e752c
 .TP
7e752c
diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
7e752c
index 8d0a8d1..e9e71e4 100644
7e752c
--- a/tc/m_tunnel_key.c
7e752c
+++ b/tc/m_tunnel_key.c
7e752c
@@ -29,6 +29,7 @@ static void explain(void)
7e752c
 		"src_ip <IP> (mandatory)\n"
7e752c
 		"dst_ip <IP> (mandatory)\n"
7e752c
 		"dst_port <UDP_PORT>\n"
7e752c
+		"geneve_opts <OPTIONS>\n"
7e752c
 		"csum | nocsum (default is \"csum\")\n");
7e752c
 }
7e752c
 
7e752c
@@ -81,6 +82,114 @@ static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n)
7e752c
 	return 0;
7e752c
 }
7e752c
 
7e752c
+static int tunnel_key_parse_be16(char *str, int base, int type,
7e752c
+				 struct nlmsghdr *n)
7e752c
+{
7e752c
+	int ret;
7e752c
+	__be16 value;
7e752c
+
7e752c
+	ret = get_be16(&value, str, base);
7e752c
+	if (ret)
7e752c
+		return ret;
7e752c
+
7e752c
+	addattr16(n, MAX_MSG, type, value);
7e752c
+
7e752c
+	return 0;
7e752c
+}
7e752c
+
7e752c
+static int tunnel_key_parse_u8(char *str, int base, int type,
7e752c
+			       struct nlmsghdr *n)
7e752c
+{
7e752c
+	int ret;
7e752c
+	__u8 value;
7e752c
+
7e752c
+	ret = get_u8(&value, str, base);
7e752c
+	if (ret)
7e752c
+		return ret;
7e752c
+
7e752c
+	addattr8(n, MAX_MSG, type, value);
7e752c
+
7e752c
+	return 0;
7e752c
+}
7e752c
+
7e752c
+static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
7e752c
+{
7e752c
+	char *token, *saveptr = NULL;
7e752c
+	struct rtattr *nest;
7e752c
+	int i, ret;
7e752c
+
7e752c
+	nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
7e752c
+
7e752c
+	token = strtok_r(str, ":", &saveptr);
7e752c
+	i = 1;
7e752c
+	while (token) {
7e752c
+		switch (i) {
7e752c
+		case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
7e752c
+		{
7e752c
+			ret = tunnel_key_parse_be16(token, 16, i, n);
7e752c
+			if (ret)
7e752c
+				return ret;
7e752c
+			break;
7e752c
+		}
7e752c
+		case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
7e752c
+		{
7e752c
+			ret = tunnel_key_parse_u8(token, 16, i, n);
7e752c
+			if (ret)
7e752c
+				return ret;
7e752c
+			break;
7e752c
+		}
7e752c
+		case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
7e752c
+		{
7e752c
+			size_t token_len = strlen(token);
7e752c
+			uint8_t *opts;
7e752c
+
7e752c
+			opts = malloc(token_len / 2);
7e752c
+			if (!opts)
7e752c
+				return -1;
7e752c
+			if (hex2mem(token, opts, token_len / 2) < 0) {
7e752c
+				free(opts);
7e752c
+				return -1;
7e752c
+			}
7e752c
+			addattr_l(n, MAX_MSG, i, opts, token_len / 2);
7e752c
+			free(opts);
7e752c
+
7e752c
+			break;
7e752c
+		}
7e752c
+		default:
7e752c
+			return -1;
7e752c
+		}
7e752c
+
7e752c
+		token = strtok_r(NULL, ":", &saveptr);
7e752c
+		i++;
7e752c
+	}
7e752c
+
7e752c
+	addattr_nest_end(n, nest);
7e752c
+
7e752c
+	return 0;
7e752c
+}
7e752c
+
7e752c
+static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
7e752c
+{
7e752c
+	char *token, *saveptr = NULL;
7e752c
+	struct rtattr *nest;
7e752c
+	int ret;
7e752c
+
7e752c
+	nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS);
7e752c
+
7e752c
+	token = strtok_r(str, ",", &saveptr);
7e752c
+	while (token) {
7e752c
+		ret = tunnel_key_parse_geneve_opt(token, n);
7e752c
+		if (ret)
7e752c
+			return ret;
7e752c
+
7e752c
+		token = strtok_r(NULL, ",", &saveptr);
7e752c
+	}
7e752c
+
7e752c
+	addattr_nest_end(n, nest);
7e752c
+
7e752c
+	return 0;
7e752c
+}
7e752c
+
7e752c
 static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
7e752c
 {
7e752c
 	int ret;
7e752c
@@ -173,6 +282,13 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
7e752c
 				fprintf(stderr, "Illegal \"dst port\"\n");
7e752c
 				return -1;
7e752c
 			}
7e752c
+		} else if (matches(*argv, "geneve_opts") == 0) {
7e752c
+			NEXT_ARG();
7e752c
+
7e752c
+			if (tunnel_key_parse_geneve_opts(*argv, n)) {
7e752c
+				fprintf(stderr, "Illegal \"geneve_opts\"\n");
7e752c
+				return -1;
7e752c
+			}
7e752c
 		} else if (matches(*argv, "tos") == 0) {
7e752c
 			NEXT_ARG();
7e752c
 			ret = tunnel_key_parse_tos_ttl(*argv,
7e752c
@@ -292,6 +408,65 @@ static void tunnel_key_print_flag(FILE *f, const char *name_on,
7e752c
 		     rta_getattr_u8(attr) ? name_on : name_off);
7e752c
 }
7e752c
 
7e752c
+static void tunnel_key_print_geneve_options(const char *name,
7e752c
+					    struct rtattr *attr)
7e752c
+{
7e752c
+	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1];
7e752c
+	struct rtattr *i = RTA_DATA(attr);
7e752c
+	int ii, data_len = 0, offset = 0;
7e752c
+	int rem = RTA_PAYLOAD(attr);
7e752c
+	char strbuf[rem * 2 + 1];
7e752c
+	char data[rem * 2 + 1];
7e752c
+	uint8_t data_r[rem];
7e752c
+	uint16_t clss;
7e752c
+	uint8_t type;
7e752c
+
7e752c
+	open_json_array(PRINT_JSON, name);
7e752c
+	print_string(PRINT_FP, name, "\n\t%s ", "geneve_opt");
7e752c
+
7e752c
+	while (rem) {
7e752c
+		parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem);
7e752c
+		clss = rta_getattr_be16(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]);
7e752c
+		type = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]);
7e752c
+		data_len = RTA_PAYLOAD(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
7e752c
+		hexstring_n2a(RTA_DATA(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]),
7e752c
+			      data_len, data, sizeof(data));
7e752c
+		hex2mem(data, data_r, data_len);
7e752c
+		offset += data_len + 20;
7e752c
+		rem -= data_len + 20;
7e752c
+		i = RTA_DATA(attr) + offset;
7e752c
+
7e752c
+		open_json_object(NULL);
7e752c
+		print_uint(PRINT_JSON, "class", NULL, clss);
7e752c
+		print_uint(PRINT_JSON, "type", NULL, type);
7e752c
+		open_json_array(PRINT_JSON, "data");
7e752c
+		for (ii = 0; ii < data_len; ii++)
7e752c
+			print_uint(PRINT_JSON, NULL, NULL, data_r[ii]);
7e752c
+		close_json_array(PRINT_JSON, "data");
7e752c
+		close_json_object();
7e752c
+
7e752c
+		sprintf(strbuf, "%04x:%02x:%s", clss, type, data);
7e752c
+		if (rem)
7e752c
+			print_string(PRINT_FP, NULL, "%s,", strbuf);
7e752c
+		else
7e752c
+			print_string(PRINT_FP, NULL, "%s", strbuf);
7e752c
+	}
7e752c
+
7e752c
+	close_json_array(PRINT_JSON, name);
7e752c
+}
7e752c
+
7e752c
+static void tunnel_key_print_key_opt(const char *name, struct rtattr *attr)
7e752c
+{
7e752c
+	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
7e752c
+
7e752c
+	if (!attr)
7e752c
+		return;
7e752c
+
7e752c
+	parse_rtattr_nested(tb, TCA_TUNNEL_KEY_ENC_OPTS_MAX, attr);
7e752c
+	tunnel_key_print_geneve_options(name,
7e752c
+					tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]);
7e752c
+}
7e752c
+
7e752c
 static void tunnel_key_print_tos_ttl(FILE *f, char *name,
7e752c
 				     struct rtattr *attr)
7e752c
 {
7e752c
@@ -346,6 +521,8 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
7e752c
 					tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
7e752c
 		tunnel_key_print_dst_port(f, "dst_port",
7e752c
 					  tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
7e752c
+		tunnel_key_print_key_opt("geneve_opts",
7e752c
+					 tb[TCA_TUNNEL_KEY_ENC_OPTS]);
7e752c
 		tunnel_key_print_flag(f, "nocsum", "csum",
7e752c
 				      tb[TCA_TUNNEL_KEY_NO_CSUM]);
7e752c
 		tunnel_key_print_tos_ttl(f, "tos",
7e752c
-- 
7e752c
1.8.3.1
7e752c