libnftnl 1.3.1
obj/tunnel.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * (C) 2018 by Pablo Neira Ayuso <pablo@netfilter.org>
4 */
5
6#include <stdio.h>
7#include <stdint.h>
8#include <arpa/inet.h>
9#include <errno.h>
10#include <inttypes.h>
11
12#include <linux/netfilter/nf_tables.h>
13
14#include <libmnl/libmnl.h>
15#include <libnftnl/object.h>
16
17#include "internal.h"
18#include "obj.h"
19
20static int
21nftnl_obj_tunnel_set(struct nftnl_obj *e, uint16_t type,
22 const void *data, uint32_t data_len)
23{
24 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
25
26 switch (type) {
27 case NFTNL_OBJ_TUNNEL_ID:
28 memcpy(&tun->id, data, data_len);
29 break;
30 case NFTNL_OBJ_TUNNEL_IPV4_SRC:
31 memcpy(&tun->src_v4, data, data_len);
32 break;
33 case NFTNL_OBJ_TUNNEL_IPV4_DST:
34 memcpy(&tun->dst_v4, data, data_len);
35 break;
36 case NFTNL_OBJ_TUNNEL_IPV6_SRC:
37 memcpy(&tun->src_v6, data, data_len);
38 break;
39 case NFTNL_OBJ_TUNNEL_IPV6_DST:
40 memcpy(&tun->dst_v6, data, data_len);
41 break;
42 case NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL:
43 memcpy(&tun->flowlabel, data, data_len);
44 break;
45 case NFTNL_OBJ_TUNNEL_SPORT:
46 memcpy(&tun->sport, data, data_len);
47 break;
48 case NFTNL_OBJ_TUNNEL_DPORT:
49 memcpy(&tun->dport, data, data_len);
50 break;
51 case NFTNL_OBJ_TUNNEL_FLAGS:
52 memcpy(&tun->tun_flags, data, data_len);
53 break;
54 case NFTNL_OBJ_TUNNEL_TOS:
55 memcpy(&tun->tun_tos, data, data_len);
56 break;
57 case NFTNL_OBJ_TUNNEL_TTL:
58 memcpy(&tun->tun_ttl, data, data_len);
59 break;
60 case NFTNL_OBJ_TUNNEL_OPTS:
61 memcpy(&tun->tun_opts, data, data_len);
62 break;
63 }
64 return 0;
65}
66
67static const void *
68nftnl_obj_tunnel_get(const struct nftnl_obj *e, uint16_t type,
69 uint32_t *data_len)
70{
71 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
72
73 switch (type) {
74 case NFTNL_OBJ_TUNNEL_ID:
75 *data_len = sizeof(tun->id);
76 return &tun->id;
77 case NFTNL_OBJ_TUNNEL_IPV4_SRC:
78 *data_len = sizeof(tun->src_v4);
79 return &tun->src_v4;
80 case NFTNL_OBJ_TUNNEL_IPV4_DST:
81 *data_len = sizeof(tun->dst_v4);
82 return &tun->dst_v4;
83 case NFTNL_OBJ_TUNNEL_IPV6_SRC:
84 *data_len = sizeof(tun->src_v6);
85 return &tun->src_v6;
86 case NFTNL_OBJ_TUNNEL_IPV6_DST:
87 *data_len = sizeof(tun->dst_v6);
88 return &tun->dst_v6;
89 case NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL:
90 *data_len = sizeof(tun->flowlabel);
91 return &tun->flowlabel;
92 case NFTNL_OBJ_TUNNEL_SPORT:
93 *data_len = sizeof(tun->sport);
94 return &tun->sport;
95 case NFTNL_OBJ_TUNNEL_DPORT:
96 *data_len = sizeof(tun->dport);
97 return &tun->dport;
98 case NFTNL_OBJ_TUNNEL_FLAGS:
99 *data_len = sizeof(tun->tun_flags);
100 return &tun->tun_flags;
101 case NFTNL_OBJ_TUNNEL_TOS:
102 *data_len = sizeof(tun->tun_tos);
103 return &tun->tun_tos;
104 case NFTNL_OBJ_TUNNEL_TTL:
105 *data_len = sizeof(tun->tun_ttl);
106 return &tun->tun_ttl;
107 case NFTNL_OBJ_TUNNEL_OPTS:
108 *data_len = sizeof(tun->tun_opts);
109 return &tun->tun_opts;
110 }
111 return NULL;
112}
113
114static int nftnl_obj_tunnel_cb(const struct nlattr *attr, void *data)
115{
116 const struct nlattr **tb = data;
117 int type = mnl_attr_get_type(attr);
118
119 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
120 return MNL_CB_OK;
121
122 switch(type) {
123 case NFTA_TUNNEL_KEY_ID:
124 case NFTA_TUNNEL_KEY_FLAGS:
125 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
126 abi_breakage();
127 break;
128 case NFTA_TUNNEL_KEY_IP:
129 case NFTA_TUNNEL_KEY_IP6:
130 case NFTA_TUNNEL_KEY_OPTS:
131 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
132 abi_breakage();
133 break;
134 case NFTA_TUNNEL_KEY_SPORT:
135 case NFTA_TUNNEL_KEY_DPORT:
136 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
137 abi_breakage();
138 break;
139 case NFTA_TUNNEL_KEY_TOS:
140 case NFTA_TUNNEL_KEY_TTL:
141 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
142 abi_breakage();
143 break;
144 }
145
146 tb[type] = attr;
147 return MNL_CB_OK;
148}
149
150static void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
151 struct nftnl_tunnel_opts *opts);
152
153static void
154nftnl_obj_tunnel_build(struct nlmsghdr *nlh, const struct nftnl_obj *e)
155{
156 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
157 struct nlattr *nest;
158
159 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ID))
160 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ID, htonl(tun->id));
161 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC) ||
162 e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_DST)) {
163 nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_IP);
164 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC))
165 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP_SRC, tun->src_v4);
166 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_DST))
167 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP_DST, tun->dst_v4);
168 mnl_attr_nest_end(nlh, nest);
169 }
170 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC) ||
171 e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_DST)) {
172 nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_IP6);
173 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC))
174 mnl_attr_put(nlh, NFTA_TUNNEL_KEY_IP6_SRC,
175 sizeof(tun->src_v6), &tun->src_v6);
176 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_DST))
177 mnl_attr_put(nlh, NFTA_TUNNEL_KEY_IP6_DST,
178 sizeof(tun->dst_v6), &tun->dst_v6);
179 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL))
180 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
181 htonl(tun->flowlabel));
182 mnl_attr_nest_end(nlh, nest);
183 }
184 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_SPORT))
185 mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_SPORT, htons(tun->sport));
186 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_DPORT))
187 mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_DPORT, htons(tun->dport));
188 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_TOS))
189 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TOS, tun->tun_tos);
190 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_TTL))
191 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TTL, tun->tun_ttl);
192 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_FLAGS))
193 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_FLAGS, htonl(tun->tun_flags));
194 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_OPTS))
195 nftnl_tunnel_opts_build(nlh, tun->tun_opts);
196}
197
198static int nftnl_obj_tunnel_ip_cb(const struct nlattr *attr, void *data)
199{
200 const struct nlattr **tb = data;
201 int type = mnl_attr_get_type(attr);
202
203 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
204 return MNL_CB_OK;
205
206 switch (type) {
207 case NFTA_TUNNEL_KEY_IP_SRC:
208 case NFTA_TUNNEL_KEY_IP_DST:
209 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
210 abi_breakage();
211 break;
212 }
213
214 tb[type] = attr;
215 return MNL_CB_OK;
216}
217
218static int nftnl_obj_tunnel_parse_ip(struct nftnl_obj *e, struct nlattr *attr,
219 struct nftnl_obj_tunnel *tun)
220{
221 struct nlattr *tb[NFTA_TUNNEL_KEY_IP_MAX + 1] = {};
222
223 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_ip_cb, tb) < 0)
224 return -1;
225
226 if (tb[NFTA_TUNNEL_KEY_IP_SRC]) {
227 tun->src_v4 = mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP_SRC]);
228 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC);
229 }
230 if (tb[NFTA_TUNNEL_KEY_IP_DST]) {
231 tun->dst_v4 = mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP_DST]);
232 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV4_DST);
233 }
234
235 return 0;
236}
237
238static int nftnl_obj_tunnel_ip6_cb(const struct nlattr *attr, void *data)
239{
240 const struct nlattr **tb = data;
241 int type = mnl_attr_get_type(attr);
242
243 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
244 return MNL_CB_OK;
245
246 switch(type) {
247 case NFTA_TUNNEL_KEY_IP6_SRC:
248 case NFTA_TUNNEL_KEY_IP6_DST:
249 if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
250 abi_breakage();
251 break;
252 case NFTA_TUNNEL_KEY_IP6_FLOWLABEL:
253 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
254 abi_breakage();
255 break;
256 }
257
258 tb[type] = attr;
259 return MNL_CB_OK;
260}
261
262static int nftnl_obj_tunnel_parse_ip6(struct nftnl_obj *e, struct nlattr *attr,
263 struct nftnl_obj_tunnel *tun)
264{
265 struct nlattr *tb[NFTA_TUNNEL_KEY_IP6_MAX + 1] = {};
266
267 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_ip6_cb, tb) < 0)
268 return -1;
269
270 if (tb[NFTA_TUNNEL_KEY_IP6_SRC]) {
271 memcpy(&tun->src_v6,
272 mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_IP6_SRC]),
273 sizeof(struct in6_addr));
274 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC);
275 }
276 if (tb[NFTA_TUNNEL_KEY_IP6_DST]) {
277 memcpy(&tun->dst_v6,
278 mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_IP6_DST]),
279 sizeof(struct in6_addr));
280 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_DST);
281 }
282 if (tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]) {
283 tun->flowlabel =
284 ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]));
285 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL);
286 }
287
288 return 0;
289}
290
292 struct list_head list;
293
294 enum nftnl_tunnel_type type;
295 uint32_t flags;
296
297 union {
298 struct {
299 uint32_t gbp;
300 } vxlan;
301 struct {
302 uint32_t version;
303 struct {
304 uint32_t index;
305 } v1;
306 struct {
307 uint8_t hwid;
308 uint8_t dir;
309 } v2;
310 } erspan;
311 struct {
312 uint16_t geneve_class;
313 uint8_t type;
314 uint8_t data[NFTNL_TUNNEL_GENEVE_DATA_MAXLEN];
315 uint32_t data_len;
316 } geneve;
317 };
318};
319
321 enum nftnl_tunnel_type type;
322 uint32_t num;
323 struct list_head opts_list;
324};
325
326EXPORT_SYMBOL(nftnl_tunnel_opt_get_data);
327const void *nftnl_tunnel_opt_get_data(const struct nftnl_tunnel_opt *ne,
328 uint16_t attr, uint32_t *data_len)
329{
330 if (!(ne->flags & (1 << attr)))
331 return NULL;
332
333 switch (ne->type) {
334 case NFTNL_TUNNEL_TYPE_ERSPAN:
335 switch (attr) {
336 case NFTNL_TUNNEL_ERSPAN_VERSION:
337 *data_len = sizeof(uint32_t);
338 return &ne->erspan.version;
339 case NFTNL_TUNNEL_ERSPAN_V1_INDEX:
340 *data_len = sizeof(uint32_t);
341 return &ne->erspan.v1.index;
342 case NFTNL_TUNNEL_ERSPAN_V2_HWID:
343 *data_len = sizeof(uint8_t);
344 return &ne->erspan.v2.hwid;
345 case NFTNL_TUNNEL_ERSPAN_V2_DIR:
346 *data_len = sizeof(uint8_t);
347 return &ne->erspan.v2.dir;
348 }
349 break;
350 case NFTNL_TUNNEL_TYPE_VXLAN:
351 switch (attr) {
352 case NFTNL_TUNNEL_VXLAN_GBP:
353 *data_len = sizeof(uint32_t);
354 return &ne->vxlan.gbp;
355 }
356 break;
357 case NFTNL_TUNNEL_TYPE_GENEVE:
358 switch (attr) {
359 case NFTNL_TUNNEL_GENEVE_CLASS:
360 *data_len = sizeof(uint16_t);
361 return &ne->geneve.geneve_class;
362 case NFTNL_TUNNEL_GENEVE_TYPE:
363 *data_len = sizeof(uint8_t);
364 return &ne->geneve.type;
365 case NFTNL_TUNNEL_GENEVE_DATA:
366 *data_len = ne->geneve.data_len;
367 return &ne->geneve.data;
368 }
369 break;
370 }
371
372 errno = EOPNOTSUPP;
373 return NULL;
374}
375
376EXPORT_SYMBOL(nftnl_tunnel_opt_get);
377const void *
378nftnl_tunnel_opt_get(const struct nftnl_tunnel_opt *ne, uint16_t attr)
379{
380 uint32_t data_len;
381 return nftnl_tunnel_opt_get_data(ne, attr, &data_len);
382}
383
384EXPORT_SYMBOL(nftnl_tunnel_opt_get_u8);
385uint8_t nftnl_tunnel_opt_get_u8(const struct nftnl_tunnel_opt *ne, uint16_t attr)
386{
387 const void *ret = nftnl_tunnel_opt_get(ne, attr);
388 return ret == NULL ? 0 : *((uint8_t *)ret);
389}
390
391EXPORT_SYMBOL(nftnl_tunnel_opt_get_u16);
392uint16_t nftnl_tunnel_opt_get_u16(const struct nftnl_tunnel_opt *ne, uint16_t attr)
393{
394 const void *ret = nftnl_tunnel_opt_get(ne, attr);
395 return ret == NULL ? 0 : *((uint16_t *)ret);
396}
397
398EXPORT_SYMBOL(nftnl_tunnel_opt_get_u32);
399uint32_t nftnl_tunnel_opt_get_u32(const struct nftnl_tunnel_opt *ne, uint16_t attr)
400{
401 const void *ret = nftnl_tunnel_opt_get(ne, attr);
402 return ret == NULL ? 0 : *((uint32_t *)ret);
403}
404
405EXPORT_SYMBOL(nftnl_tunnel_opt_get_type);
406enum nftnl_tunnel_type nftnl_tunnel_opt_get_type(const struct nftnl_tunnel_opt *ne)
407{
408 return ne->type;
409}
410
411EXPORT_SYMBOL(nftnl_tunnel_opt_get_flags);
412uint32_t nftnl_tunnel_opt_get_flags(const struct nftnl_tunnel_opt *ne)
413{
414 return ne->flags;
415}
416
417EXPORT_SYMBOL(nftnl_obj_tunnel_opts_foreach);
418int nftnl_obj_tunnel_opts_foreach(const struct nftnl_obj *ne,
419 int (*cb)(struct nftnl_tunnel_opt *opt, void *data),
420 void *data)
421{
422 struct nftnl_obj_tunnel *tun = nftnl_obj_data(ne);
423 struct nftnl_tunnel_opt *cur, *tmp;
424 int ret;
425
426 list_for_each_entry_safe(cur, tmp, &tun->tun_opts->opts_list, list) {
427 ret = cb(cur, data);
428 if (ret < 0)
429 return ret;
430 }
431
432 return 0;
433}
434
435static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data)
436{
437 const struct nlattr **tb = data;
438 int type = mnl_attr_get_type(attr);
439
440 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_VXLAN_MAX) < 0)
441 return MNL_CB_OK;
442
443 switch (type) {
444 case NFTA_TUNNEL_KEY_VXLAN_GBP:
445 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
446 abi_breakage();
447 break;
448 }
449
450 tb[type] = attr;
451 return MNL_CB_OK;
452}
453
454struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type);
455
456static int
457nftnl_obj_tunnel_parse_vxlan(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
458{
459 struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = {};
460 struct nftnl_tunnel_opt *opt;
461
462 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_vxlan_cb, tb) < 0)
463 return -1;
464
465 opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
466 if (!opt)
467 return -1;
468
469 if (tb[NFTA_TUNNEL_KEY_VXLAN_GBP]) {
470 opt->vxlan.gbp =
471 ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP]));
472 opt->flags |= (1 << NFTNL_TUNNEL_VXLAN_GBP);
473 }
474
475 list_add_tail(&opt->list, &opts->opts_list);
476
477 return 0;
478}
479
480static int nftnl_obj_tunnel_erspan_cb(const struct nlattr *attr, void *data)
481{
482 const struct nlattr **tb = data;
483 int type = mnl_attr_get_type(attr);
484
485 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_ERSPAN_MAX) < 0)
486 return MNL_CB_OK;
487
488 switch (type) {
489 case NFTA_TUNNEL_KEY_ERSPAN_VERSION:
490 case NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX:
491 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
492 abi_breakage();
493 break;
494 case NFTA_TUNNEL_KEY_ERSPAN_V2_HWID:
495 case NFTA_TUNNEL_KEY_ERSPAN_V2_DIR:
496 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
497 abi_breakage();
498 break;
499 }
500
501 tb[type] = attr;
502 return MNL_CB_OK;
503}
504
505static int
506nftnl_obj_tunnel_parse_erspan(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
507{
508 struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = {};
509 struct nftnl_tunnel_opt *opt;
510
511 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_erspan_cb, tb) < 0)
512 return -1;
513
514 opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
515 if (!opt)
516 return -1;
517
518 if (tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]) {
519 opt->erspan.version =
520 ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]));
521 opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_VERSION);
522 }
523 if (tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]) {
524 opt->erspan.v1.index =
525 ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]));
526 opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX);
527 }
528 if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]) {
529 opt->erspan.v2.hwid =
530 mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]);
531 opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID);
532 }
533 if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]) {
534 opt->erspan.v2.dir =
535 mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]);
536 opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR);
537 }
538
539 list_add_tail(&opt->list, &opts->opts_list);
540
541 return 0;
542}
543
544static int nftnl_obj_tunnel_geneve_cb(const struct nlattr *attr, void *data)
545{
546 const struct nlattr **tb = data;
547 int type = mnl_attr_get_type(attr);
548
549 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_GENEVE_MAX) < 0)
550 return MNL_CB_OK;
551
552 switch (type) {
553 case NFTA_TUNNEL_KEY_GENEVE_CLASS:
554 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
555 abi_breakage();
556 break;
557 case NFTA_TUNNEL_KEY_GENEVE_TYPE:
558 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
559 abi_breakage();
560 break;
561 case NFTA_TUNNEL_KEY_GENEVE_DATA:
562 if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
563 abi_breakage();
564 break;
565 }
566
567 tb[type] = attr;
568 return MNL_CB_OK;
569}
570
571static int
572nftnl_obj_tunnel_parse_geneve(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
573{
574 struct nlattr *tb[NFTA_TUNNEL_KEY_GENEVE_MAX + 1] = {};
575 struct nftnl_tunnel_opt *opt;
576
577 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_geneve_cb, tb) < 0)
578 return -1;
579
580 opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
581 if (!opt)
582 return -1;
583
584 if (tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]) {
585 opt->geneve.geneve_class =
586 ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]));
587 opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_CLASS);
588 }
589
590 if (tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]) {
591 opt->geneve.type =
592 mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]);
593 opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_TYPE);
594 }
595
596 if (tb[NFTA_TUNNEL_KEY_GENEVE_DATA]) {
597 uint32_t len = mnl_attr_get_payload_len(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]);
598
599 memcpy(opt->geneve.data,
600 mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]),
601 len);
602 opt->geneve.data_len = len;
603 opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_DATA);
604 }
605
606 list_add_tail(&opt->list, &opts->opts_list);
607
608 return 0;
609}
610
611struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type);
612
613static int
614nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *nest,
615 struct nftnl_obj_tunnel *tun)
616{
617 struct nlattr *attr;
618 struct nftnl_tunnel_opts *opts = NULL;
619 int err = 0;
620
621 mnl_attr_for_each_nested(attr, nest) {
622 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
623 abi_breakage();
624
625 switch(mnl_attr_get_type(attr)) {
626 case NFTA_TUNNEL_KEY_OPTS_VXLAN:
627 opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
628 if (!opts)
629 return -1;
630
631 err = nftnl_obj_tunnel_parse_vxlan(opts, attr);
632 break;
633 case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
634 opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
635 if (!opts)
636 return -1;
637
638 err = nftnl_obj_tunnel_parse_erspan(opts, attr);
639 break;
640 case NFTA_TUNNEL_KEY_OPTS_GENEVE:
641 if (!opts)
642 opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
643
644 if (!opts)
645 return -1;
646
647 err = nftnl_obj_tunnel_parse_geneve(opts, attr);
648 break;
649 }
650 }
651
652 if (opts) {
653 tun->tun_opts = opts;
654 e->flags |= (1 << NFTNL_OBJ_TUNNEL_OPTS);
655 }
656
657 return err;
658}
659
660static int
661nftnl_obj_tunnel_parse(struct nftnl_obj *e, struct nlattr *attr)
662{
663 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
664 struct nlattr *tb[NFTA_TUNNEL_KEY_MAX + 1] = {};
665 int err;
666
667 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_cb, tb) < 0)
668 return -1;
669
670 if (tb[NFTA_TUNNEL_KEY_ID]) {
671 tun->id = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ID]));
672 e->flags |= (1 << NFTNL_OBJ_TUNNEL_ID);
673 }
674 if (tb[NFTA_TUNNEL_KEY_IP]) {
675 err = nftnl_obj_tunnel_parse_ip(e, tb[NFTA_TUNNEL_KEY_IP], tun);
676 if (err < 0)
677 return err;
678 } else if (tb[NFTA_TUNNEL_KEY_IP6]) {
679 err = nftnl_obj_tunnel_parse_ip6(e, tb[NFTA_TUNNEL_KEY_IP6], tun);
680 if (err < 0)
681 return err;
682 }
683
684 if (tb[NFTA_TUNNEL_KEY_SPORT]) {
685 tun->sport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_SPORT]));
686 e->flags |= (1 << NFTNL_OBJ_TUNNEL_SPORT);
687 }
688 if (tb[NFTA_TUNNEL_KEY_DPORT]) {
689 tun->dport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_DPORT]));
690 e->flags |= (1 << NFTNL_OBJ_TUNNEL_DPORT);
691 }
692 if (tb[NFTA_TUNNEL_KEY_TOS]) {
693 tun->tun_tos = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TOS]);
694 e->flags |= (1 << NFTNL_OBJ_TUNNEL_TOS);
695 }
696 if (tb[NFTA_TUNNEL_KEY_TTL]) {
697 tun->tun_ttl = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TTL]);
698 e->flags |= (1 << NFTNL_OBJ_TUNNEL_TTL);
699 }
700 if (tb[NFTA_TUNNEL_KEY_FLAGS]) {
701 tun->tun_flags = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_FLAGS]);
702 e->flags |= (1 << NFTNL_OBJ_TUNNEL_FLAGS);
703 }
704 if (tb[NFTA_TUNNEL_KEY_OPTS]) {
705 err = nftnl_obj_tunnel_parse_opts(e, tb[NFTA_TUNNEL_KEY_OPTS], tun);
706 if (err < 0)
707 return err;
708 }
709
710 return 0;
711}
712
713static int nftnl_obj_tunnel_snprintf(char *buf, size_t len,
714 uint32_t flags, const struct nftnl_obj *e)
715{
716 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
717
718 return snprintf(buf, len, "id %u ", tun->id);
719}
720
721EXPORT_SYMBOL(nftnl_tunnel_opts_alloc);
722struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type)
723{
724 struct nftnl_tunnel_opts *opts;
725
726 switch (type) {
727 case NFTNL_TUNNEL_TYPE_VXLAN:
728 case NFTNL_TUNNEL_TYPE_ERSPAN:
729 case NFTNL_TUNNEL_TYPE_GENEVE:
730 break;
731 default:
732 errno = EOPNOTSUPP;
733 return NULL;
734 }
735
736 opts = calloc(1, sizeof(struct nftnl_tunnel_opts));
737 if (!opts)
738 return NULL;
739
740 opts->type = type;
741 INIT_LIST_HEAD(&opts->opts_list);
742
743 return opts;
744}
745
746EXPORT_SYMBOL(nftnl_tunnel_opts_add);
747int nftnl_tunnel_opts_add(struct nftnl_tunnel_opts *opts,
748 struct nftnl_tunnel_opt *opt)
749{
750 if (opt->type != opts->type) {
751 errno = EOPNOTSUPP;
752 return -1;
753 }
754
755 switch (opts->type) {
756 case NFTNL_TUNNEL_TYPE_VXLAN:
757 case NFTNL_TUNNEL_TYPE_ERSPAN:
758 if (opts->num > 0) {
759 errno = EEXIST;
760 return -1;
761 }
762 break;
763 case NFTNL_TUNNEL_TYPE_GENEVE:
764 break;
765 default:
766 errno = EOPNOTSUPP;
767 return -1;
768 }
769
770 list_add_tail(&opt->list, &opts->opts_list);
771
772 return 0;
773}
774
775EXPORT_SYMBOL(nftnl_tunnel_opts_free);
776void nftnl_tunnel_opts_free(struct nftnl_tunnel_opts *opts)
777{
778 struct nftnl_tunnel_opt *opt, *next;
779
780 list_for_each_entry_safe(opt, next, &opts->opts_list, list) {
781 switch(opts->type) {
782 case NFTNL_TUNNEL_TYPE_VXLAN:
783 case NFTNL_TUNNEL_TYPE_ERSPAN:
784 case NFTNL_TUNNEL_TYPE_GENEVE:
785 list_del(&opt->list);
786 xfree(opt);
787 break;
788 }
789 }
790}
791
792EXPORT_SYMBOL(nftnl_tunnel_opt_alloc);
793struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type)
794{
795 struct nftnl_tunnel_opt *opt;
796
797 switch (type) {
798 case NFTNL_TUNNEL_TYPE_VXLAN:
799 case NFTNL_TUNNEL_TYPE_ERSPAN:
800 case NFTNL_TUNNEL_TYPE_GENEVE:
801 break;
802 default:
803 errno = EOPNOTSUPP;
804 return NULL;
805 }
806
807 opt = calloc(1, sizeof(struct nftnl_tunnel_opt));
808 if (!opt)
809 return NULL;
810
811 opt->type = type;
812
813 return opt;
814}
815
816static int nftnl_tunnel_opt_vxlan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
817 const void *data, uint32_t data_len)
818{
819 switch (type) {
820 case NFTNL_TUNNEL_VXLAN_GBP:
821 memcpy(&opt->vxlan.gbp, data, data_len);
822 break;
823 default:
824 errno = EOPNOTSUPP;
825 return -1;
826 }
827
828 opt->flags |= (1 << type);
829
830 return 0;
831}
832
833static int nftnl_tunnel_opt_erspan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
834 const void *data, uint32_t data_len)
835{
836 switch (type) {
837 case NFTNL_TUNNEL_ERSPAN_VERSION:
838 memcpy(&opt->erspan.version, data, data_len);
839 break;
840 case NFTNL_TUNNEL_ERSPAN_V1_INDEX:
841 memcpy(&opt->erspan.v1.index, data, data_len);
842 break;
843 case NFTNL_TUNNEL_ERSPAN_V2_HWID:
844 memcpy(&opt->erspan.v2.hwid, data, data_len);
845 break;
846 case NFTNL_TUNNEL_ERSPAN_V2_DIR:
847 memcpy(&opt->erspan.v2.dir, data, data_len);
848 break;
849 default:
850 errno = EOPNOTSUPP;
851 return -1;
852 }
853
854 opt->flags |= (1 << type);
855
856 return 0;
857}
858
859static int nftnl_tunnel_opt_geneve_set(struct nftnl_tunnel_opt *opt, uint16_t type,
860 const void *data, uint32_t data_len)
861{
862 switch(type) {
863 case NFTNL_TUNNEL_GENEVE_CLASS:
864 memcpy(&opt->geneve.geneve_class, data, data_len);
865 break;
866 case NFTNL_TUNNEL_GENEVE_TYPE:
867 memcpy(&opt->geneve.type, data, data_len);
868 break;
869 case NFTNL_TUNNEL_GENEVE_DATA:
870 if (data_len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN) {
871 errno = EINVAL;
872 return -1;
873 }
874 memcpy(&opt->geneve.data, data, data_len);
875 opt->geneve.data_len = data_len;
876 break;
877 default:
878 errno = EOPNOTSUPP;
879 return -1;
880 }
881
882 opt->flags |= (1 << type);
883
884 return 0;
885}
886
887EXPORT_SYMBOL(nftnl_tunnel_opt_set);
888int nftnl_tunnel_opt_set(struct nftnl_tunnel_opt *opt, uint16_t type,
889 const void *data, uint32_t data_len)
890{
891 switch (opt->type) {
892 case NFTNL_TUNNEL_TYPE_VXLAN:
893 return nftnl_tunnel_opt_vxlan_set(opt, type, data, data_len);
894 case NFTNL_TUNNEL_TYPE_ERSPAN:
895 return nftnl_tunnel_opt_erspan_set(opt, type, data, data_len);
896 case NFTNL_TUNNEL_TYPE_GENEVE:
897 return nftnl_tunnel_opt_geneve_set(opt, type, data, data_len);
898 default:
899 errno = EOPNOTSUPP;
900 return -1;
901 }
902
903 return 0;
904}
905
906static void nftnl_tunnel_opt_build_vxlan(struct nlmsghdr *nlh,
907 const struct nftnl_tunnel_opt *opt)
908{
909 struct nlattr *nest_inner;
910
911 if (opt->flags & (1 << NFTNL_TUNNEL_VXLAN_GBP)) {
912 nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_VXLAN);
913 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP,
914 htonl(opt->vxlan.gbp));
915 mnl_attr_nest_end(nlh, nest_inner);
916 }
917}
918
919static void nftnl_tunnel_opt_build_erspan(struct nlmsghdr *nlh,
920 const struct nftnl_tunnel_opt *opt)
921{
922 struct nlattr *nest_inner;
923
924 if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_VERSION) &&
925 (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX) ||
926 (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID) &&
927 opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR)))) {
928 nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN);
929 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION,
930 htonl(opt->erspan.version));
931 if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX))
932 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
933 htonl(opt->erspan.v1.index));
934 if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID))
935 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
936 opt->erspan.v2.hwid);
937 if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR))
938 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
939 opt->erspan.v2.dir);
940 mnl_attr_nest_end(nlh, nest_inner);
941 }
942}
943
944static void nftnl_tunnel_opt_build_geneve(struct nlmsghdr *nlh,
945 const struct nftnl_tunnel_opt *opt)
946{
947 struct nlattr *nest_inner;
948
949 if (opt->flags & (1 << NFTNL_TUNNEL_GENEVE_CLASS) &&
950 opt->flags & (1 << NFTNL_TUNNEL_GENEVE_TYPE) &&
951 opt->flags & (1 << NFTNL_TUNNEL_GENEVE_DATA)) {
952 nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_GENEVE);
953 mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_GENEVE_CLASS,
954 htons(opt->geneve.geneve_class));
955 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_GENEVE_TYPE,
956 opt->geneve.type);
957 mnl_attr_put(nlh, NFTA_TUNNEL_KEY_GENEVE_DATA,
958 opt->geneve.data_len,
959 opt->geneve.data);
960 mnl_attr_nest_end(nlh, nest_inner);
961 }
962}
963
964void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
965 struct nftnl_tunnel_opts *opts)
966{
967 const struct nftnl_tunnel_opt *opt;
968 struct nlattr *nest;
969
970 nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
971
972 list_for_each_entry(opt, &opts->opts_list, list) {
973 switch (opts->type) {
974 case NFTNL_TUNNEL_TYPE_VXLAN:
975 nftnl_tunnel_opt_build_vxlan(nlh, opt);
976 break;
977 case NFTNL_TUNNEL_TYPE_ERSPAN:
978 nftnl_tunnel_opt_build_erspan(nlh, opt);
979 break;
980 case NFTNL_TUNNEL_TYPE_GENEVE:
981 nftnl_tunnel_opt_build_geneve(nlh, opt);
982 break;
983 }
984 }
985 mnl_attr_nest_end(nlh, nest);
986}
987
988static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = {
989 [NFTNL_OBJ_TUNNEL_ID] = { .maxlen = sizeof(uint32_t) },
990 [NFTNL_OBJ_TUNNEL_IPV4_SRC] = { .maxlen = sizeof(uint32_t) },
991 [NFTNL_OBJ_TUNNEL_IPV4_DST] = { .maxlen = sizeof(uint32_t) },
992 [NFTNL_OBJ_TUNNEL_IPV6_SRC] = { .maxlen = sizeof(struct in6_addr) },
993 [NFTNL_OBJ_TUNNEL_IPV6_DST] = { .maxlen = sizeof(struct in6_addr) },
994 [NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL] = { .maxlen = sizeof(uint32_t) },
995 [NFTNL_OBJ_TUNNEL_SPORT] = { .maxlen = sizeof(uint16_t) },
996 [NFTNL_OBJ_TUNNEL_DPORT] = { .maxlen = sizeof(uint16_t) },
997 [NFTNL_OBJ_TUNNEL_FLAGS] = { .maxlen = sizeof(uint32_t) },
998 [NFTNL_OBJ_TUNNEL_TOS] = { .maxlen = sizeof(uint8_t) },
999 [NFTNL_OBJ_TUNNEL_TTL] = { .maxlen = sizeof(uint8_t) },
1000 [NFTNL_OBJ_TUNNEL_OPTS] = { .maxlen = sizeof(struct nftnl_tunnel_opts *) },
1001};
1002
1003struct obj_ops obj_ops_tunnel = {
1004 .name = "tunnel",
1005 .type = NFT_OBJECT_TUNNEL,
1006 .alloc_len = sizeof(struct nftnl_obj_tunnel),
1007 .nftnl_max_attr = __NFTNL_OBJ_TUNNEL_MAX - 1,
1008 .attr_policy = obj_tunnel_attr_policy,
1009 .set = nftnl_obj_tunnel_set,
1010 .get = nftnl_obj_tunnel_get,
1011 .parse = nftnl_obj_tunnel_parse,
1012 .build = nftnl_obj_tunnel_build,
1013 .output = nftnl_obj_tunnel_snprintf,
1014};