libnftnl  1.2.8
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 
24 static int
25 nftnl_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 
83 static const void *
84 nftnl_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 
142 static 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 
178 static void
179 nftnl_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 
249 static 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 
269 static 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 
289 static 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 
313 static 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 
342 static 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 
361 static int
362 nftnl_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 
379 static 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 
404 static int
405 nftnl_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 
437 static 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 
457 static int
458 nftnl_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 
478 static int
479 nftnl_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 
531 static 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 
539 static 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 
558 struct 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 };