libnftnl  1.3.2
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  if (len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN) {
600  free(opt);
601  return -1;
602  }
603 
604  memcpy(opt->geneve.data,
605  mnl_attr_get_payload(tb[NFTA_TUNNEL_KEY_GENEVE_DATA]),
606  len);
607  opt->geneve.data_len = len;
608  opt->flags |= (1 << NFTNL_TUNNEL_GENEVE_DATA);
609  }
610 
611  list_add_tail(&opt->list, &opts->opts_list);
612 
613  return 0;
614 }
615 
616 struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type);
617 
618 static int
619 nftnl_obj_tunnel_parse_opts(struct nftnl_obj *e, struct nlattr *nest,
620  struct nftnl_obj_tunnel *tun)
621 {
622  struct nlattr *attr;
623  struct nftnl_tunnel_opts *opts = NULL;
624  int err = 0;
625 
626  mnl_attr_for_each_nested(attr, nest) {
627  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
628  abi_breakage();
629 
630  switch(mnl_attr_get_type(attr)) {
631  case NFTA_TUNNEL_KEY_OPTS_VXLAN:
632  opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_VXLAN);
633  if (!opts)
634  return -1;
635 
636  err = nftnl_obj_tunnel_parse_vxlan(opts, attr);
637  break;
638  case NFTA_TUNNEL_KEY_OPTS_ERSPAN:
639  opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
640  if (!opts)
641  return -1;
642 
643  err = nftnl_obj_tunnel_parse_erspan(opts, attr);
644  break;
645  case NFTA_TUNNEL_KEY_OPTS_GENEVE:
646  if (!opts)
647  opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
648 
649  if (!opts)
650  return -1;
651 
652  err = nftnl_obj_tunnel_parse_geneve(opts, attr);
653  break;
654  }
655  }
656 
657  if (opts) {
658  tun->tun_opts = opts;
659  e->flags |= (1 << NFTNL_OBJ_TUNNEL_OPTS);
660  }
661 
662  return err;
663 }
664 
665 static int
666 nftnl_obj_tunnel_parse(struct nftnl_obj *e, struct nlattr *attr)
667 {
668  struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
669  struct nlattr *tb[NFTA_TUNNEL_KEY_MAX + 1] = {};
670  int err;
671 
672  if (mnl_attr_parse_nested(attr, nftnl_obj_tunnel_cb, tb) < 0)
673  return -1;
674 
675  if (tb[NFTA_TUNNEL_KEY_ID]) {
676  tun->id = ntohl(mnl_attr_get_u32(tb[NFTA_TUNNEL_KEY_ID]));
677  e->flags |= (1 << NFTNL_OBJ_TUNNEL_ID);
678  }
679  if (tb[NFTA_TUNNEL_KEY_IP]) {
680  err = nftnl_obj_tunnel_parse_ip(e, tb[NFTA_TUNNEL_KEY_IP], tun);
681  if (err < 0)
682  return err;
683  } else if (tb[NFTA_TUNNEL_KEY_IP6]) {
684  err = nftnl_obj_tunnel_parse_ip6(e, tb[NFTA_TUNNEL_KEY_IP6], tun);
685  if (err < 0)
686  return err;
687  }
688 
689  if (tb[NFTA_TUNNEL_KEY_SPORT]) {
690  tun->sport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_SPORT]));
691  e->flags |= (1 << NFTNL_OBJ_TUNNEL_SPORT);
692  }
693  if (tb[NFTA_TUNNEL_KEY_DPORT]) {
694  tun->dport = ntohs(mnl_attr_get_u16(tb[NFTA_TUNNEL_KEY_DPORT]));
695  e->flags |= (1 << NFTNL_OBJ_TUNNEL_DPORT);
696  }
697  if (tb[NFTA_TUNNEL_KEY_TOS]) {
698  tun->tun_tos = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TOS]);
699  e->flags |= (1 << NFTNL_OBJ_TUNNEL_TOS);
700  }
701  if (tb[NFTA_TUNNEL_KEY_TTL]) {
702  tun->tun_ttl = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_TTL]);
703  e->flags |= (1 << NFTNL_OBJ_TUNNEL_TTL);
704  }
705  if (tb[NFTA_TUNNEL_KEY_FLAGS]) {
706  tun->tun_flags = mnl_attr_get_u8(tb[NFTA_TUNNEL_KEY_FLAGS]);
707  e->flags |= (1 << NFTNL_OBJ_TUNNEL_FLAGS);
708  }
709  if (tb[NFTA_TUNNEL_KEY_OPTS]) {
710  err = nftnl_obj_tunnel_parse_opts(e, tb[NFTA_TUNNEL_KEY_OPTS], tun);
711  if (err < 0)
712  return err;
713  }
714 
715  return 0;
716 }
717 
718 static int nftnl_obj_tunnel_snprintf(char *buf, size_t len,
719  uint32_t flags, const struct nftnl_obj *e)
720 {
721  struct nftnl_obj_tunnel *tun = nftnl_obj_data(e);
722 
723  return snprintf(buf, len, "id %u ", tun->id);
724 }
725 
726 EXPORT_SYMBOL(nftnl_tunnel_opts_alloc);
727 struct nftnl_tunnel_opts *nftnl_tunnel_opts_alloc(enum nftnl_tunnel_type type)
728 {
729  struct nftnl_tunnel_opts *opts;
730 
731  switch (type) {
732  case NFTNL_TUNNEL_TYPE_VXLAN:
733  case NFTNL_TUNNEL_TYPE_ERSPAN:
734  case NFTNL_TUNNEL_TYPE_GENEVE:
735  break;
736  default:
737  errno = EOPNOTSUPP;
738  return NULL;
739  }
740 
741  opts = calloc(1, sizeof(struct nftnl_tunnel_opts));
742  if (!opts)
743  return NULL;
744 
745  opts->type = type;
746  INIT_LIST_HEAD(&opts->opts_list);
747 
748  return opts;
749 }
750 
751 EXPORT_SYMBOL(nftnl_tunnel_opts_add);
752 int nftnl_tunnel_opts_add(struct nftnl_tunnel_opts *opts,
753  struct nftnl_tunnel_opt *opt)
754 {
755  if (opt->type != opts->type) {
756  errno = EOPNOTSUPP;
757  return -1;
758  }
759 
760  switch (opts->type) {
761  case NFTNL_TUNNEL_TYPE_VXLAN:
762  case NFTNL_TUNNEL_TYPE_ERSPAN:
763  if (opts->num > 0) {
764  errno = EEXIST;
765  return -1;
766  }
767  break;
768  case NFTNL_TUNNEL_TYPE_GENEVE:
769  break;
770  default:
771  errno = EOPNOTSUPP;
772  return -1;
773  }
774 
775  list_add_tail(&opt->list, &opts->opts_list);
776 
777  return 0;
778 }
779 
780 EXPORT_SYMBOL(nftnl_tunnel_opts_free);
781 void nftnl_tunnel_opts_free(struct nftnl_tunnel_opts *opts)
782 {
783  struct nftnl_tunnel_opt *opt, *next;
784 
785  list_for_each_entry_safe(opt, next, &opts->opts_list, list) {
786  switch(opts->type) {
787  case NFTNL_TUNNEL_TYPE_VXLAN:
788  case NFTNL_TUNNEL_TYPE_ERSPAN:
789  case NFTNL_TUNNEL_TYPE_GENEVE:
790  list_del(&opt->list);
791  xfree(opt);
792  break;
793  }
794  }
795 }
796 
797 EXPORT_SYMBOL(nftnl_tunnel_opt_alloc);
798 struct nftnl_tunnel_opt *nftnl_tunnel_opt_alloc(enum nftnl_tunnel_type type)
799 {
800  struct nftnl_tunnel_opt *opt;
801 
802  switch (type) {
803  case NFTNL_TUNNEL_TYPE_VXLAN:
804  case NFTNL_TUNNEL_TYPE_ERSPAN:
805  case NFTNL_TUNNEL_TYPE_GENEVE:
806  break;
807  default:
808  errno = EOPNOTSUPP;
809  return NULL;
810  }
811 
812  opt = calloc(1, sizeof(struct nftnl_tunnel_opt));
813  if (!opt)
814  return NULL;
815 
816  opt->type = type;
817 
818  return opt;
819 }
820 
821 static int nftnl_tunnel_opt_vxlan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
822  const void *data, uint32_t data_len)
823 {
824  switch (type) {
825  case NFTNL_TUNNEL_VXLAN_GBP:
826  memcpy(&opt->vxlan.gbp, data, data_len);
827  break;
828  default:
829  errno = EOPNOTSUPP;
830  return -1;
831  }
832 
833  opt->flags |= (1 << type);
834 
835  return 0;
836 }
837 
838 static int nftnl_tunnel_opt_erspan_set(struct nftnl_tunnel_opt *opt, uint16_t type,
839  const void *data, uint32_t data_len)
840 {
841  switch (type) {
842  case NFTNL_TUNNEL_ERSPAN_VERSION:
843  memcpy(&opt->erspan.version, data, data_len);
844  break;
845  case NFTNL_TUNNEL_ERSPAN_V1_INDEX:
846  memcpy(&opt->erspan.v1.index, data, data_len);
847  break;
848  case NFTNL_TUNNEL_ERSPAN_V2_HWID:
849  memcpy(&opt->erspan.v2.hwid, data, data_len);
850  break;
851  case NFTNL_TUNNEL_ERSPAN_V2_DIR:
852  memcpy(&opt->erspan.v2.dir, data, data_len);
853  break;
854  default:
855  errno = EOPNOTSUPP;
856  return -1;
857  }
858 
859  opt->flags |= (1 << type);
860 
861  return 0;
862 }
863 
864 static int nftnl_tunnel_opt_geneve_set(struct nftnl_tunnel_opt *opt, uint16_t type,
865  const void *data, uint32_t data_len)
866 {
867  switch(type) {
868  case NFTNL_TUNNEL_GENEVE_CLASS:
869  if (data_len != sizeof(uint16_t)) {
870  errno = EINVAL;
871  return -1;
872  }
873  memcpy(&opt->geneve.geneve_class, data, data_len);
874  break;
875  case NFTNL_TUNNEL_GENEVE_TYPE:
876  if (data_len != sizeof(uint8_t)) {
877  errno = EINVAL;
878  return -1;
879  }
880  memcpy(&opt->geneve.type, data, data_len);
881  break;
882  case NFTNL_TUNNEL_GENEVE_DATA:
883  if (data_len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN) {
884  errno = EINVAL;
885  return -1;
886  }
887  memcpy(&opt->geneve.data, data, data_len);
888  opt->geneve.data_len = data_len;
889  break;
890  default:
891  errno = EOPNOTSUPP;
892  return -1;
893  }
894 
895  opt->flags |= (1 << type);
896 
897  return 0;
898 }
899 
900 EXPORT_SYMBOL(nftnl_tunnel_opt_set);
901 int nftnl_tunnel_opt_set(struct nftnl_tunnel_opt *opt, uint16_t type,
902  const void *data, uint32_t data_len)
903 {
904  switch (opt->type) {
905  case NFTNL_TUNNEL_TYPE_VXLAN:
906  return nftnl_tunnel_opt_vxlan_set(opt, type, data, data_len);
907  case NFTNL_TUNNEL_TYPE_ERSPAN:
908  return nftnl_tunnel_opt_erspan_set(opt, type, data, data_len);
909  case NFTNL_TUNNEL_TYPE_GENEVE:
910  return nftnl_tunnel_opt_geneve_set(opt, type, data, data_len);
911  default:
912  errno = EOPNOTSUPP;
913  return -1;
914  }
915 
916  return 0;
917 }
918 
919 static void nftnl_tunnel_opt_build_vxlan(struct nlmsghdr *nlh,
920  const struct nftnl_tunnel_opt *opt)
921 {
922  struct nlattr *nest_inner;
923 
924  if (opt->flags & (1 << NFTNL_TUNNEL_VXLAN_GBP)) {
925  nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_VXLAN);
926  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_VXLAN_GBP,
927  htonl(opt->vxlan.gbp));
928  mnl_attr_nest_end(nlh, nest_inner);
929  }
930 }
931 
932 static void nftnl_tunnel_opt_build_erspan(struct nlmsghdr *nlh,
933  const struct nftnl_tunnel_opt *opt)
934 {
935  struct nlattr *nest_inner;
936 
937  if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_VERSION) &&
938  (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX) ||
939  (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID) &&
940  opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR)))) {
941  nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_ERSPAN);
942  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_VERSION,
943  htonl(opt->erspan.version));
944  if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX))
945  mnl_attr_put_u32(nlh, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
946  htonl(opt->erspan.v1.index));
947  if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID))
948  mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
949  opt->erspan.v2.hwid);
950  if (opt->flags & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR))
951  mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
952  opt->erspan.v2.dir);
953  mnl_attr_nest_end(nlh, nest_inner);
954  }
955 }
956 
957 static void nftnl_tunnel_opt_build_geneve(struct nlmsghdr *nlh,
958  const struct nftnl_tunnel_opt *opt)
959 {
960  struct nlattr *nest_inner;
961 
962  if (opt->flags & (1 << NFTNL_TUNNEL_GENEVE_CLASS) &&
963  opt->flags & (1 << NFTNL_TUNNEL_GENEVE_TYPE) &&
964  opt->flags & (1 << NFTNL_TUNNEL_GENEVE_DATA)) {
965  nest_inner = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS_GENEVE);
966  mnl_attr_put_u16(nlh, NFTA_TUNNEL_KEY_GENEVE_CLASS,
967  htons(opt->geneve.geneve_class));
968  mnl_attr_put_u8(nlh, NFTA_TUNNEL_KEY_GENEVE_TYPE,
969  opt->geneve.type);
970  mnl_attr_put(nlh, NFTA_TUNNEL_KEY_GENEVE_DATA,
971  opt->geneve.data_len,
972  opt->geneve.data);
973  mnl_attr_nest_end(nlh, nest_inner);
974  }
975 }
976 
977 void nftnl_tunnel_opts_build(struct nlmsghdr *nlh,
978  struct nftnl_tunnel_opts *opts)
979 {
980  const struct nftnl_tunnel_opt *opt;
981  struct nlattr *nest;
982 
983  nest = mnl_attr_nest_start(nlh, NFTA_TUNNEL_KEY_OPTS);
984 
985  list_for_each_entry(opt, &opts->opts_list, list) {
986  switch (opts->type) {
987  case NFTNL_TUNNEL_TYPE_VXLAN:
988  nftnl_tunnel_opt_build_vxlan(nlh, opt);
989  break;
990  case NFTNL_TUNNEL_TYPE_ERSPAN:
991  nftnl_tunnel_opt_build_erspan(nlh, opt);
992  break;
993  case NFTNL_TUNNEL_TYPE_GENEVE:
994  nftnl_tunnel_opt_build_geneve(nlh, opt);
995  break;
996  }
997  }
998  mnl_attr_nest_end(nlh, nest);
999 }
1000 
1001 static struct attr_policy obj_tunnel_attr_policy[__NFTNL_OBJ_TUNNEL_MAX] = {
1002  [NFTNL_OBJ_TUNNEL_ID] = { .maxlen = sizeof(uint32_t) },
1003  [NFTNL_OBJ_TUNNEL_IPV4_SRC] = { .maxlen = sizeof(uint32_t) },
1004  [NFTNL_OBJ_TUNNEL_IPV4_DST] = { .maxlen = sizeof(uint32_t) },
1005  [NFTNL_OBJ_TUNNEL_IPV6_SRC] = { .maxlen = sizeof(struct in6_addr) },
1006  [NFTNL_OBJ_TUNNEL_IPV6_DST] = { .maxlen = sizeof(struct in6_addr) },
1007  [NFTNL_OBJ_TUNNEL_IPV6_FLOWLABEL] = { .maxlen = sizeof(uint32_t) },
1008  [NFTNL_OBJ_TUNNEL_SPORT] = { .maxlen = sizeof(uint16_t) },
1009  [NFTNL_OBJ_TUNNEL_DPORT] = { .maxlen = sizeof(uint16_t) },
1010  [NFTNL_OBJ_TUNNEL_FLAGS] = { .maxlen = sizeof(uint32_t) },
1011  [NFTNL_OBJ_TUNNEL_TOS] = { .maxlen = sizeof(uint8_t) },
1012  [NFTNL_OBJ_TUNNEL_TTL] = { .maxlen = sizeof(uint8_t) },
1013  [NFTNL_OBJ_TUNNEL_OPTS] = { .maxlen = sizeof(struct nftnl_tunnel_opts *) },
1014 };
1015 
1016 struct obj_ops obj_ops_tunnel = {
1017  .name = "tunnel",
1018  .type = NFT_OBJECT_TUNNEL,
1019  .alloc_len = sizeof(struct nftnl_obj_tunnel),
1020  .nftnl_max_attr = __NFTNL_OBJ_TUNNEL_MAX - 1,
1021  .attr_policy = obj_tunnel_attr_policy,
1022  .set = nftnl_obj_tunnel_set,
1023  .get = nftnl_obj_tunnel_get,
1024  .parse = nftnl_obj_tunnel_parse,
1025  .build = nftnl_obj_tunnel_build,
1026  .output = nftnl_obj_tunnel_snprintf,
1027 };