[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <93e7cebfeda666b17c6a1b2bb8b5065bdab4814c.1580708369.git.lucien.xin@gmail.com>
Date: Mon, 3 Feb 2020 13:39:52 +0800
From: Xin Long <lucien.xin@...il.com>
To: network dev <netdev@...r.kernel.org>, stephen@...workplumber.org
Cc: Simon Horman <simon.horman@...ronome.com>,
Pieter Jansen van Vuuren
<pieter.jansenvanvuuren@...ronome.com>
Subject: [PATCH iproute2-next 1/7] iproute_lwtunnel: add options support for geneve metadata
This patch is to add LWTUNNEL_IP(6)_OPTS and LWTUNNEL_IP_OPTS_GENEVE's
parse and print to implement geneve options support in iproute_lwtunnel.
Options are expressed as class:type:data and multiple options may be
listed using a comma delimiter.
With this patch, users can add and dump geneve options like:
# ip net d a; ip net d b; ip net a a; ip net a b
# ip -n a l a eth0 type veth peer name eth0 netns b
# ip -n a l s eth0 up; ip -n b link set eth0 up
# ip -n a a a 10.1.0.1/24 dev eth0; ip -n b a a 10.1.0.2/24 dev eth0
# ip -n b l a geneve1 type geneve id 1 remote 10.1.0.1 ttl 64
# ip -n b a a 1.1.1.1/24 dev geneve1; ip -n b l s geneve1 up
# ip -n b r a 2.1.1.0/24 dev geneve1
# ip -n a l a geneve1 type geneve external
# ip -n a a a 2.1.1.1/24 dev geneve1; ip -n a l s geneve1 up
# ip -n a r a 1.1.1.0/24 encap ip id 1 geneve_opts \
1:1:1212121234567890,1:1:1212121234567890,1:1:1212121234567890 \
dst 10.1.0.2 dev geneve1
# ip -n a r s; echo ''; ip net exec a ping 1.1.1.1 -c 1
1.1.1.0/24 encap ip id 1 src 0.0.0.0 dst 10.1.0.2 ttl 0 tos 0
geneve_opts 0001:01:1212121234567890,0001:01:1212121234567890 ...
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.079 ms
Signed-off-by: Xin Long <lucien.xin@...il.com>
---
ip/iproute_lwtunnel.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 168 insertions(+), 2 deletions(-)
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
index 0d7d714..ba3c9e1 100644
--- a/ip/iproute_lwtunnel.c
+++ b/ip/iproute_lwtunnel.c
@@ -294,6 +294,50 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap)
rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
}
+static void lwtunnel_print_geneve_opts(struct rtattr *attr, char *opt)
+{
+ struct rtattr *tb[LWTUNNEL_IP_OPT_GENEVE_MAX + 1];
+ int data_len, offset = 0, slen = 0;
+ struct rtattr *i = RTA_DATA(attr);
+ int rem = RTA_PAYLOAD(attr);
+ char data[rem * 2 + 1];
+ __u16 class;
+ __u8 type;
+
+ while (rem) {
+ parse_rtattr(tb, LWTUNNEL_IP_OPT_GENEVE_MAX, i, rem);
+ class = rta_getattr_be16(tb[LWTUNNEL_IP_OPT_GENEVE_CLASS]);
+ type = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_GENEVE_TYPE]);
+ data_len = RTA_PAYLOAD(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]);
+ hexstring_n2a(RTA_DATA(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]),
+ data_len, data, sizeof(data));
+ offset += data_len + 20;
+ rem -= data_len + 20;
+ i = RTA_DATA(attr) + offset;
+ slen += sprintf(opt + slen, "%04x:%02x:%s", class, type, data);
+ if (rem)
+ slen += sprintf(opt + slen, ",");
+ }
+ print_string(PRINT_FP, "enc_opt", "\n geneve_opts %s ", opt);
+}
+
+static void lwtunnel_print_opts(struct rtattr *attr)
+{
+ struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1];
+ char *opt;
+
+ opt = malloc(RTA_PAYLOAD(attr) * 2 + 1);
+ if (!opt)
+ return;
+
+ parse_rtattr_nested(tb_opt, LWTUNNEL_IP_OPTS_MAX, attr);
+ if (tb_opt[LWTUNNEL_IP_OPTS_GENEVE])
+ lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE],
+ opt);
+
+ free(opt);
+}
+
static void print_encap_ip(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[LWTUNNEL_IP_MAX+1];
@@ -332,6 +376,9 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap)
if (flags & TUNNEL_SEQ)
print_bool(PRINT_ANY, "seq", "seq ", true);
}
+
+ if (tb[LWTUNNEL_IP_OPTS])
+ lwtunnel_print_opts(tb[LWTUNNEL_IP_OPTS]);
}
static void print_encap_ila(FILE *fp, struct rtattr *encap)
@@ -404,6 +451,9 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap)
if (flags & TUNNEL_SEQ)
print_bool(PRINT_ANY, "seq", "seq ", true);
}
+
+ if (tb[LWTUNNEL_IP6_OPTS])
+ lwtunnel_print_opts(tb[LWTUNNEL_IP6_OPTS]);
}
static void print_encap_bpf(FILE *fp, struct rtattr *encap)
@@ -798,11 +848,97 @@ static int parse_encap_mpls(struct rtattr *rta, size_t len,
return 0;
}
+static int lwtunnel_parse_geneve_opt(char *str, size_t len, struct rtattr *rta)
+{
+ struct rtattr *nest;
+ char *token;
+ int i, err;
+
+ nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_GENEVE | NLA_F_NESTED);
+ i = 1;
+ token = strsep(&str, ":");
+ while (token) {
+ switch (i) {
+ case LWTUNNEL_IP_OPT_GENEVE_CLASS:
+ {
+ __be16 opt_class;
+
+ if (!strlen(token))
+ break;
+ err = get_be16(&opt_class, token, 16);
+ if (err)
+ return err;
+
+ rta_addattr16(rta, len, i, opt_class);
+ break;
+ }
+ case LWTUNNEL_IP_OPT_GENEVE_TYPE:
+ {
+ __u8 opt_type;
+
+ if (!strlen(token))
+ break;
+ err = get_u8(&opt_type, token, 16);
+ if (err)
+ return err;
+
+ rta_addattr8(rta, len, i, opt_type);
+ break;
+ }
+ case LWTUNNEL_IP_OPT_GENEVE_DATA:
+ {
+ size_t token_len = strlen(token);
+ __u8 *opts;
+
+ if (!token_len)
+ break;
+ opts = malloc(token_len / 2);
+ if (!opts)
+ return -1;
+ if (hex2mem(token, opts, token_len / 2) < 0) {
+ free(opts);
+ return -1;
+ }
+ rta_addattr_l(rta, len, i, opts, token_len / 2);
+ free(opts);
+
+ break;
+ }
+ default:
+ fprintf(stderr, "Unknown \"geneve_opts\" type\n");
+ return -1;
+ }
+
+ token = strsep(&str, ":");
+ i++;
+ }
+ rta_nest_end(rta, nest);
+
+ return 0;
+}
+
+static int lwtunnel_parse_geneve_opts(char *str, size_t len, struct rtattr *rta)
+{
+ char *token;
+ int err;
+
+ token = strsep(&str, ",");
+ while (token) {
+ err = lwtunnel_parse_geneve_opt(token, len, rta);
+ if (err)
+ return err;
+
+ token = strsep(&str, ",");
+ }
+
+ return 0;
+}
+
static int parse_encap_ip(struct rtattr *rta, size_t len,
int *argcp, char ***argvp)
{
int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
- int key_ok = 0, csum_ok = 0, seq_ok = 0;
+ int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
char **argv = *argvp;
int argc = *argcp;
int ret = 0;
@@ -854,6 +990,21 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
if (get_u8(&ttl, *argv, 0))
invarg("\"ttl\" value is invalid\n", *argv);
ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
+ } else if (strcmp(*argv, "geneve_opts") == 0) {
+ struct rtattr *nest;
+
+ if (opts_ok++)
+ duparg2("opts", *argv);
+
+ NEXT_ARG();
+
+ nest = rta_nest(rta, len,
+ LWTUNNEL_IP_OPTS | NLA_F_NESTED);
+ ret = lwtunnel_parse_geneve_opts(*argv, len, rta);
+ if (ret)
+ invarg("\"geneve_opts\" value is invalid\n",
+ *argv);
+ rta_nest_end(rta, nest);
} else if (strcmp(*argv, "key") == 0) {
if (key_ok++)
duparg2("key", *argv);
@@ -969,7 +1120,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
int *argcp, char ***argvp)
{
int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
- int key_ok = 0, csum_ok = 0, seq_ok = 0;
+ int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
char **argv = *argvp;
int argc = *argcp;
int ret = 0;
@@ -1023,6 +1174,21 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
*argv);
ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
hoplimit);
+ } else if (strcmp(*argv, "geneve_opts") == 0) {
+ struct rtattr *nest;
+
+ if (opts_ok++)
+ duparg2("opts", *argv);
+
+ NEXT_ARG();
+
+ nest = rta_nest(rta, len,
+ LWTUNNEL_IP_OPTS | NLA_F_NESTED);
+ ret = lwtunnel_parse_geneve_opts(*argv, len, rta);
+ if (ret)
+ invarg("\"geneve_opts\" value is invalid\n",
+ *argv);
+ rta_nest_end(rta, nest);
} else if (strcmp(*argv, "key") == 0) {
if (key_ok++)
duparg2("key", *argv);
--
2.1.0
Powered by blists - more mailing lists