libnftnl  1.3.1
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_OPTS:
61  memcpy(&tun->tun_opts, data, data_len);
62  break;
63  }
64  return 0;
65 }
66 
67 static const void *
68 nftnl_obj_tunnel_get(const struct nftnl_obj *e, uint16_t type,
69  uint32_t *data_len)
70 {
71  struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
72 
73  switch (type) {
74  case NFTNL_OBJ_TUNNEL_ID:
75  *data_len = sizeof(tun->id);
76  return &tun->id;
77  case NFTNL_OBJ_TUNNEL_IPV4_SRC:
78  *data_len = sizeof(tun->src_v4);
79  return &tun->src_v4;
80  case NFTNL_OBJ_TUNNEL_IPV4_DST:
81  *data_len = sizeof(tun->dst_v4);
82  return &tun->dst_v4;
83  case NFTNL_OBJ_TUNNEL_IPV6_SRC:
84  *data_len = sizeof(tun->src_v6);
85  return &tun->src_v6;
86  case NFTNL_OBJ_TUNNEL_IPV6_DST:
87  *data_len = sizeof(tun->dst_v6);
88  return &tun->dst_v6;
89  case NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL:
90  *data_len = sizeof(tun->flowlabel);
91  return &tun->flowlabel;
92  case NFTNL_OBJ_TUNNEL_SPORT:
93  *data_len = sizeof(tun->sport);
94  return &tun->sport;
95  case NFTNL_OBJ_TUNNEL_DPORT:
96  *data_len = sizeof(tun->dport);
97  return &tun->dport;
98  case NFTNL_OBJ_TUNNEL_FLAGS:
99  *data_len = sizeof(tun->tun_flags);
100  return &tun->tun_flags;
101  case NFTNL_OBJ_TUNNEL_TOS:
102  *data_len = sizeof(tun->tun_tos);
103  return &tun->tun_tos;
104  case NFTNL_OBJ_TUNNEL_TTL:
105  *data_len = sizeof(tun->tun_ttl);
106  return &tun->tun_ttl;
107  case NFTNL_OBJ_TUNNEL_OPTS:
108  *data_len = sizeof(tun->tun_opts);
109  return &tun->tun_opts;
110  }
111  return NULL;
112 }
113 
114 static int nftnl_obj_tunnel_cb(const struct nlattr *attr, void *data)
115 {
116  const struct nlattr **tb = data;
117  int type = mnl_attr_get_type(attr);
118 
119  if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
120  return MNL_CB_OK;
121 
122  switch(type) {
123  case NFTA_TUNNEL_KEY_ID:
124  case NFTA_TUNNEL_KEY_FLAGS:
125  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
126  abi_breakage();
127  break;
128  case NFTA_TUNNEL_KEY_IP:
129  case NFTA_TUNNEL_KEY_IP6:
130  case NFTA_TUNNEL_KEY_OPTS:
131  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
132  abi_breakage();
133  break;
134  case NFTA_TUNNEL_KEY_SPORT:
135  case NFTA_TUNNEL_KEY_DPORT:
136  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
137  abi_breakage();
138  break;
139  case NFTA_TUNNEL_KEY_TOS:
140  case NFTA_TUNNEL_KEY_TTL:
141  if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
142  abi_breakage();
143  break;
144  }
145 
146  tb[type] = attr;
147  return MNL_CB_OK;
148 }
149 
150 static void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
151  struct nftnl_tunnel_opts *opts);
152 
153 static void
154 nftnl_obj_tunnel_build(struct nlmsghdr *nlh, const struct nftnl_obj *e)
155 {
156  struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
157  struct nlattr *nest;
158 
159  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_ID))
160  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ID, htonl(tun->id));
161  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC) ||
162  e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_DST)) {
163  nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_IP);
164  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC))
165  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP_SRC, tun->src_v4);
166  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV4_DST))
167  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP_DST, tun->dst_v4);
168  mnl_attr_nest_end(nlh, nest);
169  }
170  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC) ||
171  e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_DST)) {
172  nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_IP6);
173  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC))
174  mnl_attr_put(nlh, NFTA_TUNNEL_KEY_IP6_SRC,
175  sizeof(tun->src_v6), &tun->src_v6);
176  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_DST))
177  mnl_attr_put(nlh, NFTA_TUNNEL_KEY_IP6_DST,
178  sizeof(tun->dst_v6), &tun->dst_v6);
179  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL))
180  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
181  htonl(tun->flowlabel));
182  mnl_attr_nest_end(nlh, nest);
183  }
184  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_SPORT))
185  mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_SPORT, htons(tun->sport));
186  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_DPORT))
187  mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_DPORT, htons(tun->dport));
188  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_TOS))
189  mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TOS, tun->tun_tos);
190  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_TTL))
191  mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_TTL, tun->tun_ttl);
192  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_FLAGS))
193  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_FLAGS, htonl(tun->tun_flags));
194  if (e->flags & (1 << NFTNL_OBJ_TUNNEL_OPTS))
195  nftnl_tunnel_opts_build(nlh, tun->tun_opts);
196 }
197 
198 static int nftnl_obj_tunnel_ip_cb(const struct nlattr *attr, void *data)
199 {
200  const struct nlattr **tb = data;
201  int type = mnl_attr_get_type(attr);
202 
203  if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
204  return MNL_CB_OK;
205 
206  switch (type) {
207  case NFTA_TUNNEL_KEY_IP_SRC:
208  case NFTA_TUNNEL_KEY_IP_DST:
209  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
210  abi_breakage();
211  break;
212  }
213 
214  tb[type] = attr;
215  return MNL_CB_OK;
216 }
217 
218 static int nftnl_obj_tunnel_parse_ip(struct nftnl_obj *e, struct nlattr *attr,
219  struct nftnl_obj_tunnel *tun)
220 {
221  struct nlattr *tb[NFTA_TUNNEL_KEY_IP_MAX + 1] = {};
222 
223  if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_ip_cb, tb) < 0)
224  return -1;
225 
226  if (tb[NFTA_TUNNEL_KEY_IP_SRC]) {
227  tun->src_v4 = mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP_SRC]);
228  e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV4_SRC);
229  }
230  if (tb[NFTA_TUNNEL_KEY_IP_DST]) {
231  tun->dst_v4 = mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP_DST]);
232  e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV4_DST);
233  }
234 
235  return 0;
236 }
237 
238 static int nftnl_obj_tunnel_ip6_cb(const struct nlattr *attr, void *data)
239 {
240  const struct nlattr **tb = data;
241  int type = mnl_attr_get_type(attr);
242 
243  if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_MAX) < 0)
244  return MNL_CB_OK;
245 
246  switch(type) {
247  case NFTA_TUNNEL_KEY_IP6_SRC:
248  case NFTA_TUNNEL_KEY_IP6_DST:
249  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
250  abi_breakage();
251  break;
252  case NFTA_TUNNEL_KEY_IP6_FLOWLABEL:
253  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
254  abi_breakage();
255  break;
256  }
257 
258  tb[type] = attr;
259  return MNL_CB_OK;
260 }
261 
262 static int nftnl_obj_tunnel_parse_ip6(struct nftnl_obj *e, struct nlattr *attr,
263  struct nftnl_obj_tunnel *tun)
264 {
265  struct nlattr *tb[NFTA_TUNNEL_KEY_IP6_MAX + 1] = {};
266 
267  if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_ip6_cb, tb) < 0)
268  return -1;
269 
270  if (tb[NFTA_TUNNEL_KEY_IP6_SRC]) {
271  memcpy(&tun->src_v6,
272  mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_IP6_SRC]),
273  sizeof(struct in6_addr));
274  e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_SRC);
275  }
276  if (tb[NFTA_TUNNEL_KEY_IP6_DST]) {
277  memcpy(&tun->dst_v6,
278  mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_IP6_DST]),
279  sizeof(struct in6_addr));
280  e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_DST);
281  }
282  if (tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]) {
283  tun->flowlabel =
284  ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]));
285  e->flags |= (1 << NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL);
286  }
287 
288  return 0;
289 }
290 
292  struct list_head list;
293 
294  enum nftnl_tunnel_type type;
295  uint32_t flags;
296 
297  union {
298  struct {
299  uint32_t gbp;
300  } vxlan;
301  struct {
302  uint32_t version;
303  struct {
304  uint32_t index;
305  } v1;
306  struct {
307  uint8_t hwid;
308  uint8_t dir;
309  } v2;
310  } erspan;
311  struct {
312  uint16_t geneve_class;
313  uint8_t type;
314  uint8_t data[NFTNL_TUNNEL_GENEVE_DATA_MAXLEN];
315  uint32_t data_len;
316  } geneve;
317  };
318 };
319 
321  enum nftnl_tunnel_type type;
322  uint32_t num;
323  struct list_head opts_list;
324 };
325 
326 EXPORT_SYMBOL(nftnl_tunnel_opt_get_data);
327 const void *nftnl_tunnel_opt_get_data(const struct nftnl_tunnel_opt *ne,
328  uint16_t attr, uint32_t *data_len)
329 {
330  if (!(ne->flags & (1 << attr)))
331  return NULL;
332 
333  switch (ne->type) {
334  case NFTNL_TUNNEL_TYPE_ERSPAN:
335  switch (attr) {
336  case NFTNL_TUNNEL_ERSPAN_VERSION:
337  *data_len = sizeof(uint32_t);
338  return &ne->erspan.version;
339  case NFTNL_TUNNEL_ERSPAN_V1_INDEX:
340  *data_len = sizeof(uint32_t);
341  return &ne->erspan.v1.index;
342  case NFTNL_TUNNEL_ERSPAN_V2_HWID:
343  *data_len = sizeof(uint8_t);
344  return &ne->erspan.v2.hwid;
345  case NFTNL_TUNNEL_ERSPAN_V2_DIR:
346  *data_len = sizeof(uint8_t);
347  return &ne->erspan.v2.dir;
348  }
349  break;
350  case NFTNL_TUNNEL_TYPE_VXLAN:
351  switch (attr) {
352  case NFTNL_TUNNEL_VXLAN_GBP:
353  *data_len = sizeof(uint32_t);
354  return &ne->vxlan.gbp;
355  }
356  break;
357  case NFTNL_TUNNEL_TYPE_GENEVE:
358  switch (attr) {
359  case NFTNL_TUNNEL_GENEVE_CLASS:
360  *data_len = sizeof(uint16_t);
361  return &ne->geneve.geneve_class;
362  case NFTNL_TUNNEL_GENEVE_TYPE:
363  *data_len = sizeof(uint8_t);
364  return &ne->geneve.type;
365  case NFTNL_TUNNEL_GENEVE_DATA:
366  *data_len = ne->geneve.data_len;
367  return &ne->geneve.data;
368  }
369  break;
370  }
371 
372  errno = EOPNOTSUPP;
373  return NULL;
374 }
375 
376 EXPORT_SYMBOL(nftnl_tunnel_opt_get);
377 const void *
378 nftnl_tunnel_opt_get(const struct nftnl_tunnel_opt *ne, uint16_t attr)
379 {
380  uint32_t data_len;
381  return nftnl_tunnel_opt_get_data(ne, attr, &data_len);
382 }
383 
384 EXPORT_SYMBOL(nftnl_tunnel_opt_get_u8);
385 uint8_t nftnl_tunnel_opt_get_u8(const struct nftnl_tunnel_opt *ne, uint16_t attr)
386 {
387  const void *ret = nftnl_tunnel_opt_get(ne, attr);
388  return ret == NULL ? 0 : *((uint8_t *)ret);
389 }
390 
391 EXPORT_SYMBOL(nftnl_tunnel_opt_get_u16);
392 uint16_t nftnl_tunnel_opt_get_u16(const struct nftnl_tunnel_opt *ne, uint16_t attr)
393 {
394  const void *ret = nftnl_tunnel_opt_get(ne, attr);
395  return ret == NULL ? 0 : *((uint16_t *)ret);
396 }
397 
398 EXPORT_SYMBOL(nftnl_tunnel_opt_get_u32);
399 uint32_t nftnl_tunnel_opt_get_u32(const struct nftnl_tunnel_opt *ne, uint16_t attr)
400 {
401  const void *ret = nftnl_tunnel_opt_get(ne, attr);
402  return ret == NULL ? 0 : *((uint32_t *)ret);
403 }
404 
405 EXPORT_SYMBOL(nftnl_tunnel_opt_get_type);
406 enum nftnl_tunnel_type nftnl_tunnel_opt_get_type(const struct nftnl_tunnel_opt *ne)
407 {
408  return ne->type;
409 }
410 
411 EXPORT_SYMBOL(nftnl_tunnel_opt_get_flags);
412 uint32_t nftnl_tunnel_opt_get_flags(const struct nftnl_tunnel_opt *ne)
413 {
414  return ne->flags;
415 }
416 
417 EXPORT_SYMBOL(nftnl_obj_tunnel_opts_foreach);
418 int nftnl_obj_tunnel_opts_foreach(const struct nftnl_obj *ne,
419  int (*cb)(struct nftnl_tunnel_opt *opt, void *data),
420  void *data)
421 {
422  struct nftnl_obj_tunnel *tun = nftnl_obj_data(ne);
423  struct nftnl_tunnel_opt *cur, *tmp;
424  int ret;
425 
426  list_for_each_entry_safe(cur, tmp, &tun->tun_opts->opts_list, list) {
427  ret = cb(cur, data);
428  if (ret < 0)
429  return ret;
430  }
431 
432  return 0;
433 }
434 
435 static int nftnl_obj_tunnel_vxlan_cb(const struct nlattr *attr, void *data)
436 {
437  const struct nlattr **tb = data;
438  int type = mnl_attr_get_type(attr);
439 
440  if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_VXLAN_MAX) < 0)
441  return MNL_CB_OK;
442 
443  switch (type) {
444  case NFTA_TUNNEL_KEY_VXLAN_GBP:
445  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
446  abi_breakage();
447  break;
448  }
449 
450  tb[type] = attr;
451  return MNL_CB_OK;
452 }
453 
454 struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type);
455 
456 static int
457 nftnl_obj_tunnel_parse_vxlan(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
458 {
459  struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = {};
460  struct nftnl_tunnel_opt *opt;
461 
462  if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_vxlan_cb, tb) < 0)
463  return -1;
464 
465  opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
466  if (!opt)
467  return -1;
468 
469  if (tb[NFTA_TUNNEL_KEY_VXLAN_GBP]) {
470  opt->vxlan.gbp =
471  ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP]));
472  opt->flags |= (1 << NFTNL_TUNNEL_VXLAN_GBP);
473  }
474 
475  list_add_tail(&opt->list, &opts->opts_list);
476 
477  return 0;
478 }
479 
480 static int nftnl_obj_tunnel_erspan_cb(const struct nlattr *attr, void *data)
481 {
482  const struct nlattr **tb = data;
483  int type = mnl_attr_get_type(attr);
484 
485  if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_ERSPAN_MAX) < 0)
486  return MNL_CB_OK;
487 
488  switch (type) {
489  case NFTA_TUNNEL_KEY_ERSPAN_VERSION:
490  case NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX:
491  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
492  abi_breakage();
493  break;
494  case NFTA_TUNNEL_KEY_ERSPAN_V2_HWID:
495  case NFTA_TUNNEL_KEY_ERSPAN_V2_DIR:
496  if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
497  abi_breakage();
498  break;
499  }
500 
501  tb[type] = attr;
502  return MNL_CB_OK;
503 }
504 
505 static int
506 nftnl_obj_tunnel_parse_erspan(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
507 {
508  struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = {};
509  struct nftnl_tunnel_opt *opt;
510 
511  if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_erspan_cb, tb) < 0)
512  return -1;
513 
514  opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
515  if (!opt)
516  return -1;
517 
518  if (tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]) {
519  opt->erspan.version =
520  ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION]));
521  opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_VERSION);
522  }
523  if (tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]) {
524  opt->erspan.v1.index =
525  ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]));
526  opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX);
527  }
528  if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]) {
529  opt->erspan.v2.hwid =
530  mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]);
531  opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID);
532  }
533  if (tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]) {
534  opt->erspan.v2.dir =
535  mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]);
536  opt->flags |= (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR);
537  }
538 
539  list_add_tail(&opt->list, &opts->opts_list);
540 
541  return 0;
542 }
543 
544 static int nftnl_obj_tunnel_geneve_cb(const struct nlattr *attr, void *data)
545 {
546  const struct nlattr **tb = data;
547  int type = mnl_attr_get_type(attr);
548 
549  if (mnl_attr_type_valid(attr, NFTA_TUNNEL_KEY_GENEVE_MAX) < 0)
550  return MNL_CB_OK;
551 
552  switch (type) {
553  case NFTA_TUNNEL_KEY_GENEVE_CLASS:
554  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
555  abi_breakage();
556  break;
557  case NFTA_TUNNEL_KEY_GENEVE_TYPE:
558  if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
559  abi_breakage();
560  break;
561  case NFTA_TUNNEL_KEY_GENEVE_DATA:
562  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
563  abi_breakage();
564  break;
565  }
566 
567  tb[type] = attr;
568  return MNL_CB_OK;
569 }
570 
571 static int
572 nftnl_obj_tunnel_parse_geneve(struct nftnl_tunnel_opts *opts, struct nlattr *attr)
573 {
574  struct nlattr *tb[NFTA_TUNNEL_KEY_GENEVE_MAX + 1] = {};
575  struct nftnl_tunnel_opt *opt;
576 
577  if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_geneve_cb, tb) < 0)
578  return -1;
579 
580  opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
581  if (!opt)
582  return -1;
583 
584  if (tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]) {
585  opt->geneve.geneve_class =
586  ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_GENEVE_CLASS]));
587  opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_CLASS);
588  }
589 
590  if (tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]) {
591  opt->geneve.type =
592  mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_GENEVE_TYPE]);
593  opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_TYPE);
594  }
595 
596  if (tb[NFTA_TUNNEL_KEY_GENEVE_DATA]) {
597  uint32_t len = mnl_attr_get_payload_len(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]);
598 
599  memcpy(opt->geneve.data,
600  mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]),
601  len);
602  opt->geneve.data_len = len;
603  opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_DATA);
604  }
605 
606  list_add_tail(&opt->list, &opts->opts_list);
607 
608  return 0;
609 }
610 
611 struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type);
612 
613 static int
614 nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *nest,
615  struct nftnl_obj_tunnel *tun)
616 {
617  struct nlattr *attr;
618  struct nftnl_tunnel_opts *opts = NULL;
619  int err = 0;
620 
621  mnl_attr_for_each_nested(attr, nest) {
622  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
623  abi_breakage();
624 
625  switch(mnl_attr_get_type(attr)) {
626  case NFTA_TUNNEL_KEY_OPTS_VXLAN:
627  opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
628  if (!opts)
629  return -1;
630 
631  err = nftnl_obj_tunnel_parse_vxlan(opts, attr);
632  break;
633  case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
634  opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
635  if (!opts)
636  return -1;
637 
638  err = nftnl_obj_tunnel_parse_erspan(opts, attr);
639  break;
640  case NFTA_TUNNEL_KEY_OPTS_GENEVE:
641  if (!opts)
642  opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
643 
644  if (!opts)
645  return -1;
646 
647  err = nftnl_obj_tunnel_parse_geneve(opts, attr);
648  break;
649  }
650  }
651 
652  if (opts) {
653  tun->tun_opts = opts;
654  e->flags |= (1 << NFTNL_OBJ_TUNNEL_OPTS);
655  }
656 
657  return err;
658 }
659 
660 static int
661 nftnl_obj_tunnel_parse(struct nftnl_obj *e, struct nlattr *attr)
662 {
663  struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
664  struct nlattr *tb[NFTA_TUNNEL_KEY_MAX + 1] = {};
665  int err;
666 
667  if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_cb, tb) < 0)
668  return -1;
669 
670  if (tb[NFTA_TUNNEL_KEY_ID]) {
671  tun->id = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ID]));
672  e->flags |= (1 << NFTNL_OBJ_TUNNEL_ID);
673  }
674  if (tb[NFTA_TUNNEL_KEY_IP]) {
675  err = nftnl_obj_tunnel_parse_ip(e, tb[NFTA_TUNNEL_KEY_IP], tun);
676  if (err < 0)
677  return err;
678  } else if (tb[NFTA_TUNNEL_KEY_IP6]) {
679  err = nftnl_obj_tunnel_parse_ip6(e, tb[NFTA_TUNNEL_KEY_IP6], tun);
680  if (err < 0)
681  return err;
682  }
683 
684  if (tb[NFTA_TUNNEL_KEY_SPORT]) {
685  tun->sport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_SPORT]));
686  e->flags |= (1 << NFTNL_OBJ_TUNNEL_SPORT);
687  }
688  if (tb[NFTA_TUNNEL_KEY_DPORT]) {
689  tun->dport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_DPORT]));
690  e->flags |= (1 << NFTNL_OBJ_TUNNEL_DPORT);
691  }
692  if (tb[NFTA_TUNNEL_KEY_TOS]) {
693  tun->tun_tos = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TOS]);
694  e->flags |= (1 << NFTNL_OBJ_TUNNEL_TOS);
695  }
696  if (tb[NFTA_TUNNEL_KEY_TTL]) {
697  tun->tun_ttl = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TTL]);
698  e->flags |= (1 << NFTNL_OBJ_TUNNEL_TTL);
699  }
700  if (tb[NFTA_TUNNEL_KEY_FLAGS]) {
701  tun->tun_flags = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_FLAGS]);
702  e->flags |= (1 << NFTNL_OBJ_TUNNEL_FLAGS);
703  }
704  if (tb[NFTA_TUNNEL_KEY_OPTS]) {
705  err = nftnl_obj_tunnel_parse_opts(e, tb[NFTA_TUNNEL_KEY_OPTS], tun);
706  if (err < 0)
707  return err;
708  }
709 
710  return 0;
711 }
712 
713 static int nftnl_obj_tunnel_snprintf(char *buf, size_t len,
714  uint32_t flags, const struct nftnl_obj *e)
715 {
716  struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
717 
718  return snprintf(buf, len, "id %u ", tun->id);
719 }
720 
721 EXPORT_SYMBOL(nftnl_tunnel_opts_alloc);
722 struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type)
723 {
724  struct nftnl_tunnel_opts *opts;
725 
726  switch (type) {
727  case NFTNL_TUNNEL_TYPE_VXLAN:
728  case NFTNL_TUNNEL_TYPE_ERSPAN:
729  case NFTNL_TUNNEL_TYPE_GENEVE:
730  break;
731  default:
732  errno = EOPNOTSUPP;
733  return NULL;
734  }
735 
736  opts = calloc(1, sizeof(struct nftnl_tunnel_opts));
737  if (!opts)
738  return NULL;
739 
740  opts->type = type;
741  INIT_LIST_HEAD(&opts->opts_list);
742 
743  return opts;
744 }
745 
746 EXPORT_SYMBOL(nftnl_tunnel_opts_add);
747 int nftnl_tunnel_opts_add(struct nftnl_tunnel_opts *opts,
748  struct nftnl_tunnel_opt *opt)
749 {
750  if (opt->type != opts->type) {
751  errno = EOPNOTSUPP;
752  return -1;
753  }
754 
755  switch (opts->type) {
756  case NFTNL_TUNNEL_TYPE_VXLAN:
757  case NFTNL_TUNNEL_TYPE_ERSPAN:
758  if (opts->num > 0) {
759  errno = EEXIST;
760  return -1;
761  }
762  break;
763  case NFTNL_TUNNEL_TYPE_GENEVE:
764  break;
765  default:
766  errno = EOPNOTSUPP;
767  return -1;
768  }
769 
770  list_add_tail(&opt->list, &opts->opts_list);
771 
772  return 0;
773 }
774 
775 EXPORT_SYMBOL(nftnl_tunnel_opts_free);
776 void nftnl_tunnel_opts_free(struct nftnl_tunnel_opts *opts)
777 {
778  struct nftnl_tunnel_opt *opt, *next;
779 
780  list_for_each_entry_safe(opt, next, &opts->opts_list, list) {
781  switch(opts->type) {
782  case NFTNL_TUNNEL_TYPE_VXLAN:
783  case NFTNL_TUNNEL_TYPE_ERSPAN:
784  case NFTNL_TUNNEL_TYPE_GENEVE:
785  list_del(&opt->list);
786  xfree(opt);
787  break;
788  }
789  }
790 }
791 
792 EXPORT_SYMBOL(nftnl_tunnel_opt_alloc);
793 struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type)
794 {
795  struct nftnl_tunnel_opt *opt;
796 
797  switch (type) {
798  case NFTNL_TUNNEL_TYPE_VXLAN:
799  case NFTNL_TUNNEL_TYPE_ERSPAN:
800  case NFTNL_TUNNEL_TYPE_GENEVE:
801  break;
802  default:
803  errno = EOPNOTSUPP;
804  return NULL;
805  }
806 
807  opt = calloc(1, sizeof(struct nftnl_tunnel_opt));
808  if (!opt)
809  return NULL;
810 
811  opt->type = type;
812 
813  return opt;
814 }
815 
816 static int nftnl_tunnel_opt_vxlan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
817  const void *data, uint32_t data_len)
818 {
819  switch (type) {
820  case NFTNL_TUNNEL_VXLAN_GBP:
821  memcpy(&opt->vxlan.gbp, data, data_len);
822  break;
823  default:
824  errno = EOPNOTSUPP;
825  return -1;
826  }
827 
828  opt->flags |= (1 << type);
829 
830  return 0;
831 }
832 
833 static int nftnl_tunnel_opt_erspan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
834  const void *data, uint32_t data_len)
835 {
836  switch (type) {
837  case NFTNL_TUNNEL_ERSPAN_VERSION:
838  memcpy(&opt->erspan.version, data, data_len);
839  break;
840  case NFTNL_TUNNEL_ERSPAN_V1_INDEX:
841  memcpy(&opt->erspan.v1.index, data, data_len);
842  break;
843  case NFTNL_TUNNEL_ERSPAN_V2_HWID:
844  memcpy(&opt->erspan.v2.hwid, data, data_len);
845  break;
846  case NFTNL_TUNNEL_ERSPAN_V2_DIR:
847  memcpy(&opt->erspan.v2.dir, data, data_len);
848  break;
849  default:
850  errno = EOPNOTSUPP;
851  return -1;
852  }
853 
854  opt->flags |= (1 << type);
855 
856  return 0;
857 }
858 
859 static int nftnl_tunnel_opt_geneve_set(struct nftnl_tunnel_opt *opt, uint16_t type,
860  const void *data, uint32_t data_len)
861 {
862  switch(type) {
863  case NFTNL_TUNNEL_GENEVE_CLASS:
864  memcpy(&opt->geneve.geneve_class, data, data_len);
865  break;
866  case NFTNL_TUNNEL_GENEVE_TYPE:
867  memcpy(&opt->geneve.type, data, data_len);
868  break;
869  case NFTNL_TUNNEL_GENEVE_DATA:
870  if (data_len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN) {
871  errno = EINVAL;
872  return -1;
873  }
874  memcpy(&opt->geneve.data, data, data_len);
875  opt->geneve.data_len = data_len;
876  break;
877  default:
878  errno = EOPNOTSUPP;
879  return -1;
880  }
881 
882  opt->flags |= (1 << type);
883 
884  return 0;
885 }
886 
887 EXPORT_SYMBOL(nftnl_tunnel_opt_set);
888 int nftnl_tunnel_opt_set(struct nftnl_tunnel_opt *opt, uint16_t type,
889  const void *data, uint32_t data_len)
890 {
891  switch (opt->type) {
892  case NFTNL_TUNNEL_TYPE_VXLAN:
893  return nftnl_tunnel_opt_vxlan_set(opt, type, data, data_len);
894  case NFTNL_TUNNEL_TYPE_ERSPAN:
895  return nftnl_tunnel_opt_erspan_set(opt, type, data, data_len);
896  case NFTNL_TUNNEL_TYPE_GENEVE:
897  return nftnl_tunnel_opt_geneve_set(opt, type, data, data_len);
898  default:
899  errno = EOPNOTSUPP;
900  return -1;
901  }
902 
903  return 0;
904 }
905 
906 static void nftnl_tunnel_opt_build_vxlan(struct nlmsghdr *nlh,
907  const struct nftnl_tunnel_opt *opt)
908 {
909  struct nlattr *nest_inner;
910 
911  if (opt->flags & (1 << NFTNL_TUNNEL_VXLAN_GBP)) {
912  nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_VXLAN);
913  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP,
914  htonl(opt->vxlan.gbp));
915  mnl_attr_nest_end(nlh, nest_inner);
916  }
917 }
918 
919 static void nftnl_tunnel_opt_build_erspan(struct nlmsghdr *nlh,
920  const struct nftnl_tunnel_opt *opt)
921 {
922  struct nlattr *nest_inner;
923 
924  if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_VERSION) &&
925  (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX) ||
926  (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID) &&
927  opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR)))) {
928  nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN);
929  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION,
930  htonl(opt->erspan.version));
931  if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX))
932  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
933  htonl(opt->erspan.v1.index));
934  if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID))
935  mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
936  opt->erspan.v2.hwid);
937  if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR))
938  mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
939  opt->erspan.v2.dir);
940  mnl_attr_nest_end(nlh, nest_inner);
941  }
942 }
943 
944 static void nftnl_tunnel_opt_build_geneve(struct nlmsghdr *nlh,
945  const struct nftnl_tunnel_opt *opt)
946 {
947  struct nlattr *nest_inner;
948 
949  if (opt->flags & (1 << NFTNL_TUNNEL_GENEVE_CLASS) &&
950  opt->flags & (1 << NFTNL_TUNNEL_GENEVE_TYPE) &&
951  opt->flags & (1 << NFTNL_TUNNEL_GENEVE_DATA)) {
952  nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_GENEVE);
953  mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_GENEVE_CLASS,
954  htons(opt->geneve.geneve_class));
955  mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_GENEVE_TYPE,
956  opt->geneve.type);
957  mnl_attr_put(nlh, NFTA_TUNNEL_KEY_GENEVE_DATA,
958  opt->geneve.data_len,
959  opt->geneve.data);
960  mnl_attr_nest_end(nlh, nest_inner);
961  }
962 }
963 
964 void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
965  struct nftnl_tunnel_opts *opts)
966 {
967  const struct nftnl_tunnel_opt *opt;
968  struct nlattr *nest;
969 
970  nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
971 
972  list_for_each_entry(opt, &opts->opts_list, list) {
973  switch (opts->type) {
974  case NFTNL_TUNNEL_TYPE_VXLAN:
975  nftnl_tunnel_opt_build_vxlan(nlh, opt);
976  break;
977  case NFTNL_TUNNEL_TYPE_ERSPAN:
978  nftnl_tunnel_opt_build_erspan(nlh, opt);
979  break;
980  case NFTNL_TUNNEL_TYPE_GENEVE:
981  nftnl_tunnel_opt_build_geneve(nlh, opt);
982  break;
983  }
984  }
985  mnl_attr_nest_end(nlh, nest);
986 }
987 
988 static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = {
989  [NFTNL_OBJ_TUNNEL_ID] = { .maxlen = sizeof(uint32_t) },
990  [NFTNL_OBJ_TUNNEL_IPV4_SRC] = { .maxlen = sizeof(uint32_t) },
991  [NFTNL_OBJ_TUNNEL_IPV4_DST] = { .maxlen = sizeof(uint32_t) },
992  [NFTNL_OBJ_TUNNEL_IPV6_SRC] = { .maxlen = sizeof(struct in6_addr) },
993  [NFTNL_OBJ_TUNNEL_IPV6_DST] = { .maxlen = sizeof(struct in6_addr) },
994  [NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL] = { .maxlen = sizeof(uint32_t) },
995  [NFTNL_OBJ_TUNNEL_SPORT] = { .maxlen = sizeof(uint16_t) },
996  [NFTNL_OBJ_TUNNEL_DPORT] = { .maxlen = sizeof(uint16_t) },
997  [NFTNL_OBJ_TUNNEL_FLAGS] = { .maxlen = sizeof(uint32_t) },
998  [NFTNL_OBJ_TUNNEL_TOS] = { .maxlen = sizeof(uint8_t) },
999  [NFTNL_OBJ_TUNNEL_TTL] = { .maxlen = sizeof(uint8_t) },
1000  [NFTNL_OBJ_TUNNEL_OPTS] = { .maxlen = sizeof(struct nftnl_tunnel_opts *) },
1001 };
1002 
1003 struct obj_ops obj_ops_tunnel = {
1004  .name = "tunnel",
1005  .type = NFT_OBJECT_TUNNEL,
1006  .alloc_len = sizeof(struct nftnl_obj_tunnel),
1007  .nftnl_max_attr = __NFTNL_OBJ_TUNNEL_MAX - 1,
1008  .attr_policy = obj_tunnel_attr_policy,
1009  .set = nftnl_obj_tunnel_set,
1010  .get = nftnl_obj_tunnel_get,
1011  .parse = nftnl_obj_tunnel_parse,
1012  .build = nftnl_obj_tunnel_build,
1013  .output = nftnl_obj_tunnel_snprintf,
1014 };