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