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 
20 static int
21 nftnl_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 
79 static const void *
80 nftnl_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 
138 static 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 
174 static void
175 nftnl_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 
245 static 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 
265 static 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 
285 static 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 
309 static 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 
338 static 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 
357 static int
358 nftnl_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 
375 static 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 
400 static int
401 nftnl_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 
433 static 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 
453 static int
454 nftnl_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 
474 static int
475 nftnl_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 
527 static 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 
535 static 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 
554 struct 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 };