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