Skip to content

Commit 4ece477

Browse files
lxindavem330
authored andcommitted
lwtunnel: add options setting and dumping for geneve
To add options setting and dumping, .build_state(), .fill_encap() and .get_encap_size() in ip_tun_lwt_ops needs to be extended: ip_tun_build_state(): ip_tun_parse_opts(): ip_tun_parse_opts_geneve() ip_tun_fill_encap_info(): ip_tun_fill_encap_opts(): ip_tun_fill_encap_opts_geneve() ip_tun_encap_nlsize() ip_tun_opts_nlsize(): if (tun_flags & TUNNEL_GENEVE_OPT) ip_tun_parse_opts(), ip_tun_fill_encap_opts() and ip_tun_opts_nlsize() processes LWTUNNEL_IP_OPTS. ip_tun_parse_opts_geneve(), ip_tun_fill_encap_opts_geneve() and if (tun_flags & TUNNEL_GENEVE_OPT) processes LWTUNNEL_IP_OPTS_GENEVE. Signed-off-by: Xin Long <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0eb8eb2 commit 4ece477

File tree

2 files changed

+216
-16
lines changed

2 files changed

+216
-16
lines changed

include/uapi/linux/lwtunnel.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ enum lwtunnel_ip_t {
2727
LWTUNNEL_IP_TOS,
2828
LWTUNNEL_IP_FLAGS,
2929
LWTUNNEL_IP_PAD,
30+
LWTUNNEL_IP_OPTS,
3031
__LWTUNNEL_IP_MAX,
3132
};
3233

@@ -41,11 +42,30 @@ enum lwtunnel_ip6_t {
4142
LWTUNNEL_IP6_TC,
4243
LWTUNNEL_IP6_FLAGS,
4344
LWTUNNEL_IP6_PAD,
45+
LWTUNNEL_IP6_OPTS,
4446
__LWTUNNEL_IP6_MAX,
4547
};
4648

4749
#define LWTUNNEL_IP6_MAX (__LWTUNNEL_IP6_MAX - 1)
4850

51+
enum {
52+
LWTUNNEL_IP_OPTS_UNSPEC,
53+
LWTUNNEL_IP_OPTS_GENEVE,
54+
__LWTUNNEL_IP_OPTS_MAX,
55+
};
56+
57+
#define LWTUNNEL_IP_OPTS_MAX (__LWTUNNEL_IP_OPTS_MAX - 1)
58+
59+
enum {
60+
LWTUNNEL_IP_OPT_GENEVE_UNSPEC,
61+
LWTUNNEL_IP_OPT_GENEVE_CLASS,
62+
LWTUNNEL_IP_OPT_GENEVE_TYPE,
63+
LWTUNNEL_IP_OPT_GENEVE_DATA,
64+
__LWTUNNEL_IP_OPT_GENEVE_MAX,
65+
};
66+
67+
#define LWTUNNEL_IP_OPT_GENEVE_MAX (__LWTUNNEL_IP_OPT_GENEVE_MAX - 1)
68+
4969
enum {
5070
LWT_BPF_PROG_UNSPEC,
5171
LWT_BPF_PROG_FD,

net/ipv4/ip_tunnel_core.c

Lines changed: 196 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <net/netns/generic.h>
3535
#include <net/rtnetlink.h>
3636
#include <net/dst_metadata.h>
37+
#include <net/geneve.h>
3738

3839
const struct ip_tunnel_encap_ops __rcu *
3940
iptun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly;
@@ -218,31 +219,125 @@ static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = {
218219
[LWTUNNEL_IP_TTL] = { .type = NLA_U8 },
219220
[LWTUNNEL_IP_TOS] = { .type = NLA_U8 },
220221
[LWTUNNEL_IP_FLAGS] = { .type = NLA_U16 },
222+
[LWTUNNEL_IP_OPTS] = { .type = NLA_NESTED },
221223
};
222224

225+
static const struct nla_policy ip_opts_policy[LWTUNNEL_IP_OPTS_MAX + 1] = {
226+
[LWTUNNEL_IP_OPTS_GENEVE] = { .type = NLA_NESTED },
227+
};
228+
229+
static const struct nla_policy
230+
geneve_opt_policy[LWTUNNEL_IP_OPT_GENEVE_MAX + 1] = {
231+
[LWTUNNEL_IP_OPT_GENEVE_CLASS] = { .type = NLA_U16 },
232+
[LWTUNNEL_IP_OPT_GENEVE_TYPE] = { .type = NLA_U8 },
233+
[LWTUNNEL_IP_OPT_GENEVE_DATA] = { .type = NLA_BINARY, .len = 128 },
234+
};
235+
236+
static int ip_tun_parse_opts_geneve(struct nlattr *attr,
237+
struct ip_tunnel_info *info,
238+
struct netlink_ext_ack *extack)
239+
{
240+
struct nlattr *tb[LWTUNNEL_IP_OPT_GENEVE_MAX + 1];
241+
int data_len, err;
242+
243+
err = nla_parse_nested_deprecated(tb, LWTUNNEL_IP_OPT_GENEVE_MAX,
244+
attr, geneve_opt_policy, extack);
245+
if (err)
246+
return err;
247+
248+
if (!tb[LWTUNNEL_IP_OPT_GENEVE_CLASS] ||
249+
!tb[LWTUNNEL_IP_OPT_GENEVE_TYPE] ||
250+
!tb[LWTUNNEL_IP_OPT_GENEVE_DATA])
251+
return -EINVAL;
252+
253+
attr = tb[LWTUNNEL_IP_OPT_GENEVE_DATA];
254+
data_len = nla_len(attr);
255+
if (data_len % 4)
256+
return -EINVAL;
257+
258+
if (info) {
259+
struct geneve_opt *opt = ip_tunnel_info_opts(info);
260+
261+
memcpy(opt->opt_data, nla_data(attr), data_len);
262+
opt->length = data_len / 4;
263+
attr = tb[LWTUNNEL_IP_OPT_GENEVE_CLASS];
264+
opt->opt_class = nla_get_be16(attr);
265+
attr = tb[LWTUNNEL_IP_OPT_GENEVE_TYPE];
266+
opt->type = nla_get_u8(attr);
267+
info->key.tun_flags |= TUNNEL_GENEVE_OPT;
268+
}
269+
270+
return sizeof(struct geneve_opt) + data_len;
271+
}
272+
273+
static int ip_tun_parse_opts(struct nlattr *attr, struct ip_tunnel_info *info,
274+
struct netlink_ext_ack *extack)
275+
{
276+
struct nlattr *tb[LWTUNNEL_IP_OPTS_MAX + 1];
277+
int err;
278+
279+
if (!attr)
280+
return 0;
281+
282+
err = nla_parse_nested_deprecated(tb, LWTUNNEL_IP_OPTS_MAX, attr,
283+
ip_opts_policy, extack);
284+
if (err)
285+
return err;
286+
287+
if (tb[LWTUNNEL_IP_OPTS_GENEVE])
288+
err = ip_tun_parse_opts_geneve(tb[LWTUNNEL_IP_OPTS_GENEVE],
289+
info, extack);
290+
else
291+
err = -EINVAL;
292+
293+
return err;
294+
}
295+
296+
static int ip_tun_get_optlen(struct nlattr *attr,
297+
struct netlink_ext_ack *extack)
298+
{
299+
return ip_tun_parse_opts(attr, NULL, extack);
300+
}
301+
302+
static int ip_tun_set_opts(struct nlattr *attr, struct ip_tunnel_info *info,
303+
struct netlink_ext_ack *extack)
304+
{
305+
return ip_tun_parse_opts(attr, info, extack);
306+
}
307+
223308
static int ip_tun_build_state(struct nlattr *attr,
224309
unsigned int family, const void *cfg,
225310
struct lwtunnel_state **ts,
226311
struct netlink_ext_ack *extack)
227312
{
228-
struct ip_tunnel_info *tun_info;
229-
struct lwtunnel_state *new_state;
230313
struct nlattr *tb[LWTUNNEL_IP_MAX + 1];
231-
int err;
314+
struct lwtunnel_state *new_state;
315+
struct ip_tunnel_info *tun_info;
316+
int err, opt_len;
232317

233318
err = nla_parse_nested_deprecated(tb, LWTUNNEL_IP_MAX, attr,
234319
ip_tun_policy, extack);
235320
if (err < 0)
236321
return err;
237322

238-
new_state = lwtunnel_state_alloc(sizeof(*tun_info));
323+
opt_len = ip_tun_get_optlen(tb[LWTUNNEL_IP_OPTS], extack);
324+
if (opt_len < 0)
325+
return opt_len;
326+
327+
new_state = lwtunnel_state_alloc(sizeof(*tun_info) + opt_len);
239328
if (!new_state)
240329
return -ENOMEM;
241330

242331
new_state->type = LWTUNNEL_ENCAP_IP;
243332

244333
tun_info = lwt_tun_info(new_state);
245334

335+
err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, extack);
336+
if (err < 0) {
337+
lwtstate_free(new_state);
338+
return err;
339+
}
340+
246341
#ifdef CONFIG_DST_CACHE
247342
err = dst_cache_init(&tun_info->dst_cache, GFP_KERNEL);
248343
if (err) {
@@ -267,10 +362,10 @@ static int ip_tun_build_state(struct nlattr *attr,
267362
tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP_TOS]);
268363

269364
if (tb[LWTUNNEL_IP_FLAGS])
270-
tun_info->key.tun_flags = nla_get_be16(tb[LWTUNNEL_IP_FLAGS]);
365+
tun_info->key.tun_flags |= nla_get_be16(tb[LWTUNNEL_IP_FLAGS]);
271366

272367
tun_info->mode = IP_TUNNEL_INFO_TX;
273-
tun_info->options_len = 0;
368+
tun_info->options_len = opt_len;
274369

275370
*ts = new_state;
276371

@@ -286,6 +381,54 @@ static void ip_tun_destroy_state(struct lwtunnel_state *lwtstate)
286381
#endif
287382
}
288383

384+
static int ip_tun_fill_encap_opts_geneve(struct sk_buff *skb,
385+
struct ip_tunnel_info *tun_info)
386+
{
387+
struct geneve_opt *opt;
388+
struct nlattr *nest;
389+
390+
nest = nla_nest_start_noflag(skb, LWTUNNEL_IP_OPTS_GENEVE);
391+
if (!nest)
392+
return -ENOMEM;
393+
394+
opt = ip_tunnel_info_opts(tun_info);
395+
if (nla_put_be16(skb, LWTUNNEL_IP_OPT_GENEVE_CLASS, opt->opt_class) ||
396+
nla_put_u8(skb, LWTUNNEL_IP_OPT_GENEVE_TYPE, opt->type) ||
397+
nla_put(skb, LWTUNNEL_IP_OPT_GENEVE_DATA, opt->length * 4,
398+
opt->opt_data)) {
399+
nla_nest_cancel(skb, nest);
400+
return -ENOMEM;
401+
}
402+
403+
nla_nest_end(skb, nest);
404+
return 0;
405+
}
406+
407+
static int ip_tun_fill_encap_opts(struct sk_buff *skb, int type,
408+
struct ip_tunnel_info *tun_info)
409+
{
410+
struct nlattr *nest;
411+
int err = 0;
412+
413+
if (!(tun_info->key.tun_flags & TUNNEL_GENEVE_OPT))
414+
return 0;
415+
416+
nest = nla_nest_start_noflag(skb, type);
417+
if (!nest)
418+
return -ENOMEM;
419+
420+
if (tun_info->key.tun_flags & TUNNEL_GENEVE_OPT)
421+
err = ip_tun_fill_encap_opts_geneve(skb, tun_info);
422+
423+
if (err) {
424+
nla_nest_cancel(skb, nest);
425+
return err;
426+
}
427+
428+
nla_nest_end(skb, nest);
429+
return 0;
430+
}
431+
289432
static int ip_tun_fill_encap_info(struct sk_buff *skb,
290433
struct lwtunnel_state *lwtstate)
291434
{
@@ -297,20 +440,44 @@ static int ip_tun_fill_encap_info(struct sk_buff *skb,
297440
nla_put_in_addr(skb, LWTUNNEL_IP_SRC, tun_info->key.u.ipv4.src) ||
298441
nla_put_u8(skb, LWTUNNEL_IP_TOS, tun_info->key.tos) ||
299442
nla_put_u8(skb, LWTUNNEL_IP_TTL, tun_info->key.ttl) ||
300-
nla_put_be16(skb, LWTUNNEL_IP_FLAGS, tun_info->key.tun_flags))
443+
nla_put_be16(skb, LWTUNNEL_IP_FLAGS, tun_info->key.tun_flags) ||
444+
ip_tun_fill_encap_opts(skb, LWTUNNEL_IP_OPTS, tun_info))
301445
return -ENOMEM;
302446

303447
return 0;
304448
}
305449

450+
static int ip_tun_opts_nlsize(struct ip_tunnel_info *info)
451+
{
452+
int opt_len;
453+
454+
if (!(info->key.tun_flags & TUNNEL_GENEVE_OPT))
455+
return 0;
456+
457+
opt_len = nla_total_size(0); /* LWTUNNEL_IP_OPTS */
458+
if (info->key.tun_flags & TUNNEL_GENEVE_OPT) {
459+
struct geneve_opt *opt = ip_tunnel_info_opts(info);
460+
461+
opt_len += nla_total_size(0) /* LWTUNNEL_IP_OPTS_GENEVE */
462+
+ nla_total_size(2) /* OPT_GENEVE_CLASS */
463+
+ nla_total_size(1) /* OPT_GENEVE_TYPE */
464+
+ nla_total_size(opt->length * 4);
465+
/* OPT_GENEVE_DATA */
466+
}
467+
468+
return opt_len;
469+
}
470+
306471
static int ip_tun_encap_nlsize(struct lwtunnel_state *lwtstate)
307472
{
308473
return nla_total_size_64bit(8) /* LWTUNNEL_IP_ID */
309474
+ nla_total_size(4) /* LWTUNNEL_IP_DST */
310475
+ nla_total_size(4) /* LWTUNNEL_IP_SRC */
311476
+ nla_total_size(1) /* LWTUNNEL_IP_TOS */
312477
+ nla_total_size(1) /* LWTUNNEL_IP_TTL */
313-
+ nla_total_size(2); /* LWTUNNEL_IP_FLAGS */
478+
+ nla_total_size(2) /* LWTUNNEL_IP_FLAGS */
479+
+ ip_tun_opts_nlsize(lwt_tun_info(lwtstate));
480+
/* LWTUNNEL_IP_OPTS */
314481
}
315482

316483
static int ip_tun_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b)
@@ -348,24 +515,34 @@ static int ip6_tun_build_state(struct nlattr *attr,
348515
struct lwtunnel_state **ts,
349516
struct netlink_ext_ack *extack)
350517
{
351-
struct ip_tunnel_info *tun_info;
352-
struct lwtunnel_state *new_state;
353518
struct nlattr *tb[LWTUNNEL_IP6_MAX + 1];
354-
int err;
519+
struct lwtunnel_state *new_state;
520+
struct ip_tunnel_info *tun_info;
521+
int err, opt_len;
355522

356523
err = nla_parse_nested_deprecated(tb, LWTUNNEL_IP6_MAX, attr,
357524
ip6_tun_policy, extack);
358525
if (err < 0)
359526
return err;
360527

361-
new_state = lwtunnel_state_alloc(sizeof(*tun_info));
528+
opt_len = ip_tun_get_optlen(tb[LWTUNNEL_IP6_OPTS], extack);
529+
if (opt_len < 0)
530+
return opt_len;
531+
532+
new_state = lwtunnel_state_alloc(sizeof(*tun_info) + opt_len);
362533
if (!new_state)
363534
return -ENOMEM;
364535

365536
new_state->type = LWTUNNEL_ENCAP_IP6;
366537

367538
tun_info = lwt_tun_info(new_state);
368539

540+
err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, extack);
541+
if (err < 0) {
542+
lwtstate_free(new_state);
543+
return err;
544+
}
545+
369546
if (tb[LWTUNNEL_IP6_ID])
370547
tun_info->key.tun_id = nla_get_be64(tb[LWTUNNEL_IP6_ID]);
371548

@@ -382,10 +559,10 @@ static int ip6_tun_build_state(struct nlattr *attr,
382559
tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP6_TC]);
383560

384561
if (tb[LWTUNNEL_IP6_FLAGS])
385-
tun_info->key.tun_flags = nla_get_be16(tb[LWTUNNEL_IP6_FLAGS]);
562+
tun_info->key.tun_flags |= nla_get_be16(tb[LWTUNNEL_IP6_FLAGS]);
386563

387564
tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6;
388-
tun_info->options_len = 0;
565+
tun_info->options_len = opt_len;
389566

390567
*ts = new_state;
391568

@@ -403,7 +580,8 @@ static int ip6_tun_fill_encap_info(struct sk_buff *skb,
403580
nla_put_in6_addr(skb, LWTUNNEL_IP6_SRC, &tun_info->key.u.ipv6.src) ||
404581
nla_put_u8(skb, LWTUNNEL_IP6_TC, tun_info->key.tos) ||
405582
nla_put_u8(skb, LWTUNNEL_IP6_HOPLIMIT, tun_info->key.ttl) ||
406-
nla_put_be16(skb, LWTUNNEL_IP6_FLAGS, tun_info->key.tun_flags))
583+
nla_put_be16(skb, LWTUNNEL_IP6_FLAGS, tun_info->key.tun_flags) ||
584+
ip_tun_fill_encap_opts(skb, LWTUNNEL_IP6_OPTS, tun_info))
407585
return -ENOMEM;
408586

409587
return 0;
@@ -416,7 +594,9 @@ static int ip6_tun_encap_nlsize(struct lwtunnel_state *lwtstate)
416594
+ nla_total_size(16) /* LWTUNNEL_IP6_SRC */
417595
+ nla_total_size(1) /* LWTUNNEL_IP6_HOPLIMIT */
418596
+ nla_total_size(1) /* LWTUNNEL_IP6_TC */
419-
+ nla_total_size(2); /* LWTUNNEL_IP6_FLAGS */
597+
+ nla_total_size(2) /* LWTUNNEL_IP6_FLAGS */
598+
+ ip_tun_opts_nlsize(lwt_tun_info(lwtstate));
599+
/* LWTUNNEL_IP6_OPTS */
420600
}
421601

422602
static const struct lwtunnel_encap_ops ip6_tun_lwt_ops = {

0 commit comments

Comments
 (0)