libnftnl 1.2.9
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_VXLAN_GBP:
61 memcpy(&tun->u.tun_vxlan.gbp, data, data_len);
62 break;
63 case NFTNL_OBJ_TUNNEL_ERSPAN_VERSION:
64 memcpy(&tun->u.tun_erspan.version, data, data_len);
65 break;
66 case NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX:
67 memcpy(&tun->u.tun_erspan.u.v1_index, data, data_len);
68 break;
69 case NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID:
70 memcpy(&tun->u.tun_erspan.u.v2.hwid, data, data_len);
71 break;
72 case NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR:
73 memcpy(&tun->u.tun_erspan.u.v2.dir, data, data_len);
74 break;
75 }
76 return 0;
77}
78
79static const void *
80nftnl_obj_tunnel_get(const struct nftnl_obj *e, uint16_t type,
81 uint32_t *data_len)
82{
83 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
84
85 switch (type) {
86 case NFTNL_OBJ_TUNNEL_ID:
87 *data_len = sizeof(tun->id);
88 return &tun->id;
89 case NFTNL_OBJ_TUNNEL_IPV4_SRC:
90 *data_len = sizeof(tun->src_v4);
91 return &tun->src_v4;
92 case NFTNL_OBJ_TUNNEL_IPV4_DST:
93 *data_len = sizeof(tun->dst_v4);
94 return &tun->dst_v4;
95 case NFTNL_OBJ_TUNNEL_IPV6_SRC:
96 *data_len = sizeof(tun->src_v6);
97 return &tun->src_v6;
98 case NFTNL_OBJ_TUNNEL_IPV6_DST:
99 *data_len = sizeof(tun->dst_v6);
100 return &tun->dst_v6;
101 case NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL:
102 *data_len = sizeof(tun->flowlabel);
103 return &tun->flowlabel;
104 case NFTNL_OBJ_TUNNEL_SPORT:
105 *data_len = sizeof(tun->sport);
106 return &tun->sport;
107 case NFTNL_OBJ_TUNNEL_DPORT:
108 *data_len = sizeof(tun->dport);
109 return &tun->dport;
110 case NFTNL_OBJ_TUNNEL_FLAGS:
111 *data_len = sizeof(tun->tun_flags);
112 return &tun->tun_flags;
113 case NFTNL_OBJ_TUNNEL_TOS:
114 *data_len = sizeof(tun->tun_tos);
115 return &tun->tun_tos;
116 case NFTNL_OBJ_TUNNEL_TTL:
117 *data_len = sizeof(tun->tun_ttl);
118 return &tun->tun_ttl;
119 case NFTNL_OBJ_TUNNEL_VXLAN_GBP:
120 *data_len = sizeof(tun->u.tun_vxlan.gbp);
121 return &tun->u.tun_vxlan.gbp;
122 case NFTNL_OBJ_TUNNEL_ERSPAN_VERSION:
123 *data_len = sizeof(tun->u.tun_erspan.version);
124 return &tun->u.tun_erspan.version;
125 case NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX:
126 *data_len = sizeof(tun->u.tun_erspan.u.v1_index);
127 return &tun->u.tun_erspan.u.v1_index;
128 case NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID:
129 *data_len = sizeof(tun->u.tun_erspan.u.v2.hwid);
130 return &tun->u.tun_erspan.u.v2.hwid;
131 case NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR:
132 *data_len = sizeof(tun->u.tun_erspan.u.v2.dir);
133 return &tun->u.tun_erspan.u.v2.dir;
134 }
135 return NULL;
136}
137
138static int nftnl_obj_tunnel_cb(const struct nlattr *attr, void *data)
139{
140 const struct nlattr **tb = data;
141 int type = mnl_attr_get_type(attr);
142
143 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
144 return MNL_CB_OK;
145
146 switch(type) {
147 case NFTA_TUNNEL_KEY_ID:
148 case NFTA_TUNNEL_KEY_FLAGS:
149 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
150 abi_breakage();
151 break;
152 case NFTA_TUNNEL_KEY_IP:
153 case NFTA_TUNNEL_KEY_IP6:
154 case NFTA_TUNNEL_KEY_OPTS:
155 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
156 abi_breakage();
157 break;
158 case NFTA_TUNNEL_KEY_SPORT:
159 case NFTA_TUNNEL_KEY_DPORT:
160 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
161 abi_breakage();
162 break;
163 case NFTA_TUNNEL_KEY_TOS:
164 case NFTA_TUNNEL_KEY_TTL:
165 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
166 abi_breakage();
167 break;
168 }
169
170 tb[type] = attr;
171 return MNL_CB_OK;
172}
173
174static void
175nftnl_obj_tunnel_build(struct nlmsghdr *nlh, const struct nftnl_obj *e)
176{
177 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
178 struct nlattr *nest, *nest_inner;
179
180 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ID))
181 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ID, htonl(tun->id));
182 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC) ||
183 e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_DST)) {
184 nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_IP);
185 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC))
186 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP_SRC, tun->src_v4);
187 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_DST))
188 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP_DST, tun->dst_v4);
189 mnl_attr_nest_end(nlh, nest);
190 }
191 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC) ||
192 e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_DST)) {
193 nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_IP6);
194 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC))
195 mnl_attr_put(nlh, NFTA_TUNNEL_KEY_IP6_SRC,
196 sizeof(tun->src_v6), &tun->src_v6);
197 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_DST))
198 mnl_attr_put(nlh, NFTA_TUNNEL_KEY_IP6_DST,
199 sizeof(tun->dst_v6), &tun->dst_v6);
200 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL))
201 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
202 htonl(tun->flowlabel));
203 mnl_attr_nest_end(nlh, nest);
204 }
205 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_SPORT))
206 mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_SPORT, htons(tun->sport));
207 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_DPORT))
208 mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_DPORT, htons(tun->dport));
209 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_TOS))
210 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TOS, tun->tun_tos);
211 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_TTL))
212 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TTL, tun->tun_ttl);
213 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_FLAGS))
214 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_FLAGS, htonl(tun->tun_flags));
215 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_VXLAN_GBP)) {
216 nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
217 nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_VXLAN);
218 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP,
219 htonl(tun->u.tun_vxlan.gbp));
220 mnl_attr_nest_end(nlh, nest_inner);
221 mnl_attr_nest_end(nlh, nest);
222 }
223 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_VERSION) &&
224 (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX) ||
225 (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID) &&
226 e->flags & (1u << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR)))) {
227 nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
228 nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN);
229 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION,
230 htonl(tun->u.tun_erspan.version));
231 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX))
232 mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
233 htonl(tun->u.tun_erspan.u.v1_index));
234 if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID))
235 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
236 tun->u.tun_erspan.u.v2.hwid);
237 if (e->flags & (1u << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR))
238 mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
239 tun->u.tun_erspan.u.v2.dir);
240 mnl_attr_nest_end(nlh, nest_inner);
241 mnl_attr_nest_end(nlh, nest);
242 }
243}
244
245static int nftnl_obj_tunnel_ip_cb(const struct nlattr *attr, void *data)
246{
247 const struct nlattr **tb = data;
248 int type = mnl_attr_get_type(attr);
249
250 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
251 return MNL_CB_OK;
252
253 switch (type) {
254 case NFTA_TUNNEL_KEY_IP_SRC:
255 case NFTA_TUNNEL_KEY_IP_DST:
256 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
257 abi_breakage();
258 break;
259 }
260
261 tb[type] = attr;
262 return MNL_CB_OK;
263}
264
265static int nftnl_obj_tunnel_parse_ip(struct nftnl_obj *e, struct nlattr *attr,
266 struct nftnl_obj_tunnel *tun)
267{
268 struct nlattr *tb[NFTA_TUNNEL_KEY_IP_MAX + 1] = {};
269
270 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_ip_cb, tb) < 0)
271 return -1;
272
273 if (tb[NFTA_TUNNEL_KEY_IP_SRC]) {
274 tun->src_v4 = mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP_SRC]);
275 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC);
276 }
277 if (tb[NFTA_TUNNEL_KEY_IP_DST]) {
278 tun->dst_v4 = mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP_DST]);
279 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV4_DST);
280 }
281
282 return 0;
283}
284
285static int nftnl_obj_tunnel_ip6_cb(const struct nlattr *attr, void *data)
286{
287 const struct nlattr **tb = data;
288 int type = mnl_attr_get_type(attr);
289
290 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
291 return MNL_CB_OK;
292
293 switch(type) {
294 case NFTA_TUNNEL_KEY_IP6_SRC:
295 case NFTA_TUNNEL_KEY_IP6_DST:
296 if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
297 abi_breakage();
298 break;
299 case NFTA_TUNNEL_KEY_IP6_FLOWLABEL:
300 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
301 abi_breakage();
302 break;
303 }
304
305 tb[type] = attr;
306 return MNL_CB_OK;
307}
308
309static int nftnl_obj_tunnel_parse_ip6(struct nftnl_obj *e, struct nlattr *attr,
310 struct nftnl_obj_tunnel *tun)
311{
312 struct nlattr *tb[NFTA_TUNNEL_KEY_IP6_MAX + 1] = {};
313
314 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_ip6_cb, tb) < 0)
315 return -1;
316
317 if (tb[NFTA_TUNNEL_KEY_IP6_SRC]) {
318 memcpy(&tun->src_v6,
319 mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_IP6_SRC]),
320 sizeof(struct in6_addr));
321 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC);
322 }
323 if (tb[NFTA_TUNNEL_KEY_IP6_DST]) {
324 memcpy(&tun->dst_v6,
325 mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_IP6_DST]),
326 sizeof(struct in6_addr));
327 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_DST);
328 }
329 if (tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]) {
330 tun->flowlabel =
331 ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]));
332 e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL);
333 }
334
335 return 0;
336}
337
338static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data)
339{
340 const struct nlattr **tb = data;
341 int type = mnl_attr_get_type(attr);
342
343 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_VXLAN_MAX) < 0)
344 return MNL_CB_OK;
345
346 switch (type) {
347 case NFTA_TUNNEL_KEY_VXLAN_GBP:
348 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
349 abi_breakage();
350 break;
351 }
352
353 tb[type] = attr;
354 return MNL_CB_OK;
355}
356
357static int
358nftnl_obj_tunnel_parse_vxlan(struct nftnl_obj *e, struct nlattr *attr,
359 struct nftnl_obj_tunnel *tun)
360{
361 struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = {};
362
363 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_vxlan_cb, tb) < 0)
364 return -1;
365
366 if (tb[NFTA_TUNNEL_KEY_VXLAN_GBP]) {
367 tun->u.tun_vxlan.gbp =
368 ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP]));
369 e->flags |= (1 << NFTNL_OBJ_TUNNEL_VXLAN_GBP);
370 }
371
372 return 0;
373}
374
375static int nftnl_obj_tunnel_erspan_cb(const struct nlattr *attr, void *data)
376{
377 const struct nlattr **tb = data;
378 int type = mnl_attr_get_type(attr);
379
380 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_ERSPAN_MAX) < 0)
381 return MNL_CB_OK;
382
383 switch (type) {
384 case NFTA_TUNNEL_KEY_ERSPAN_VERSION:
385 case NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX:
386 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
387 abi_breakage();
388 break;
389 case NFTA_TUNNEL_KEY_ERSPAN_V2_HWID:
390 case NFTA_TUNNEL_KEY_ERSPAN_V2_DIR:
391 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
392 abi_breakage();
393 break;
394 }
395
396 tb[type] = attr;
397 return MNL_CB_OK;
398}
399
400static int
401nftnl_obj_tunnel_parse_erspan(struct nftnl_obj *e, struct nlattr *attr,
402 struct nftnl_obj_tunnel *tun)
403{
404 struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = {};
405
406 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_erspan_cb, tb) < 0)
407 return -1;
408
409 if (tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]) {
410 tun->u.tun_erspan.version =
411 ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]));
412 e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_VERSION);
413 }
414 if (tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]) {
415 tun->u.tun_erspan.u.v1_index =
416 ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]));
417 e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX);
418 }
419 if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]) {
420 tun->u.tun_erspan.u.v2.hwid =
421 mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]);
422 e->flags |= (1 << NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID);
423 }
424 if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]) {
425 tun->u.tun_erspan.u.v2.dir =
426 mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]);
427 e->flags |= (1u << NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR);
428 }
429
430 return 0;
431}
432
433static int nftnl_obj_tunnel_opts_cb(const struct nlattr *attr, void *data)
434{
435 const struct nlattr **tb = data;
436 int type = mnl_attr_get_type(attr);
437
438 if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_OPTS_MAX) < 0)
439 return MNL_CB_OK;
440
441 switch (type) {
442 case NFTA_TUNNEL_KEY_OPTS_VXLAN:
443 case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
444 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
445 abi_breakage();
446 break;
447 }
448
449 tb[type] = attr;
450 return MNL_CB_OK;
451}
452
453static int
454nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *attr,
455 struct nftnl_obj_tunnel *tun)
456{
457 struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = {};
458 int err = 0;
459
460 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_opts_cb, tb) < 0)
461 return -1;
462
463 if (tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]) {
464 err = nftnl_obj_tunnel_parse_vxlan(e, tb[NFTA_TUNNEL_KEY_OPTS_VXLAN],
465 tun);
466 } else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) {
467 err = nftnl_obj_tunnel_parse_erspan(e, tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN],
468 tun);
469 }
470
471 return err;
472}
473
474static int
475nftnl_obj_tunnel_parse(struct nftnl_obj *e, struct nlattr *attr)
476{
477 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
478 struct nlattr *tb[NFTA_TUNNEL_KEY_MAX + 1] = {};
479 int err;
480
481 if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_cb, tb) < 0)
482 return -1;
483
484 if (tb[NFTA_TUNNEL_KEY_ID]) {
485 tun->id = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ID]));
486 e->flags |= (1 << NFTNL_OBJ_TUNNEL_ID);
487 }
488 if (tb[NFTA_TUNNEL_KEY_IP]) {
489 err = nftnl_obj_tunnel_parse_ip(e, tb[NFTA_TUNNEL_KEY_IP], tun);
490 if (err < 0)
491 return err;
492 } else if (tb[NFTA_TUNNEL_KEY_IP6]) {
493 err = nftnl_obj_tunnel_parse_ip6(e, tb[NFTA_TUNNEL_KEY_IP6], tun);
494 if (err < 0)
495 return err;
496 }
497
498 if (tb[NFTA_TUNNEL_KEY_SPORT]) {
499 tun->sport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_SPORT]));
500 e->flags |= (1 << NFTNL_OBJ_TUNNEL_SPORT);
501 }
502 if (tb[NFTA_TUNNEL_KEY_DPORT]) {
503 tun->dport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_DPORT]));
504 e->flags |= (1 << NFTNL_OBJ_TUNNEL_DPORT);
505 }
506 if (tb[NFTA_TUNNEL_KEY_TOS]) {
507 tun->tun_tos = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TOS]);
508 e->flags |= (1 << NFTNL_OBJ_TUNNEL_TOS);
509 }
510 if (tb[NFTA_TUNNEL_KEY_TTL]) {
511 tun->tun_ttl = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TTL]);
512 e->flags |= (1 << NFTNL_OBJ_TUNNEL_TTL);
513 }
514 if (tb[NFTA_TUNNEL_KEY_FLAGS]) {
515 tun->tun_flags = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_FLAGS]);
516 e->flags |= (1 << NFTNL_OBJ_TUNNEL_FLAGS);
517 }
518 if (tb[NFTA_TUNNEL_KEY_OPTS]) {
519 err = nftnl_obj_tunnel_parse_opts(e, tb[NFTA_TUNNEL_KEY_OPTS], tun);
520 if (err < 0)
521 return err;
522 }
523
524 return 0;
525}
526
527static int nftnl_obj_tunnel_snprintf(char *buf, size_t len,
528 uint32_t flags, const struct nftnl_obj *e)
529{
530 struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
531
532 return snprintf(buf, len, "id %u ", tun->id);
533}
534
535static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = {
536 [NFTNL_OBJ_TUNNEL_ID] = { .maxlen = sizeof(uint32_t) },
537 [NFTNL_OBJ_TUNNEL_IPV4_SRC] = { .maxlen = sizeof(uint32_t) },
538 [NFTNL_OBJ_TUNNEL_IPV4_DST] = { .maxlen = sizeof(uint32_t) },
539 [NFTNL_OBJ_TUNNEL_IPV6_SRC] = { .maxlen = sizeof(struct in6_addr) },
540 [NFTNL_OBJ_TUNNEL_IPV6_DST] = { .maxlen = sizeof(struct in6_addr) },
541 [NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL] = { .maxlen = sizeof(uint32_t) },
542 [NFTNL_OBJ_TUNNEL_SPORT] = { .maxlen = sizeof(uint16_t) },
543 [NFTNL_OBJ_TUNNEL_DPORT] = { .maxlen = sizeof(uint16_t) },
544 [NFTNL_OBJ_TUNNEL_FLAGS] = { .maxlen = sizeof(uint32_t) },
545 [NFTNL_OBJ_TUNNEL_TOS] = { .maxlen = sizeof(uint8_t) },
546 [NFTNL_OBJ_TUNNEL_TTL] = { .maxlen = sizeof(uint8_t) },
547 [NFTNL_OBJ_TUNNEL_VXLAN_GBP] = { .maxlen = sizeof(uint32_t) },
548 [NFTNL_OBJ_TUNNEL_ERSPAN_VERSION] = { .maxlen = sizeof(uint32_t) },
549 [NFTNL_OBJ_TUNNEL_ERSPAN_V1_INDEX] = { .maxlen = sizeof(uint32_t) },
550 [NFTNL_OBJ_TUNNEL_ERSPAN_V2_HWID] = { .maxlen = sizeof(uint8_t) },
551 [NFTNL_OBJ_TUNNEL_ERSPAN_V2_DIR] = { .maxlen = sizeof(uint8_t) },
552};
553
554struct obj_ops obj_ops_tunnel = {
555 .name = "tunnel",
556 .type = NFT_OBJECT_TUNNEL,
557 .alloc_len = sizeof(struct nftnl_obj_tunnel),
558 .nftnl_max_attr = __NFTNL_OBJ_TUNNEL_MAX - 1,
559 .attr_policy = obj_tunnel_attr_policy,
560 .set = nftnl_obj_tunnel_set,
561 .get = nftnl_obj_tunnel_get,
562 .parse = nftnl_obj_tunnel_parse,
563 .build = nftnl_obj_tunnel_build,
564 .output = nftnl_obj_tunnel_snprintf,
565};