libnftnl  1.2.0
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, 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 
85 static const void *
86 nftnl_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 
144 static 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 
180 static void
181 nftnl_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 
251 static 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 
271 static 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 
291 static 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 
315 static 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 
344 static 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 
363 static int
364 nftnl_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 
381 static 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 
406 static int
407 nftnl_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 
439 static 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 
459 static int
460 nftnl_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 
480 static int
481 nftnl_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 
533 static 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 
541 struct 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  .snprintf = nftnl_obj_tunnel_snprintf,
551 };