libnftnl 1.3.2
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 if (len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN) {
600 free(opt);
601 return -1;
602 }
603
604 memcpy(opt->geneve.data,
605 mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]),
606 len);
607 opt->geneve.data_len = len;
608 opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_DATA);
609 }
610
611 list_add_tail(&opt->list, &opts->opts_list);
612
613 return 0;
614}
615
616struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type);
617
618static int
619nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *nest,
620 struct nftnl_obj_tunnel *tun)
621{
622 struct nlattr *attr;
623 struct nftnl_tunnel_opts *opts = NULL;
624 int err = 0;
625
626 mnl_attr_for_each_nested(attr, nest) {
627 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
628 abi_breakage();
629
630 switch(mnl_attr_get_type(attr)) {
631 case NFTA_TUNNEL_KEY_OPTS_VXLAN:
632 opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
633 if (!opts)
634 return -1;
635
636 err = nftnl_obj_tunnel_parse_vxlan(opts, attr);
637 break;
638 case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
639 opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
640 if (!opts)
641 return -1;
642
643 err = nftnl_obj_tunnel_parse_erspan(opts, attr);
644 break;
645 case NFTA_TUNNEL_KEY_OPTS_GENEVE:
646 if (!opts)
647 opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
648
649 if (!opts)
650 return -1;
651
652 err = nftnl_obj_tunnel_parse_geneve(opts, attr);
653 break;
654 }
655 }
656
657 if (opts) {
658 tun->tun_opts = opts;
659 e->flags |= (1 << NFTNL_OBJ_TUNNEL_OPTS);
660 }
661
662 return err;
663}
664
665static int
666nftnl_obj_tunnel_parse(struct nftnl_obj *e, struct nlattr *attr)
667{
668 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
669 struct nlattr *tb[NFTA_TUNNEL_KEY_MAX + 1] = {};
670 int err;
671
672 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_cb, tb) < 0)
673 return -1;
674
675 if (tb[NFTA_TUNNEL_KEY_ID]) {
676 tun->id = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ID]));
677 e->flags |= (1 << NFTNL_OBJ_TUNNEL_ID);
678 }
679 if (tb[NFTA_TUNNEL_KEY_IP]) {
680 err = nftnl_obj_tunnel_parse_ip(e, tb[NFTA_TUNNEL_KEY_IP], tun);
681 if (err < 0)
682 return err;
683 } else if (tb[NFTA_TUNNEL_KEY_IP6]) {
684 err = nftnl_obj_tunnel_parse_ip6(e, tb[NFTA_TUNNEL_KEY_IP6], tun);
685 if (err < 0)
686 return err;
687 }
688
689 if (tb[NFTA_TUNNEL_KEY_SPORT]) {
690 tun->sport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_SPORT]));
691 e->flags |= (1 << NFTNL_OBJ_TUNNEL_SPORT);
692 }
693 if (tb[NFTA_TUNNEL_KEY_DPORT]) {
694 tun->dport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_DPORT]));
695 e->flags |= (1 << NFTNL_OBJ_TUNNEL_DPORT);
696 }
697 if (tb[NFTA_TUNNEL_KEY_TOS]) {
698 tun->tun_tos = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TOS]);
699 e->flags |= (1 << NFTNL_OBJ_TUNNEL_TOS);
700 }
701 if (tb[NFTA_TUNNEL_KEY_TTL]) {
702 tun->tun_ttl = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TTL]);
703 e->flags |= (1 << NFTNL_OBJ_TUNNEL_TTL);
704 }
705 if (tb[NFTA_TUNNEL_KEY_FLAGS]) {
706 tun->tun_flags = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_FLAGS]);
707 e->flags |= (1 << NFTNL_OBJ_TUNNEL_FLAGS);
708 }
709 if (tb[NFTA_TUNNEL_KEY_OPTS]) {
710 err = nftnl_obj_tunnel_parse_opts(e, tb[NFTA_TUNNEL_KEY_OPTS], tun);
711 if (err < 0)
712 return err;
713 }
714
715 return 0;
716}
717
718static int nftnl_obj_tunnel_snprintf(char *buf, size_t len,
719 uint32_t flags, const struct nftnl_obj *e)
720{
721 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
722
723 return snprintf(buf, len, "id %u ", tun->id);
724}
725
726EXPORT_SYMBOL(nftnl_tunnel_opts_alloc);
727struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type)
728{
729 struct nftnl_tunnel_opts *opts;
730
731 switch (type) {
732 case NFTNL_TUNNEL_TYPE_VXLAN:
733 case NFTNL_TUNNEL_TYPE_ERSPAN:
734 case NFTNL_TUNNEL_TYPE_GENEVE:
735 break;
736 default:
737 errno = EOPNOTSUPP;
738 return NULL;
739 }
740
741 opts = calloc(1, sizeof(struct nftnl_tunnel_opts));
742 if (!opts)
743 return NULL;
744
745 opts->type = type;
746 INIT_LIST_HEAD(&opts->opts_list);
747
748 return opts;
749}
750
751EXPORT_SYMBOL(nftnl_tunnel_opts_add);
752int nftnl_tunnel_opts_add(struct nftnl_tunnel_opts *opts,
753 struct nftnl_tunnel_opt *opt)
754{
755 if (opt->type != opts->type) {
756 errno = EOPNOTSUPP;
757 return -1;
758 }
759
760 switch (opts->type) {
761 case NFTNL_TUNNEL_TYPE_VXLAN:
762 case NFTNL_TUNNEL_TYPE_ERSPAN:
763 if (opts->num > 0) {
764 errno = EEXIST;
765 return -1;
766 }
767 break;
768 case NFTNL_TUNNEL_TYPE_GENEVE:
769 break;
770 default:
771 errno = EOPNOTSUPP;
772 return -1;
773 }
774
775 list_add_tail(&opt->list, &opts->opts_list);
776
777 return 0;
778}
779
780EXPORT_SYMBOL(nftnl_tunnel_opts_free);
781void nftnl_tunnel_opts_free(struct nftnl_tunnel_opts *opts)
782{
783 struct nftnl_tunnel_opt *opt, *next;
784
785 list_for_each_entry_safe(opt, next, &opts->opts_list, list) {
786 switch(opts->type) {
787 case NFTNL_TUNNEL_TYPE_VXLAN:
788 case NFTNL_TUNNEL_TYPE_ERSPAN:
789 case NFTNL_TUNNEL_TYPE_GENEVE:
790 list_del(&opt->list);
791 xfree(opt);
792 break;
793 }
794 }
795}
796
797EXPORT_SYMBOL(nftnl_tunnel_opt_alloc);
798struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type)
799{
800 struct nftnl_tunnel_opt *opt;
801
802 switch (type) {
803 case NFTNL_TUNNEL_TYPE_VXLAN:
804 case NFTNL_TUNNEL_TYPE_ERSPAN:
805 case NFTNL_TUNNEL_TYPE_GENEVE:
806 break;
807 default:
808 errno = EOPNOTSUPP;
809 return NULL;
810 }
811
812 opt = calloc(1, sizeof(struct nftnl_tunnel_opt));
813 if (!opt)
814 return NULL;
815
816 opt->type = type;
817
818 return opt;
819}
820
821static int nftnl_tunnel_opt_vxlan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
822 const void *data, uint32_t data_len)
823{
824 switch (type) {
825 case NFTNL_TUNNEL_VXLAN_GBP:
826 memcpy(&opt->vxlan.gbp, data, data_len);
827 break;
828 default:
829 errno = EOPNOTSUPP;
830 return -1;
831 }
832
833 opt->flags |= (1 << type);
834
835 return 0;
836}
837
838static int nftnl_tunnel_opt_erspan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
839 const void *data, uint32_t data_len)
840{
841 switch (type) {
842 case NFTNL_TUNNEL_ERSPAN_VERSION:
843 memcpy(&opt->erspan.version, data, data_len);
844 break;
845 case NFTNL_TUNNEL_ERSPAN_V1_INDEX:
846 memcpy(&opt->erspan.v1.index, data, data_len);
847 break;
848 case NFTNL_TUNNEL_ERSPAN_V2_HWID:
849 memcpy(&opt->erspan.v2.hwid, data, data_len);
850 break;
851 case NFTNL_TUNNEL_ERSPAN_V2_DIR:
852 memcpy(&opt->erspan.v2.dir, data, data_len);
853 break;
854 default:
855 errno = EOPNOTSUPP;
856 return -1;
857 }
858
859 opt->flags |= (1 << type);
860
861 return 0;
862}
863
864static int nftnl_tunnel_opt_geneve_set(struct nftnl_tunnel_opt *opt, uint16_t type,
865 const void *data, uint32_t data_len)
866{
867 switch(type) {
868 case NFTNL_TUNNEL_GENEVE_CLASS:
869 if (data_len != sizeof(uint16_t)) {
870 errno = EINVAL;
871 return -1;
872 }
873 memcpy(&opt->geneve.geneve_class, data, data_len);
874 break;
875 case NFTNL_TUNNEL_GENEVE_TYPE:
876 if (data_len != sizeof(uint8_t)) {
877 errno = EINVAL;
878 return -1;
879 }
880 memcpy(&opt->geneve.type, data, data_len);
881 break;
882 case NFTNL_TUNNEL_GENEVE_DATA:
883 if (data_len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN) {
884 errno = EINVAL;
885 return -1;
886 }
887 memcpy(&opt->geneve.data, data, data_len);
888 opt->geneve.data_len = data_len;
889 break;
890 default:
891 errno = EOPNOTSUPP;
892 return -1;
893 }
894
895 opt->flags |= (1 << type);
896
897 return 0;
898}
899
900EXPORT_SYMBOL(nftnl_tunnel_opt_set);
901int nftnl_tunnel_opt_set(struct nftnl_tunnel_opt *opt, uint16_t type,
902 const void *data, uint32_t data_len)
903{
904 switch (opt->type) {
905 case NFTNL_TUNNEL_TYPE_VXLAN:
906 return nftnl_tunnel_opt_vxlan_set(opt, type, data, data_len);
907 case NFTNL_TUNNEL_TYPE_ERSPAN:
908 return nftnl_tunnel_opt_erspan_set(opt, type, data, data_len);
909 case NFTNL_TUNNEL_TYPE_GENEVE:
910 return nftnl_tunnel_opt_geneve_set(opt, type, data, data_len);
911 default:
912 errno = EOPNOTSUPP;
913 return -1;
914 }
915
916 return 0;
917}
918
919static void nftnl_tunnel_opt_build_vxlan(struct nlmsghdr *nlh,
920 const struct nftnl_tunnel_opt *opt)
921{
922 struct nlattr *nest_inner;
923
924 if (opt->flags & (1 << NFTNL_TUNNEL_VXLAN_GBP)) {
925 nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_VXLAN);
926 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP,
927 htonl(opt->vxlan.gbp));
928 mnl_attr_nest_end(nlh, nest_inner);
929 }
930}
931
932static void nftnl_tunnel_opt_build_erspan(struct nlmsghdr *nlh,
933 const struct nftnl_tunnel_opt *opt)
934{
935 struct nlattr *nest_inner;
936
937 if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_VERSION) &&
938 (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX) ||
939 (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID) &&
940 opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR)))) {
941 nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN);
942 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION,
943 htonl(opt->erspan.version));
944 if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX))
945 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
946 htonl(opt->erspan.v1.index));
947 if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID))
948 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
949 opt->erspan.v2.hwid);
950 if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR))
951 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
952 opt->erspan.v2.dir);
953 mnl_attr_nest_end(nlh, nest_inner);
954 }
955}
956
957static void nftnl_tunnel_opt_build_geneve(struct nlmsghdr *nlh,
958 const struct nftnl_tunnel_opt *opt)
959{
960 struct nlattr *nest_inner;
961
962 if (opt->flags & (1 << NFTNL_TUNNEL_GENEVE_CLASS) &&
963 opt->flags & (1 << NFTNL_TUNNEL_GENEVE_TYPE) &&
964 opt->flags & (1 << NFTNL_TUNNEL_GENEVE_DATA)) {
965 nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_GENEVE);
966 mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_GENEVE_CLASS,
967 htons(opt->geneve.geneve_class));
968 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_GENEVE_TYPE,
969 opt->geneve.type);
970 mnl_attr_put(nlh, NFTA_TUNNEL_KEY_GENEVE_DATA,
971 opt->geneve.data_len,
972 opt->geneve.data);
973 mnl_attr_nest_end(nlh, nest_inner);
974 }
975}
976
977void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
978 struct nftnl_tunnel_opts *opts)
979{
980 const struct nftnl_tunnel_opt *opt;
981 struct nlattr *nest;
982
983 nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
984
985 list_for_each_entry(opt, &opts->opts_list, list) {
986 switch (opts->type) {
987 case NFTNL_TUNNEL_TYPE_VXLAN:
988 nftnl_tunnel_opt_build_vxlan(nlh, opt);
989 break;
990 case NFTNL_TUNNEL_TYPE_ERSPAN:
991 nftnl_tunnel_opt_build_erspan(nlh, opt);
992 break;
993 case NFTNL_TUNNEL_TYPE_GENEVE:
994 nftnl_tunnel_opt_build_geneve(nlh, opt);
995 break;
996 }
997 }
998 mnl_attr_nest_end(nlh, nest);
999}
1000
1001static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = {
1002 [NFTNL_OBJ_TUNNEL_ID] = { .maxlen = sizeof(uint32_t) },
1003 [NFTNL_OBJ_TUNNEL_IPV4_SRC] = { .maxlen = sizeof(uint32_t) },
1004 [NFTNL_OBJ_TUNNEL_IPV4_DST] = { .maxlen = sizeof(uint32_t) },
1005 [NFTNL_OBJ_TUNNEL_IPV6_SRC] = { .maxlen = sizeof(struct in6_addr) },
1006 [NFTNL_OBJ_TUNNEL_IPV6_DST] = { .maxlen = sizeof(struct in6_addr) },
1007 [NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL] = { .maxlen = sizeof(uint32_t) },
1008 [NFTNL_OBJ_TUNNEL_SPORT] = { .maxlen = sizeof(uint16_t) },
1009 [NFTNL_OBJ_TUNNEL_DPORT] = { .maxlen = sizeof(uint16_t) },
1010 [NFTNL_OBJ_TUNNEL_FLAGS] = { .maxlen = sizeof(uint32_t) },
1011 [NFTNL_OBJ_TUNNEL_TOS] = { .maxlen = sizeof(uint8_t) },
1012 [NFTNL_OBJ_TUNNEL_TTL] = { .maxlen = sizeof(uint8_t) },
1013 [NFTNL_OBJ_TUNNEL_OPTS] = { .maxlen = sizeof(struct nftnl_tunnel_opts *) },
1014};
1015
1016struct obj_ops obj_ops_tunnel = {
1017 .name = "tunnel",
1018 .type = NFT_OBJECT_TUNNEL,
1019 .alloc_len = sizeof(struct nftnl_obj_tunnel),
1020 .nftnl_max_attr = __NFTNL_OBJ_TUNNEL_MAX - 1,
1021 .attr_policy = obj_tunnel_attr_policy,
1022 .set = nftnl_obj_tunnel_set,
1023 .get = nftnl_obj_tunnel_get,
1024 .parse = nftnl_obj_tunnel_parse,
1025 .build = nftnl_obj_tunnel_build,
1026 .output = nftnl_obj_tunnel_snprintf,
1027};