|
|
359b1d |
From c6f909bd0f40c58f39f857e1c57638cb41241fa2 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 geneve metadata
|
|
|
359b1d |
|
|
|
359b1d |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
|
|
|
359b1d |
Upstream Status: unknown commit ca7614d4c6f45
|
|
|
359b1d |
|
|
|
359b1d |
commit ca7614d4c6f456187d831a8202bb4a8559a72f8b
|
|
|
359b1d |
Author: Xin Long <lucien.xin@gmail.com>
|
|
|
359b1d |
Date: Mon Apr 27 18:27:45 2020 +0800
|
|
|
359b1d |
|
|
|
359b1d |
iproute_lwtunnel: add options support for geneve metadata
|
|
|
359b1d |
|
|
|
359b1d |
This patch is to add LWTUNNEL_IP(6)_OPTS and LWTUNNEL_IP_OPTS_GENEVE's
|
|
|
359b1d |
parse and print to implement geneve options support in iproute_lwtunnel.
|
|
|
359b1d |
|
|
|
359b1d |
Options are expressed as class:type:data and multiple options may be
|
|
|
359b1d |
listed using a comma delimiter, class and type are numbers and data
|
|
|
359b1d |
is a hex string.
|
|
|
359b1d |
|
|
|
359b1d |
With this patch, users can add and dump geneve 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; 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 geneve1 type geneve id 1 remote 10.1.0.1 ttl 64
|
|
|
359b1d |
# ip -n b addr add 1.1.1.1/24 dev geneve1
|
|
|
359b1d |
# ip -n b link set geneve1 up
|
|
|
359b1d |
# ip -n b route add 2.1.1.0/24 dev geneve1
|
|
|
359b1d |
# ip -n a link add geneve1 type geneve external
|
|
|
359b1d |
# ip -n a addr add 2.1.1.1/24 dev geneve1
|
|
|
359b1d |
# ip -n a link set geneve1 up
|
|
|
359b1d |
# ip -n a route add 1.1.1.0/24 encap ip id 1 geneve_opts \
|
|
|
359b1d |
1:1:1212121234567890,1:1:1212121234567890,1:1:1212121234567890 \
|
|
|
359b1d |
dst 10.1.0.2 dev geneve1
|
|
|
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 |
geneve_opts 1:1:1212121234567890,1:1:1212121234567890 ...
|
|
|
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.079 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 array 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 class and type as uint and print data as hex string.
|
|
|
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 | 174 +++++++++++++++++++++++++++++++++++++++++-
|
|
|
359b1d |
1 file changed, 172 insertions(+), 2 deletions(-)
|
|
|
359b1d |
|
|
|
359b1d |
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
|
|
|
359b1d |
index 60f34a32a6e5b..76d906c47c44f 100644
|
|
|
359b1d |
--- a/ip/iproute_lwtunnel.c
|
|
|
359b1d |
+++ b/ip/iproute_lwtunnel.c
|
|
|
359b1d |
@@ -291,6 +291,54 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap)
|
|
|
359b1d |
rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
|
|
|
359b1d |
}
|
|
|
359b1d |
|
|
|
359b1d |
+static void lwtunnel_print_geneve_opts(struct rtattr *attr)
|
|
|
359b1d |
+{
|
|
|
359b1d |
+ struct rtattr *tb[LWTUNNEL_IP_OPT_GENEVE_MAX + 1];
|
|
|
359b1d |
+ struct rtattr *i = RTA_DATA(attr);
|
|
|
359b1d |
+ int rem = RTA_PAYLOAD(attr);
|
|
|
359b1d |
+ char *name = "geneve_opts";
|
|
|
359b1d |
+ int data_len, offset = 0;
|
|
|
359b1d |
+ char data[rem * 2 + 1];
|
|
|
359b1d |
+ __u16 class;
|
|
|
359b1d |
+ __u8 type;
|
|
|
359b1d |
+
|
|
|
359b1d |
+ print_nl();
|
|
|
359b1d |
+ print_string(PRINT_FP, name, "\t%s ", name);
|
|
|
359b1d |
+ open_json_array(PRINT_JSON, name);
|
|
|
359b1d |
+
|
|
|
359b1d |
+ while (rem) {
|
|
|
359b1d |
+ parse_rtattr(tb, LWTUNNEL_IP_OPT_GENEVE_MAX, i, rem);
|
|
|
359b1d |
+ class = rta_getattr_be16(tb[LWTUNNEL_IP_OPT_GENEVE_CLASS]);
|
|
|
359b1d |
+ type = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_GENEVE_TYPE]);
|
|
|
359b1d |
+ data_len = RTA_PAYLOAD(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]);
|
|
|
359b1d |
+ hexstring_n2a(RTA_DATA(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]),
|
|
|
359b1d |
+ data_len, data, sizeof(data));
|
|
|
359b1d |
+ offset += data_len + 20;
|
|
|
359b1d |
+ rem -= data_len + 20;
|
|
|
359b1d |
+ i = RTA_DATA(attr) + offset;
|
|
|
359b1d |
+
|
|
|
359b1d |
+ open_json_object(NULL);
|
|
|
359b1d |
+ print_uint(PRINT_ANY, "class", "%u", class);
|
|
|
359b1d |
+ print_uint(PRINT_ANY, "type", ":%u", type);
|
|
|
359b1d |
+ if (rem)
|
|
|
359b1d |
+ print_string(PRINT_ANY, "data", ":%s,", data);
|
|
|
359b1d |
+ else
|
|
|
359b1d |
+ print_string(PRINT_ANY, "data", ":%s ", data);
|
|
|
359b1d |
+ close_json_object();
|
|
|
359b1d |
+ }
|
|
|
359b1d |
+
|
|
|
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 |
+
|
|
|
359b1d |
+ parse_rtattr_nested(tb_opt, LWTUNNEL_IP_OPTS_MAX, attr);
|
|
|
359b1d |
+ if (tb_opt[LWTUNNEL_IP_OPTS_GENEVE])
|
|
|
359b1d |
+ lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]);
|
|
|
359b1d |
+}
|
|
|
359b1d |
+
|
|
|
359b1d |
static void print_encap_ip(FILE *fp, struct rtattr *encap)
|
|
|
359b1d |
{
|
|
|
359b1d |
struct rtattr *tb[LWTUNNEL_IP_MAX+1];
|
|
|
359b1d |
@@ -329,6 +377,9 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap)
|
|
|
359b1d |
if (flags & TUNNEL_SEQ)
|
|
|
359b1d |
print_bool(PRINT_ANY, "seq", "seq ", true);
|
|
|
359b1d |
}
|
|
|
359b1d |
+
|
|
|
359b1d |
+ if (tb[LWTUNNEL_IP_OPTS])
|
|
|
359b1d |
+ lwtunnel_print_opts(tb[LWTUNNEL_IP_OPTS]);
|
|
|
359b1d |
}
|
|
|
359b1d |
|
|
|
359b1d |
static void print_encap_ila(FILE *fp, struct rtattr *encap)
|
|
|
359b1d |
@@ -401,6 +452,9 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap)
|
|
|
359b1d |
if (flags & TUNNEL_SEQ)
|
|
|
359b1d |
print_bool(PRINT_ANY, "seq", "seq ", true);
|
|
|
359b1d |
}
|
|
|
359b1d |
+
|
|
|
359b1d |
+ if (tb[LWTUNNEL_IP6_OPTS])
|
|
|
359b1d |
+ lwtunnel_print_opts(tb[LWTUNNEL_IP6_OPTS]);
|
|
|
359b1d |
}
|
|
|
359b1d |
|
|
|
359b1d |
static void print_encap_bpf(FILE *fp, struct rtattr *encap)
|
|
|
359b1d |
@@ -795,11 +849,97 @@ static int parse_encap_mpls(struct rtattr *rta, size_t len,
|
|
|
359b1d |
return 0;
|
|
|
359b1d |
}
|
|
|
359b1d |
|
|
|
359b1d |
+static int lwtunnel_parse_geneve_opt(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_GENEVE | NLA_F_NESTED);
|
|
|
359b1d |
+ i = 1;
|
|
|
359b1d |
+ token = strsep(&str, ":");
|
|
|
359b1d |
+ while (token) {
|
|
|
359b1d |
+ switch (i) {
|
|
|
359b1d |
+ case LWTUNNEL_IP_OPT_GENEVE_CLASS:
|
|
|
359b1d |
+ {
|
|
|
359b1d |
+ __be16 opt_class;
|
|
|
359b1d |
+
|
|
|
359b1d |
+ if (!strlen(token))
|
|
|
359b1d |
+ break;
|
|
|
359b1d |
+ err = get_be16(&opt_class, token, 0);
|
|
|
359b1d |
+ if (err)
|
|
|
359b1d |
+ return err;
|
|
|
359b1d |
+
|
|
|
359b1d |
+ rta_addattr16(rta, len, i, opt_class);
|
|
|
359b1d |
+ break;
|
|
|
359b1d |
+ }
|
|
|
359b1d |
+ case LWTUNNEL_IP_OPT_GENEVE_TYPE:
|
|
|
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_GENEVE_DATA:
|
|
|
359b1d |
+ {
|
|
|
359b1d |
+ size_t token_len = strlen(token);
|
|
|
359b1d |
+ __u8 *opts;
|
|
|
359b1d |
+
|
|
|
359b1d |
+ if (!token_len)
|
|
|
359b1d |
+ break;
|
|
|
359b1d |
+ opts = malloc(token_len / 2);
|
|
|
359b1d |
+ if (!opts)
|
|
|
359b1d |
+ return -1;
|
|
|
359b1d |
+ if (hex2mem(token, opts, token_len / 2) < 0) {
|
|
|
359b1d |
+ free(opts);
|
|
|
359b1d |
+ return -1;
|
|
|
359b1d |
+ }
|
|
|
359b1d |
+ rta_addattr_l(rta, len, i, opts, token_len / 2);
|
|
|
359b1d |
+ free(opts);
|
|
|
359b1d |
+
|
|
|
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 |
+ rta_nest_end(rta, nest);
|
|
|
359b1d |
+
|
|
|
359b1d |
+ return 0;
|
|
|
359b1d |
+}
|
|
|
359b1d |
+
|
|
|
359b1d |
+static int lwtunnel_parse_geneve_opts(char *str, size_t len, struct rtattr *rta)
|
|
|
359b1d |
+{
|
|
|
359b1d |
+ char *token;
|
|
|
359b1d |
+ int err;
|
|
|
359b1d |
+
|
|
|
359b1d |
+ token = strsep(&str, ",");
|
|
|
359b1d |
+ while (token) {
|
|
|
359b1d |
+ err = lwtunnel_parse_geneve_opt(token, len, rta);
|
|
|
359b1d |
+ if (err)
|
|
|
359b1d |
+ return err;
|
|
|
359b1d |
+
|
|
|
359b1d |
+ token = strsep(&str, ",");
|
|
|
359b1d |
+ }
|
|
|
359b1d |
+
|
|
|
359b1d |
+ return 0;
|
|
|
359b1d |
+}
|
|
|
359b1d |
+
|
|
|
359b1d |
static int parse_encap_ip(struct rtattr *rta, size_t len,
|
|
|
359b1d |
int *argcp, char ***argvp)
|
|
|
359b1d |
{
|
|
|
359b1d |
int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
|
|
|
359b1d |
- int key_ok = 0, csum_ok = 0, seq_ok = 0;
|
|
|
359b1d |
+ int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
|
|
|
359b1d |
char **argv = *argvp;
|
|
|
359b1d |
int argc = *argcp;
|
|
|
359b1d |
int ret = 0;
|
|
|
359b1d |
@@ -851,6 +991,21 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
|
|
|
359b1d |
if (get_u8(&ttl, *argv, 0))
|
|
|
359b1d |
invarg("\"ttl\" value is invalid\n", *argv);
|
|
|
359b1d |
ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
|
|
|
359b1d |
+ } else if (strcmp(*argv, "geneve_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_geneve_opts(*argv, len, rta);
|
|
|
359b1d |
+ if (ret)
|
|
|
359b1d |
+ invarg("\"geneve_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 |
@@ -966,7 +1121,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
359b1d |
int *argcp, char ***argvp)
|
|
|
359b1d |
{
|
|
|
359b1d |
int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
|
|
|
359b1d |
- int key_ok = 0, csum_ok = 0, seq_ok = 0;
|
|
|
359b1d |
+ int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
|
|
|
359b1d |
char **argv = *argvp;
|
|
|
359b1d |
int argc = *argcp;
|
|
|
359b1d |
int ret = 0;
|
|
|
359b1d |
@@ -1020,6 +1175,21 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
359b1d |
*argv);
|
|
|
359b1d |
ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
|
|
|
359b1d |
hoplimit);
|
|
|
359b1d |
+ } else if (strcmp(*argv, "geneve_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_geneve_opts(*argv, len, rta);
|
|
|
359b1d |
+ if (ret)
|
|
|
359b1d |
+ invarg("\"geneve_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 |
|