Skip to content

Commit 925d844

Browse files
lxinummakynes
authored andcommitted
netfilter: nft_tunnel: add support for geneve opts
Like vxlan and erspan opts, geneve opts should also be supported in nft_tunnel. The difference is geneve RFC (draft-ietf-nvo3-geneve-14) allows a geneve packet to carry multiple geneve opts. So with this patch, nftables/libnftnl would do: # nft add table ip filter # nft add chain ip filter input { type filter hook input priority 0 \; } # nft add tunnel filter geneve_02 { type geneve\; id 2\; \ ip saddr 192.168.1.1\; ip daddr 192.168.1.2\; \ sport 9000\; dport 9001\; dscp 1234\; ttl 64\; flags 1\; \ opts \"1:1:34567890,2:2:12121212,3:3:1212121234567890\"\; } # nft list tunnels table filter table ip filter { tunnel geneve_02 { id 2 ip saddr 192.168.1.1 ip daddr 192.168.1.2 sport 9000 dport 9001 tos 18 ttl 64 flags 1 geneve opts 1:1:34567890,2:2:12121212,3:3:1212121234567890 } } v1->v2: - no changes, just post it separately. Signed-off-by: Xin Long <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 68983a3 commit 925d844

File tree

2 files changed

+108
-12
lines changed

2 files changed

+108
-12
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,7 @@ enum nft_tunnel_opts_attributes {
17701770
NFTA_TUNNEL_KEY_OPTS_UNSPEC,
17711771
NFTA_TUNNEL_KEY_OPTS_VXLAN,
17721772
NFTA_TUNNEL_KEY_OPTS_ERSPAN,
1773+
NFTA_TUNNEL_KEY_OPTS_GENEVE,
17731774
__NFTA_TUNNEL_KEY_OPTS_MAX
17741775
};
17751776
#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1)
@@ -1791,6 +1792,15 @@ enum nft_tunnel_opts_erspan_attributes {
17911792
};
17921793
#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1)
17931794

1795+
enum nft_tunnel_opts_geneve_attributes {
1796+
NFTA_TUNNEL_KEY_GENEVE_UNSPEC,
1797+
NFTA_TUNNEL_KEY_GENEVE_CLASS,
1798+
NFTA_TUNNEL_KEY_GENEVE_TYPE,
1799+
NFTA_TUNNEL_KEY_GENEVE_DATA,
1800+
__NFTA_TUNNEL_KEY_GENEVE_MAX
1801+
};
1802+
#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1)
1803+
17941804
enum nft_tunnel_flags {
17951805
NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0),
17961806
NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1),

net/netfilter/nft_tunnel.c

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <net/ip_tunnels.h>
1212
#include <net/vxlan.h>
1313
#include <net/erspan.h>
14+
#include <net/geneve.h>
1415

1516
struct nft_tunnel {
1617
enum nft_tunnel_keys key:8;
@@ -144,6 +145,7 @@ struct nft_tunnel_opts {
144145
union {
145146
struct vxlan_metadata vxlan;
146147
struct erspan_metadata erspan;
148+
u8 data[IP_TUNNEL_OPTS_MAX];
147149
} u;
148150
u32 len;
149151
__be16 flags;
@@ -301,32 +303,97 @@ static int nft_tunnel_obj_erspan_init(const struct nlattr *attr,
301303
return 0;
302304
}
303305

306+
static const struct nla_policy nft_tunnel_opts_geneve_policy[NFTA_TUNNEL_KEY_GENEVE_MAX + 1] = {
307+
[NFTA_TUNNEL_KEY_GENEVE_CLASS] = { .type = NLA_U16 },
308+
[NFTA_TUNNEL_KEY_GENEVE_TYPE] = { .type = NLA_U8 },
309+
[NFTA_TUNNEL_KEY_GENEVE_DATA] = { .type = NLA_BINARY, .len = 128 },
310+
};
311+
312+
static int nft_tunnel_obj_geneve_init(const struct nlattr *attr,
313+
struct nft_tunnel_opts *opts)
314+
{
315+
struct geneve_opt *opt = (struct geneve_opt *)opts->u.data + opts->len;
316+
struct nlattr *tb[NFTA_TUNNEL_KEY_GENEVE_MAX + 1];
317+
int err, data_len;
318+
319+
err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_GENEVE_MAX, attr,
320+
nft_tunnel_opts_geneve_policy, NULL);
321+
if (err < 0)
322+
return err;
323+
324+
if (!tb[NFTA_TUNNEL_KEY_GENEVE_CLASS] ||
325+
!tb[NFTA_TUNNEL_KEY_GENEVE_TYPE] ||
326+
!tb[NFTA_TUNNEL_KEY_GENEVE_DATA])
327+
return -EINVAL;
328+
329+
attr = tb[NFTA_TUNNEL_KEY_GENEVE_DATA];
330+
data_len = nla_len(attr);
331+
if (data_len % 4)
332+
return -EINVAL;
333+
334+
opts->len += sizeof(*opt) + data_len;
335+
if (opts->len > IP_TUNNEL_OPTS_MAX)
336+
return -EINVAL;
337+
338+
memcpy(opt->opt_data, nla_data(attr), data_len);
339+
opt->length = data_len / 4;
340+
opt->opt_class = nla_get_be16(tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]);
341+
opt->type = nla_get_u8(tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]);
342+
opts->flags = TUNNEL_GENEVE_OPT;
343+
344+
return 0;
345+
}
346+
304347
static const struct nla_policy nft_tunnel_opts_policy[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = {
348+
[NFTA_TUNNEL_KEY_OPTS_UNSPEC] = {
349+
.strict_start_type = NFTA_TUNNEL_KEY_OPTS_GENEVE },
305350
[NFTA_TUNNEL_KEY_OPTS_VXLAN] = { .type = NLA_NESTED, },
306351
[NFTA_TUNNEL_KEY_OPTS_ERSPAN] = { .type = NLA_NESTED, },
352+
[NFTA_TUNNEL_KEY_OPTS_GENEVE] = { .type = NLA_NESTED, },
307353
};
308354

309355
static int nft_tunnel_obj_opts_init(const struct nft_ctx *ctx,
310356
const struct nlattr *attr,
311357
struct ip_tunnel_info *info,
312358
struct nft_tunnel_opts *opts)
313359
{
314-
struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1];
315-
int err;
360+
int err, rem, type = 0;
361+
struct nlattr *nla;
316362

317-
err = nla_parse_nested_deprecated(tb, NFTA_TUNNEL_KEY_OPTS_MAX, attr,
318-
nft_tunnel_opts_policy, NULL);
363+
err = nla_validate_nested_deprecated(attr, NFTA_TUNNEL_KEY_OPTS_MAX,
364+
nft_tunnel_opts_policy, NULL);
319365
if (err < 0)
320366
return err;
321367

322-
if (tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]) {
323-
err = nft_tunnel_obj_vxlan_init(tb[NFTA_TUNNEL_KEY_OPTS_VXLAN],
324-
opts);
325-
} else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) {
326-
err = nft_tunnel_obj_erspan_init(tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN],
327-
opts);
328-
} else {
329-
return -EOPNOTSUPP;
368+
nla_for_each_attr(nla, nla_data(attr), nla_len(attr), rem) {
369+
switch (nla_type(nla)) {
370+
case NFTA_TUNNEL_KEY_OPTS_VXLAN:
371+
if (type)
372+
return -EINVAL;
373+
err = nft_tunnel_obj_vxlan_init(nla, opts);
374+
if (err)
375+
return err;
376+
type = TUNNEL_VXLAN_OPT;
377+
break;
378+
case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
379+
if (type)
380+
return -EINVAL;
381+
err = nft_tunnel_obj_erspan_init(nla, opts);
382+
if (err)
383+
return err;
384+
type = TUNNEL_ERSPAN_OPT;
385+
break;
386+
case NFTA_TUNNEL_KEY_OPTS_GENEVE:
387+
if (type && type != TUNNEL_GENEVE_OPT)
388+
return -EINVAL;
389+
err = nft_tunnel_obj_geneve_init(nla, opts);
390+
if (err)
391+
return err;
392+
type = TUNNEL_GENEVE_OPT;
393+
break;
394+
default:
395+
return -EOPNOTSUPP;
396+
}
330397
}
331398

332399
return err;
@@ -518,6 +585,25 @@ static int nft_tunnel_opts_dump(struct sk_buff *skb,
518585
break;
519586
}
520587
nla_nest_end(skb, inner);
588+
} else if (opts->flags & TUNNEL_GENEVE_OPT) {
589+
struct geneve_opt *opt;
590+
int offset = 0;
591+
592+
inner = nla_nest_start_noflag(skb, NFTA_TUNNEL_KEY_OPTS_GENEVE);
593+
if (!inner)
594+
goto failure;
595+
while (opts->len > offset) {
596+
opt = (struct geneve_opt *)opts->u.data + offset;
597+
if (nla_put_be16(skb, NFTA_TUNNEL_KEY_GENEVE_CLASS,
598+
opt->opt_class) ||
599+
nla_put_u8(skb, NFTA_TUNNEL_KEY_GENEVE_TYPE,
600+
opt->type) ||
601+
nla_put(skb, NFTA_TUNNEL_KEY_GENEVE_DATA,
602+
opt->length * 4, opt->opt_data))
603+
goto inner_failure;
604+
offset += sizeof(*opt) + opt->length * 4;
605+
}
606+
nla_nest_end(skb, inner);
521607
}
522608
nla_nest_end(skb, nest);
523609
return 0;

0 commit comments

Comments
 (0)