aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2018-08-02 14:51:39 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2018-08-03 15:12:12 -0400
commitaf308b94a2a4a5a27bec9028354c4df444a7c8ba (patch)
tree2d3082f03ade1bdeec8e276266816128bf27d39d
parent033eab53fff7acc0f5718dee6fda641734b94416 (diff)
netfilter: nf_tables: add tunnel support
This patch implements the tunnel object type that can be used to configure tunnels via metadata template through the existing lightweight API from the ingress path. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h69
-rw-r--r--net/core/dst.c1
-rw-r--r--net/netfilter/Kconfig6
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/nft_tunnel.c458
5 files changed, 534 insertions, 1 deletions
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index f112ea52dc1a..3ee1198eeac1 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1416,7 +1416,8 @@ enum nft_ct_helper_attributes {
1416#define NFT_OBJECT_CT_HELPER 3 1416#define NFT_OBJECT_CT_HELPER 3
1417#define NFT_OBJECT_LIMIT 4 1417#define NFT_OBJECT_LIMIT 4
1418#define NFT_OBJECT_CONNLIMIT 5 1418#define NFT_OBJECT_CONNLIMIT 5
1419#define __NFT_OBJECT_MAX 6 1419#define NFT_OBJECT_TUNNEL 6
1420#define __NFT_OBJECT_MAX 7
1420#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) 1421#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
1421 1422
1422/** 1423/**
@@ -1580,4 +1581,70 @@ enum nft_ng_types {
1580}; 1581};
1581#define NFT_NG_MAX (__NFT_NG_MAX - 1) 1582#define NFT_NG_MAX (__NFT_NG_MAX - 1)
1582 1583
1584enum nft_tunnel_key_ip_attributes {
1585 NFTA_TUNNEL_KEY_IP_UNSPEC,
1586 NFTA_TUNNEL_KEY_IP_SRC,
1587 NFTA_TUNNEL_KEY_IP_DST,
1588 __NFTA_TUNNEL_KEY_IP_MAX
1589};
1590#define NFTA_TUNNEL_KEY_IP_MAX (__NFTA_TUNNEL_KEY_IP_MAX - 1)
1591
1592enum nft_tunnel_ip6_attributes {
1593 NFTA_TUNNEL_KEY_IP6_UNSPEC,
1594 NFTA_TUNNEL_KEY_IP6_SRC,
1595 NFTA_TUNNEL_KEY_IP6_DST,
1596 NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
1597 __NFTA_TUNNEL_KEY_IP6_MAX
1598};
1599#define NFTA_TUNNEL_KEY_IP6_MAX (__NFTA_TUNNEL_KEY_IP6_MAX - 1)
1600
1601enum nft_tunnel_opts_attributes {
1602 NFTA_TUNNEL_KEY_OPTS_UNSPEC,
1603 NFTA_TUNNEL_KEY_OPTS_VXLAN,
1604 NFTA_TUNNEL_KEY_OPTS_ERSPAN,
1605 __NFTA_TUNNEL_KEY_OPTS_MAX
1606};
1607#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1)
1608
1609enum nft_tunnel_opts_vxlan_attributes {
1610 NFTA_TUNNEL_KEY_VXLAN_UNSPEC,
1611 NFTA_TUNNEL_KEY_VXLAN_GBP,
1612 __NFTA_TUNNEL_KEY_VXLAN_MAX
1613};
1614#define NFTA_TUNNEL_KEY_VXLAN_MAX (__NFTA_TUNNEL_KEY_VXLAN_MAX - 1)
1615
1616enum nft_tunnel_opts_erspan_attributes {
1617 NFTA_TUNNEL_KEY_ERSPAN_UNSPEC,
1618 NFTA_TUNNEL_KEY_ERSPAN_VERSION,
1619 NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
1620 NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
1621 NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
1622 __NFTA_TUNNEL_KEY_ERSPAN_MAX
1623};
1624#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1)
1625
1626enum nft_tunnel_flags {
1627 NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0),
1628 NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1),
1629 NFT_TUNNEL_F_SEQ_NUMBER = (1 << 2),
1630};
1631#define NFT_TUNNEL_F_MASK (NFT_TUNNEL_F_ZERO_CSUM_TX | \
1632 NFT_TUNNEL_F_DONT_FRAGMENT | \
1633 NFT_TUNNEL_F_SEQ_NUMBER)
1634
1635enum nft_tunnel_key_attributes {
1636 NFTA_TUNNEL_KEY_UNSPEC,
1637 NFTA_TUNNEL_KEY_ID,
1638 NFTA_TUNNEL_KEY_IP,
1639 NFTA_TUNNEL_KEY_IP6,
1640 NFTA_TUNNEL_KEY_FLAGS,
1641 NFTA_TUNNEL_KEY_TOS,
1642 NFTA_TUNNEL_KEY_TTL,
1643 NFTA_TUNNEL_KEY_SPORT,
1644 NFTA_TUNNEL_KEY_DPORT,
1645 NFTA_TUNNEL_KEY_OPTS,
1646 __NFTA_TUNNEL_KEY_MAX
1647};
1648#define NFTA_TUNNEL_KEY_MAX (__NFTA_TUNNEL_KEY_MAX - 1)
1649
1583#endif /* _LINUX_NF_TABLES_H */ 1650#endif /* _LINUX_NF_TABLES_H */
diff --git a/net/core/dst.c b/net/core/dst.c
index 2d9b37f8944a..81ccf20e2826 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -307,6 +307,7 @@ void metadata_dst_free(struct metadata_dst *md_dst)
307#endif 307#endif
308 kfree(md_dst); 308 kfree(md_dst);
309} 309}
310EXPORT_SYMBOL_GPL(metadata_dst_free);
310 311
311struct metadata_dst __percpu * 312struct metadata_dst __percpu *
312metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags) 313metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 55e399d5af10..654588088676 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -559,6 +559,12 @@ config NFT_NAT
559 This option adds the "nat" expression that you can use to perform 559 This option adds the "nat" expression that you can use to perform
560 typical Network Address Translation (NAT) packet transformations. 560 typical Network Address Translation (NAT) packet transformations.
561 561
562config NFT_TUNNEL
563 tristate "Netfilter nf_tables tunnel module"
564 help
565 This option adds the "tunnel" expression that you can use to set
566 tunneling policies.
567
562config NFT_OBJREF 568config NFT_OBJREF
563 tristate "Netfilter nf_tables stateful object reference module" 569 tristate "Netfilter nf_tables stateful object reference module"
564 help 570 help
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index cf61615cc529..16895e045b66 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_NFT_QUEUE) += nft_queue.o
101obj-$(CONFIG_NFT_QUOTA) += nft_quota.o 101obj-$(CONFIG_NFT_QUOTA) += nft_quota.o
102obj-$(CONFIG_NFT_REJECT) += nft_reject.o 102obj-$(CONFIG_NFT_REJECT) += nft_reject.o
103obj-$(CONFIG_NFT_REJECT_INET) += nft_reject_inet.o 103obj-$(CONFIG_NFT_REJECT_INET) += nft_reject_inet.o
104obj-$(CONFIG_NFT_TUNNEL) += nft_tunnel.o
104obj-$(CONFIG_NFT_COUNTER) += nft_counter.o 105obj-$(CONFIG_NFT_COUNTER) += nft_counter.o
105obj-$(CONFIG_NFT_LOG) += nft_log.o 106obj-$(CONFIG_NFT_LOG) += nft_log.o
106obj-$(CONFIG_NFT_MASQ) += nft_masq.o 107obj-$(CONFIG_NFT_MASQ) += nft_masq.o
diff --git a/net/netfilter/nft_tunnel.c b/net/netfilter/nft_tunnel.c
new file mode 100644
index 000000000000..715613d99c20
--- /dev/null
+++ b/net/netfilter/nft_tunnel.c
@@ -0,0 +1,458 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#include <linux/kernel.h>
3#include <linux/init.h>
4#include <linux/module.h>
5#include <linux/seqlock.h>
6#include <linux/netlink.h>
7#include <linux/netfilter.h>
8#include <linux/netfilter/nf_tables.h>
9#include <net/netfilter/nf_tables.h>
10#include <net/dst_metadata.h>
11#include <net/ip_tunnels.h>
12#include <net/vxlan.h>
13#include <net/erspan.h>
14
15struct nft_tunnel_opts {
16 union {
17 struct vxlan_metadata vxlan;
18 struct erspan_metadata erspan;
19 } u;
20 u32 len;
21 u32 flags;
22};
23
24struct nft_tunnel_obj {
25 struct metadata_dst *md;
26 struct nft_tunnel_opts opts;
27};
28
29static const struct nla_policy nft_tunnel_ip_policy[NFTA_TUNNEL_KEY_IP_MAX + 1] = {
30 [NFTA_TUNNEL_KEY_IP_SRC] = { .type = NLA_U32 },
31 [NFTA_TUNNEL_KEY_IP_DST] = { .type = NLA_U32 },
32};
33
34static int nft_tunnel_obj_ip_init(const struct nft_ctx *ctx,
35 const struct nlattr *attr,
36 struct ip_tunnel_info *info)
37{
38 struct nlattr *tb[NFTA_TUNNEL_KEY_IP_MAX + 1];
39 int err;
40
41 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_IP_MAX, attr,
42 nft_tunnel_ip_policy, NULL);
43 if (err < 0)
44 return err;
45
46 if (!tb[NFTA_TUNNEL_KEY_IP_DST])
47 return -EINVAL;
48
49 if (tb[NFTA_TUNNEL_KEY_IP_SRC])
50 info->key.u.ipv4.src = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP_SRC]);
51 if (tb[NFTA_TUNNEL_KEY_IP_DST])
52 info->key.u.ipv4.dst = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP_DST]);
53
54 return 0;
55}
56
57static const struct nla_policy nft_tunnel_ip6_policy[NFTA_TUNNEL_KEY_IP6_MAX + 1] = {
58 [NFTA_TUNNEL_KEY_IP6_SRC] = { .len = sizeof(struct in6_addr), },
59 [NFTA_TUNNEL_KEY_IP6_DST] = { .len = sizeof(struct in6_addr), },
60 [NFTA_TUNNEL_KEY_IP6_FLOWLABEL] = { .type = NLA_U32, }
61};
62
63static int nft_tunnel_obj_ip6_init(const struct nft_ctx *ctx,
64 const struct nlattr *attr,
65 struct ip_tunnel_info *info)
66{
67 struct nlattr *tb[NFTA_TUNNEL_KEY_IP6_MAX + 1];
68 int err;
69
70 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_IP6_MAX, attr,
71 nft_tunnel_ip6_policy, NULL);
72 if (err < 0)
73 return err;
74
75 if (!tb[NFTA_TUNNEL_KEY_IP6_DST])
76 return -EINVAL;
77
78 if (tb[NFTA_TUNNEL_KEY_IP6_SRC]) {
79 memcpy(&info->key.u.ipv6.src,
80 nla_data(tb[NFTA_TUNNEL_KEY_IP6_SRC]),
81 sizeof(struct in6_addr));
82 }
83 if (tb[NFTA_TUNNEL_KEY_IP6_DST]) {
84 memcpy(&info->key.u.ipv6.dst,
85 nla_data(tb[NFTA_TUNNEL_KEY_IP6_DST]),
86 sizeof(struct in6_addr));
87 }
88 if (tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL])
89 info->key.label = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]);
90
91 info->mode |= IP_TUNNEL_INFO_IPV6;
92
93 return 0;
94}
95
96static const struct nla_policy nft_tunnel_opts_vxlan_policy[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = {
97 [NFTA_TUNNEL_KEY_VXLAN_GBP] = { .type = NLA_U32 },
98};
99
100static int nft_tunnel_obj_vxlan_init(const struct nlattr *attr,
101 struct nft_tunnel_opts *opts)
102{
103 struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1];
104 int err;
105
106 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_VXLAN_MAX, attr,
107 nft_tunnel_opts_vxlan_policy, NULL);
108 if (err < 0)
109 return err;
110
111 if (!tb[NFTA_TUNNEL_KEY_VXLAN_GBP])
112 return -EINVAL;
113
114 opts->u.vxlan.gbp = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP]));
115
116 opts->len = sizeof(struct vxlan_metadata);
117 opts->flags = TUNNEL_VXLAN_OPT;
118
119 return 0;
120}
121
122static const struct nla_policy nft_tunnel_opts_erspan_policy[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = {
123 [NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX] = { .type = NLA_U32 },
124 [NFTA_TUNNEL_KEY_ERSPAN_V2_DIR] = { .type = NLA_U8 },
125 [NFTA_TUNNEL_KEY_ERSPAN_V2_HWID] = { .type = NLA_U8 },
126};
127
128static int nft_tunnel_obj_erspan_init(const struct nlattr *attr,
129 struct nft_tunnel_opts *opts)
130{
131 struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1];
132 uint8_t hwid, dir;
133 int err, version;
134
135 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_ERSPAN_MAX, attr,
136 nft_tunnel_opts_erspan_policy, NULL);
137 if (err < 0)
138 return err;
139
140 version = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]));
141 switch (version) {
142 case ERSPAN_VERSION:
143 if (!tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX])
144 return -EINVAL;
145
146 opts->u.erspan.u.index =
147 nla_get_be32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]);
148 break;
149 case ERSPAN_VERSION2:
150 if (!tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR] ||
151 !tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID])
152 return -EINVAL;
153
154 hwid = nla_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]);
155 dir = nla_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]);
156
157 set_hwid(&opts->u.erspan.u.md2, hwid);
158 opts->u.erspan.u.md2.dir = dir;
159 break;
160 default:
161 return -EOPNOTSUPP;
162 }
163 opts->u.erspan.version = version;
164
165 opts->len = sizeof(struct erspan_metadata);
166 opts->flags = TUNNEL_ERSPAN_OPT;
167
168 return 0;
169}
170
171static const struct nla_policy nft_tunnel_opts_policy[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = {
172 [NFTA_TUNNEL_KEY_OPTS_VXLAN] = { .type = NLA_NESTED, },
173 [NFTA_TUNNEL_KEY_OPTS_ERSPAN] = { .type = NLA_NESTED, },
174};
175
176static int nft_tunnel_obj_opts_init(const struct nft_ctx *ctx,
177 const struct nlattr *attr,
178 struct ip_tunnel_info *info,
179 struct nft_tunnel_opts *opts)
180{
181 struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1];
182 int err;
183
184 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_OPTS_MAX, attr,
185 nft_tunnel_opts_policy, NULL);
186 if (err < 0)
187 return err;
188
189 if (tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]) {
190 err = nft_tunnel_obj_vxlan_init(tb[NFTA_TUNNEL_KEY_OPTS_VXLAN],
191 opts);
192 } else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) {
193 err = nft_tunnel_obj_erspan_init(tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN],
194 opts);
195 } else {
196 return -EOPNOTSUPP;
197 }
198
199 return err;
200}
201
202static const struct nla_policy nft_tunnel_key_policy[NFTA_TUNNEL_KEY_MAX + 1] = {
203 [NFTA_TUNNEL_KEY_IP] = { .type = NLA_NESTED, },
204 [NFTA_TUNNEL_KEY_IP6] = { .type = NLA_NESTED, },
205 [NFTA_TUNNEL_KEY_ID] = { .type = NLA_U32, },
206 [NFTA_TUNNEL_KEY_FLAGS] = { .type = NLA_U32, },
207 [NFTA_TUNNEL_KEY_TOS] = { .type = NLA_U8, },
208 [NFTA_TUNNEL_KEY_TTL] = { .type = NLA_U8, },
209 [NFTA_TUNNEL_KEY_OPTS] = { .type = NLA_NESTED, },
210};
211
212static int nft_tunnel_obj_init(const struct nft_ctx *ctx,
213 const struct nlattr * const tb[],
214 struct nft_object *obj)
215{
216 struct nft_tunnel_obj *priv = nft_obj_data(obj);
217 struct ip_tunnel_info info;
218 struct metadata_dst *md;
219 int err;
220
221 if (!tb[NFTA_TUNNEL_KEY_ID])
222 return -EINVAL;
223
224 memset(&info, 0, sizeof(info));
225 info.mode = IP_TUNNEL_INFO_TX;
226 info.key.tun_id = key32_to_tunnel_id(nla_get_be32(tb[NFTA_TUNNEL_KEY_ID]));
227 info.key.tun_flags = TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_NOCACHE;
228
229 if (tb[NFTA_TUNNEL_KEY_IP]) {
230 err = nft_tunnel_obj_ip_init(ctx, tb[NFTA_TUNNEL_KEY_IP], &info);
231 if (err < 0)
232 return err;
233 } else if (tb[NFTA_TUNNEL_KEY_IP6]) {
234 err = nft_tunnel_obj_ip6_init(ctx, tb[NFTA_TUNNEL_KEY_IP6], &info);
235 if (err < 0)
236 return err;
237 } else {
238 return -EINVAL;
239 }
240
241 if (tb[NFTA_TUNNEL_KEY_SPORT]) {
242 info.key.tp_src =
243 ntohs(nla_get_be16(tb[NFTA_TUNNEL_KEY_SPORT]));
244 }
245 if (tb[NFTA_TUNNEL_KEY_DPORT]) {
246 info.key.tp_dst =
247 ntohs(nla_get_be16(tb[NFTA_TUNNEL_KEY_DPORT]));
248 }
249
250 if (tb[NFTA_TUNNEL_KEY_FLAGS]) {
251 u32 tun_flags;
252
253 tun_flags = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_FLAGS]));
254 if (tun_flags & ~NFT_TUNNEL_F_MASK)
255 return -EOPNOTSUPP;
256
257 if (tun_flags & NFT_TUNNEL_F_ZERO_CSUM_TX)
258 info.key.tun_flags &= ~TUNNEL_CSUM;
259 if (tun_flags & NFT_TUNNEL_F_DONT_FRAGMENT)
260 info.key.tun_flags |= TUNNEL_DONT_FRAGMENT;
261 if (tun_flags & NFT_TUNNEL_F_SEQ_NUMBER)
262 info.key.tun_flags |= TUNNEL_SEQ;
263 }
264 if (tb[NFTA_TUNNEL_KEY_TOS])
265 info.key.tos = nla_get_u8(tb[NFTA_TUNNEL_KEY_TOS]);
266 if (tb[NFTA_TUNNEL_KEY_TTL])
267 info.key.ttl = nla_get_u8(tb[NFTA_TUNNEL_KEY_TTL]);
268 else
269 info.key.ttl = U8_MAX;
270
271 if (tb[NFTA_TUNNEL_KEY_OPTS]) {
272 err = nft_tunnel_obj_opts_init(ctx, tb[NFTA_TUNNEL_KEY_OPTS],
273 &info, &priv->opts);
274 if (err < 0)
275 return err;
276 }
277
278 md = metadata_dst_alloc(priv->opts.len, METADATA_IP_TUNNEL, GFP_KERNEL);
279 if (!md)
280 return -ENOMEM;
281
282 memcpy(&md->u.tun_info, &info, sizeof(info));
283 ip_tunnel_info_opts_set(&md->u.tun_info, &priv->opts.u, priv->opts.len,
284 priv->opts.flags);
285 priv->md = md;
286
287 return 0;
288}
289
290static inline void nft_tunnel_obj_eval(struct nft_object *obj,
291 struct nft_regs *regs,
292 const struct nft_pktinfo *pkt)
293{
294 struct nft_tunnel_obj *priv = nft_obj_data(obj);
295 struct sk_buff *skb = pkt->skb;
296
297 skb_dst_drop(skb);
298 dst_hold((struct dst_entry *) priv->md);
299 skb_dst_set(skb, (struct dst_entry *) priv->md);
300}
301
302static int nft_tunnel_ip_dump(struct sk_buff *skb, struct ip_tunnel_info *info)
303{
304 struct nlattr *nest;
305
306 if (info->mode & IP_TUNNEL_INFO_IPV6) {
307 nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_IP6);
308 if (!nest)
309 return -1;
310
311 if (nla_put_in6_addr(skb, NFTA_TUNNEL_KEY_IP6_SRC, &info->key.u.ipv6.src) < 0 ||
312 nla_put_in6_addr(skb, NFTA_TUNNEL_KEY_IP6_DST, &info->key.u.ipv6.dst) < 0 ||
313 nla_put_be32(skb, NFTA_TUNNEL_KEY_IP6_FLOWLABEL, info->key.label))
314 return -1;
315
316 nla_nest_end(skb, nest);
317 } else {
318 nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_IP);
319 if (!nest)
320 return -1;
321
322 if (nla_put_in_addr(skb, NFTA_TUNNEL_KEY_IP_SRC, info->key.u.ipv4.src) < 0 ||
323 nla_put_in_addr(skb, NFTA_TUNNEL_KEY_IP_DST, info->key.u.ipv4.dst) < 0)
324 return -1;
325
326 nla_nest_end(skb, nest);
327 }
328
329 return 0;
330}
331
332static int nft_tunnel_opts_dump(struct sk_buff *skb,
333 struct nft_tunnel_obj *priv)
334{
335 struct nft_tunnel_opts *opts = &priv->opts;
336 struct nlattr *nest;
337
338 nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_OPTS);
339 if (!nest)
340 return -1;
341
342 if (opts->flags & TUNNEL_VXLAN_OPT) {
343 if (nla_put_be32(skb, NFTA_TUNNEL_KEY_VXLAN_GBP,
344 htonl(opts->u.vxlan.gbp)))
345 return -1;
346 } else if (opts->flags & TUNNEL_ERSPAN_OPT) {
347 switch (opts->u.erspan.version) {
348 case ERSPAN_VERSION:
349 if (nla_put_be32(skb, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
350 opts->u.erspan.u.index))
351 return -1;
352 break;
353 case ERSPAN_VERSION2:
354 if (nla_put_u8(skb, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
355 get_hwid(&opts->u.erspan.u.md2)) ||
356 nla_put_u8(skb, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
357 opts->u.erspan.u.md2.dir))
358 return -1;
359 break;
360 }
361 }
362 nla_nest_end(skb, nest);
363
364 return 0;
365}
366
367static int nft_tunnel_ports_dump(struct sk_buff *skb,
368 struct ip_tunnel_info *info)
369{
370 if (nla_put_be16(skb, NFTA_TUNNEL_KEY_SPORT, htons(info->key.tp_src)) < 0 ||
371 nla_put_be16(skb, NFTA_TUNNEL_KEY_DPORT, htons(info->key.tp_dst)) < 0)
372 return -1;
373
374 return 0;
375}
376
377static int nft_tunnel_flags_dump(struct sk_buff *skb,
378 struct ip_tunnel_info *info)
379{
380 u32 flags = 0;
381
382 if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)
383 flags |= NFT_TUNNEL_F_DONT_FRAGMENT;
384 if (!(info->key.tun_flags & TUNNEL_CSUM))
385 flags |= NFT_TUNNEL_F_ZERO_CSUM_TX;
386 if (info->key.tun_flags & TUNNEL_SEQ)
387 flags |= NFT_TUNNEL_F_SEQ_NUMBER;
388
389 if (nla_put_be32(skb, NFTA_TUNNEL_KEY_FLAGS, htonl(flags)) < 0)
390 return -1;
391
392 return 0;
393}
394
395static int nft_tunnel_obj_dump(struct sk_buff *skb,
396 struct nft_object *obj, bool reset)
397{
398 struct nft_tunnel_obj *priv = nft_obj_data(obj);
399 struct ip_tunnel_info *info = &priv->md->u.tun_info;
400
401 if (nla_put_be32(skb, NFTA_TUNNEL_KEY_ID,
402 tunnel_id_to_key32(info->key.tun_id)) ||
403 nft_tunnel_ip_dump(skb, info) < 0 ||
404 nft_tunnel_ports_dump(skb, info) < 0 ||
405 nft_tunnel_flags_dump(skb, info) < 0 ||
406 nla_put_u8(skb, NFTA_TUNNEL_KEY_TOS, info->key.tos) ||
407 nla_put_u8(skb, NFTA_TUNNEL_KEY_TTL, info->key.ttl) ||
408 nft_tunnel_opts_dump(skb, priv) < 0)
409 goto nla_put_failure;
410
411 return 0;
412
413nla_put_failure:
414 return -1;
415}
416
417static void nft_tunnel_obj_destroy(const struct nft_ctx *ctx,
418 struct nft_object *obj)
419{
420 struct nft_tunnel_obj *priv = nft_obj_data(obj);
421
422 metadata_dst_free(priv->md);
423}
424
425static struct nft_object_type nft_tunnel_obj_type;
426static const struct nft_object_ops nft_tunnel_obj_ops = {
427 .type = &nft_tunnel_obj_type,
428 .size = sizeof(struct nft_tunnel_obj),
429 .eval = nft_tunnel_obj_eval,
430 .init = nft_tunnel_obj_init,
431 .destroy = nft_tunnel_obj_destroy,
432 .dump = nft_tunnel_obj_dump,
433};
434
435static struct nft_object_type nft_tunnel_obj_type __read_mostly = {
436 .type = NFT_OBJECT_TUNNEL,
437 .ops = &nft_tunnel_obj_ops,
438 .maxattr = NFTA_TUNNEL_KEY_MAX,
439 .policy = nft_tunnel_key_policy,
440 .owner = THIS_MODULE,
441};
442
443static int __init nft_tunnel_module_init(void)
444{
445 return nft_register_obj(&nft_tunnel_obj_type);
446}
447
448static void __exit nft_tunnel_module_exit(void)
449{
450 nft_unregister_obj(&nft_tunnel_obj_type);
451}
452
453module_init(nft_tunnel_module_init);
454module_exit(nft_tunnel_module_exit);
455
456MODULE_LICENSE("GPL");
457MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
458MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_TUNNEL);