libnl  3.2.24-rc1
vxlan.c
1 /*
2  * lib/route/link/vxlan.c VXLAN Link Info
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2013 Yasunobu Chiba <yasu@dsl.gr.jp>
10  */
11 
12 /**
13  * @ingroup link
14  * @defgroup vxlan VXLAN
15  * Virtual eXtensible Local Area Network link module
16  *
17  * @details
18  * \b Link Type Name: "vxlan"
19  *
20  * @route_doc{link_vxlan, VXLAN Documentation}
21  *
22  * @{
23  */
24 
25 #include <netlink-private/netlink.h>
26 #include <netlink/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/utils.h>
29 #include <netlink/object.h>
30 #include <netlink/route/rtnl.h>
31 #include <netlink-private/route/link/api.h>
32 #include <netlink/route/link/vxlan.h>
33 
34 #include <linux/if_link.h>
35 
36 /** @cond SKIP */
37 #define VXLAN_HAS_ID (1<<0)
38 #define VXLAN_HAS_GROUP (1<<1)
39 #define VXLAN_HAS_LINK (1<<2)
40 #define VXLAN_HAS_LOCAL (1<<3)
41 #define VXLAN_HAS_TTL (1<<4)
42 #define VXLAN_HAS_TOS (1<<5)
43 #define VXLAN_HAS_LEARNING (1<<6)
44 #define VXLAN_HAS_AGEING (1<<7)
45 #define VXLAN_HAS_LIMIT (1<<8)
46 #define VXLAN_HAS_PORT_RANGE (1<<9)
47 #define VXLAN_HAS_PROXY (1<<10)
48 #define VXLAN_HAS_RSC (1<<11)
49 #define VXLAN_HAS_L2MISS (1<<12)
50 #define VXLAN_HAS_L3MISS (1<<13)
51 
52 struct vxlan_info
53 {
54  uint32_t vxi_id;
55  uint32_t vxi_group;
56  uint32_t vxi_link;
57  uint32_t vxi_local;
58  uint8_t vxi_ttl;
59  uint8_t vxi_tos;
60  uint8_t vxi_learning;
61  uint32_t vxi_ageing;
62  uint32_t vxi_limit;
63  struct ifla_vxlan_port_range vxi_port_range;
64  uint8_t vxi_proxy;
65  uint8_t vxi_rsc;
66  uint8_t vxi_l2miss;
67  uint8_t vxi_l3miss;
68  uint32_t vxi_mask;
69 };
70 
71 /** @endcond */
72 
73 static struct nla_policy vxlan_policy[IFLA_VXLAN_MAX+1] = {
74  [IFLA_VXLAN_ID] = { .type = NLA_U32 },
75  [IFLA_VXLAN_GROUP] = { .minlen = sizeof(uint32_t) },
76  [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
77  [IFLA_VXLAN_LOCAL] = { .minlen = sizeof(uint32_t) },
78  [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
79  [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
80  [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
81  [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
82  [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
83  [IFLA_VXLAN_PORT_RANGE] = { .minlen = sizeof(struct ifla_vxlan_port_range) },
84  [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
85  [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
86  [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
87  [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
88 };
89 
90 static int vxlan_alloc(struct rtnl_link *link)
91 {
92  struct vxlan_info *vxi;
93 
94  if ((vxi = calloc(1, sizeof(*vxi))) == NULL)
95  return -NLE_NOMEM;
96 
97  link->l_info = vxi;
98 
99  return 0;
100 }
101 
102 static int vxlan_parse(struct rtnl_link *link, struct nlattr *data,
103  struct nlattr *xstats)
104 {
105  struct nlattr *tb[IFLA_VXLAN_MAX+1];
106  struct vxlan_info *vxi;
107  int err;
108 
109  NL_DBG(3, "Parsing VXLAN link info");
110 
111  if ((err = nla_parse_nested(tb, IFLA_VXLAN_MAX, data, vxlan_policy)) < 0)
112  goto errout;
113 
114  if ((err = vxlan_alloc(link)) < 0)
115  goto errout;
116 
117  vxi = link->l_info;
118 
119  if (tb[IFLA_VXLAN_ID]) {
120  vxi->vxi_id = nla_get_u32(tb[IFLA_VXLAN_ID]);
121  vxi->vxi_mask |= VXLAN_HAS_ID;
122  }
123 
124  if (tb[IFLA_VXLAN_GROUP]) {
125  nla_memcpy(&vxi->vxi_group, tb[IFLA_VXLAN_GROUP],
126  sizeof(vxi->vxi_group));
127  vxi->vxi_mask |= VXLAN_HAS_GROUP;
128  }
129 
130  if (tb[IFLA_VXLAN_LINK]) {
131  vxi->vxi_link = nla_get_u32(tb[IFLA_VXLAN_LINK]);
132  vxi->vxi_mask |= VXLAN_HAS_LINK;
133  }
134 
135  if (tb[IFLA_VXLAN_LOCAL]) {
136  nla_memcpy(&vxi->vxi_local, tb[IFLA_VXLAN_LOCAL],
137  sizeof(vxi->vxi_local));
138  vxi->vxi_mask |= VXLAN_HAS_LOCAL;
139  }
140 
141  if (tb[IFLA_VXLAN_TTL]) {
142  vxi->vxi_ttl = nla_get_u8(tb[IFLA_VXLAN_TTL]);
143  vxi->vxi_mask |= VXLAN_HAS_TTL;
144  }
145 
146  if (tb[IFLA_VXLAN_TOS]) {
147  vxi->vxi_tos = nla_get_u8(tb[IFLA_VXLAN_TOS]);
148  vxi->vxi_mask |= VXLAN_HAS_TOS;
149  }
150 
151  if (tb[IFLA_VXLAN_LEARNING]) {
152  vxi->vxi_learning = nla_get_u8(tb[IFLA_VXLAN_LEARNING]);
153  vxi->vxi_mask |= VXLAN_HAS_LEARNING;
154  }
155 
156  if (tb[IFLA_VXLAN_AGEING]) {
157  vxi->vxi_ageing = nla_get_u32(tb[IFLA_VXLAN_AGEING]);
158  vxi->vxi_mask |= VXLAN_HAS_AGEING;
159  }
160 
161  if (tb[IFLA_VXLAN_LIMIT]) {
162  vxi->vxi_limit = nla_get_u32(tb[IFLA_VXLAN_LIMIT]);
163  vxi->vxi_mask |= VXLAN_HAS_LIMIT;
164  }
165 
166  if (tb[IFLA_VXLAN_PORT_RANGE]) {
167  nla_memcpy(&vxi->vxi_port_range, tb[IFLA_VXLAN_PORT_RANGE],
168  sizeof(vxi->vxi_port_range));
169  vxi->vxi_mask |= VXLAN_HAS_PORT_RANGE;
170  }
171 
172  if (tb[IFLA_VXLAN_PROXY]) {
173  vxi->vxi_proxy = nla_get_u8(tb[IFLA_VXLAN_PROXY]);
174  vxi->vxi_mask |= VXLAN_HAS_PROXY;
175  }
176 
177  if (tb[IFLA_VXLAN_RSC]) {
178  vxi->vxi_rsc = nla_get_u8(tb[IFLA_VXLAN_RSC]);
179  vxi->vxi_mask |= VXLAN_HAS_RSC;
180  }
181 
182  if (tb[IFLA_VXLAN_L2MISS]) {
183  vxi->vxi_l2miss = nla_get_u8(tb[IFLA_VXLAN_L2MISS]);
184  vxi->vxi_mask |= VXLAN_HAS_L2MISS;
185  }
186 
187  if (tb[IFLA_VXLAN_L3MISS]) {
188  vxi->vxi_l3miss = nla_get_u8(tb[IFLA_VXLAN_L3MISS]);
189  vxi->vxi_mask |= VXLAN_HAS_L3MISS;
190  }
191 
192  err = 0;
193 
194 errout:
195  return err;
196 }
197 
198 static void vxlan_free(struct rtnl_link *link)
199 {
200  struct vxlan_info *vxi = link->l_info;
201 
202  free(vxi);
203  link->l_info = NULL;
204 }
205 
206 static void vxlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
207 {
208  struct vxlan_info *vxi = link->l_info;
209 
210  nl_dump(p, "vxlan-id %u", vxi->vxi_id);
211 }
212 
213 static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
214 {
215  struct vxlan_info *vxi = link->l_info;
216  char *name, addr[INET_ADDRSTRLEN];
217 
218  nl_dump_line(p, " vxlan-id %u\n", vxi->vxi_id);
219 
220  if (vxi->vxi_mask & VXLAN_HAS_GROUP) {
221  nl_dump(p, " group ");
222  if(inet_ntop(AF_INET, &vxi->vxi_group, addr, sizeof(addr)))
223  nl_dump_line(p, "%s\n", addr);
224  else
225  nl_dump_line(p, "%#x\n", ntohs(vxi->vxi_group));
226  }
227 
228  if (vxi->vxi_mask & VXLAN_HAS_LINK) {
229  nl_dump(p, " link ");
230  name = rtnl_link_get_name(link);
231  if (name)
232  nl_dump_line(p, "%s\n", name);
233  else
234  nl_dump_line(p, "%u\n", vxi->vxi_link);
235  }
236 
237  if (vxi->vxi_mask & VXLAN_HAS_LOCAL) {
238  nl_dump(p, " local ");
239  if(inet_ntop(AF_INET, &vxi->vxi_local, addr, sizeof(addr)))
240  nl_dump_line(p, "%s\n", addr);
241  else
242  nl_dump_line(p, "%#x\n", ntohs(vxi->vxi_local));
243  }
244 
245  if (vxi->vxi_mask & VXLAN_HAS_TTL) {
246  nl_dump(p, " ttl ");
247  if(vxi->vxi_ttl)
248  nl_dump_line(p, "%u\n", vxi->vxi_ttl);
249  else
250  nl_dump_line(p, "inherit\n");
251  }
252 
253  if (vxi->vxi_mask & VXLAN_HAS_TOS) {
254  nl_dump(p, " tos ");
255  if (vxi->vxi_tos == 1)
256  nl_dump_line(p, "inherit\n", vxi->vxi_tos);
257  else
258  nl_dump_line(p, "%#x\n", vxi->vxi_tos);
259  }
260 
261  if (vxi->vxi_mask & VXLAN_HAS_LEARNING) {
262  nl_dump(p, " learning ");
263  if (vxi->vxi_learning)
264  nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_learning);
265  else
266  nl_dump_line(p, "disabled\n");
267  }
268 
269  if (vxi->vxi_mask & VXLAN_HAS_AGEING) {
270  nl_dump(p, " ageing ");
271  if (vxi->vxi_ageing)
272  nl_dump_line(p, "%u seconds\n", vxi->vxi_ageing);
273  else
274  nl_dump_line(p, "disabled\n");
275  }
276 
277  if (vxi->vxi_mask & VXLAN_HAS_LIMIT) {
278  nl_dump(p, " limit ");
279  if (vxi->vxi_limit)
280  nl_dump_line(p, "%u\n", vxi->vxi_limit);
281  else
282  nl_dump_line(p, "unlimited\n");
283  }
284 
285  if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
286  nl_dump_line(p, " port range %u - %u\n",
287  ntohs(vxi->vxi_port_range.low),
288  ntohs(vxi->vxi_port_range.high));
289 
290  if (vxi->vxi_mask & VXLAN_HAS_PROXY) {
291  nl_dump(p, " proxy ");
292  if (vxi->vxi_proxy)
293  nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_proxy);
294  else
295  nl_dump_line(p, "disabled\n");
296  }
297 
298  if (vxi->vxi_mask & VXLAN_HAS_RSC) {
299  nl_dump(p, " rsc ");
300  if (vxi->vxi_rsc)
301  nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_rsc);
302  else
303  nl_dump_line(p, "disabled\n");
304  }
305 
306  if (vxi->vxi_mask & VXLAN_HAS_L2MISS) {
307  nl_dump(p, " l2miss ");
308  if (vxi->vxi_l2miss)
309  nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_l2miss);
310  else
311  nl_dump_line(p, "disabled\n");
312  }
313 
314  if (vxi->vxi_mask & VXLAN_HAS_L3MISS) {
315  nl_dump(p, " l3miss ");
316  if (vxi->vxi_l3miss)
317  nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_l3miss);
318  else
319  nl_dump_line(p, "disabled\n");
320  }
321 }
322 
323 static int vxlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
324 {
325  struct vxlan_info *vdst, *vsrc = src->l_info;
326  int err;
327 
328  dst->l_info = NULL;
329  if ((err = rtnl_link_set_type(dst, "vxlan")) < 0)
330  return err;
331  vdst = dst->l_info;
332 
333  if (!vdst || !vsrc)
334  return -NLE_NOMEM;
335 
336  memcpy(vdst, vsrc, sizeof(struct vxlan_info));
337 
338  return 0;
339 }
340 
341 static int vxlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
342 {
343  struct vxlan_info *vxi = link->l_info;
344  struct nlattr *data;
345 
346  if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
347  return -NLE_MSGSIZE;
348 
349  if (vxi->vxi_mask & VXLAN_HAS_ID)
350  NLA_PUT_U32(msg, IFLA_VXLAN_ID, vxi->vxi_id);
351 
352  if (vxi->vxi_mask & VXLAN_HAS_GROUP)
353  NLA_PUT(msg, IFLA_VXLAN_GROUP, sizeof(vxi->vxi_group), &vxi->vxi_group);
354 
355  if (vxi->vxi_mask & VXLAN_HAS_LINK)
356  NLA_PUT_U32(msg, IFLA_VXLAN_LINK, vxi->vxi_link);
357 
358  if (vxi->vxi_mask & VXLAN_HAS_LOCAL)
359  NLA_PUT(msg, IFLA_VXLAN_LOCAL, sizeof(vxi->vxi_local), &vxi->vxi_local);
360 
361  if (vxi->vxi_mask & VXLAN_HAS_TTL)
362  NLA_PUT_U8(msg, IFLA_VXLAN_TTL, vxi->vxi_ttl);
363 
364  if (vxi->vxi_mask & VXLAN_HAS_TOS)
365  NLA_PUT_U8(msg, IFLA_VXLAN_TOS, vxi->vxi_tos);
366 
367  if (vxi->vxi_mask & VXLAN_HAS_LEARNING)
368  NLA_PUT_U8(msg, IFLA_VXLAN_LEARNING, vxi->vxi_learning);
369 
370  if (vxi->vxi_mask & VXLAN_HAS_AGEING)
371  NLA_PUT_U32(msg, IFLA_VXLAN_AGEING, vxi->vxi_ageing);
372 
373  if (vxi->vxi_mask & VXLAN_HAS_LIMIT)
374  NLA_PUT_U32(msg, IFLA_VXLAN_LIMIT, vxi->vxi_limit);
375 
376  if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
377  NLA_PUT(msg, IFLA_VXLAN_PORT_RANGE, sizeof(vxi->vxi_port_range),
378  &vxi->vxi_port_range);
379 
380  if (vxi->vxi_mask & VXLAN_HAS_PROXY)
381  NLA_PUT_U8(msg, IFLA_VXLAN_PROXY, vxi->vxi_proxy);
382 
383  if (vxi->vxi_mask & VXLAN_HAS_RSC)
384  NLA_PUT_U8(msg, IFLA_VXLAN_RSC, vxi->vxi_rsc);
385 
386  if (vxi->vxi_mask & VXLAN_HAS_L2MISS)
387  NLA_PUT_U8(msg, IFLA_VXLAN_L2MISS, vxi->vxi_l2miss);
388 
389  if (vxi->vxi_mask & VXLAN_HAS_L3MISS)
390  NLA_PUT_U8(msg, IFLA_VXLAN_L3MISS, vxi->vxi_l3miss);
391 
392  nla_nest_end(msg, data);
393 
394 nla_put_failure:
395 
396  return 0;
397 }
398 
399 static struct rtnl_link_info_ops vxlan_info_ops = {
400  .io_name = "vxlan",
401  .io_alloc = vxlan_alloc,
402  .io_parse = vxlan_parse,
403  .io_dump = {
404  [NL_DUMP_LINE] = vxlan_dump_line,
405  [NL_DUMP_DETAILS] = vxlan_dump_details,
406  },
407  .io_clone = vxlan_clone,
408  .io_put_attrs = vxlan_put_attrs,
409  .io_free = vxlan_free,
410 };
411 
412 /** @cond SKIP */
413 #define IS_VXLAN_LINK_ASSERT(link) \
414  if ((link)->l_info_ops != &vxlan_info_ops) { \
415  APPBUG("Link is not a vxlan link. set type \"vxlan\" first."); \
416  return -NLE_OPNOTSUPP; \
417  }
418 /** @endcond */
419 
420 /**
421  * @name VXLAN Object
422  * @{
423  */
424 
425 /**
426  * Allocate link object of type VXLAN
427  *
428  * @return Allocated link object or NULL.
429  */
431 {
432  struct rtnl_link *link;
433  int err;
434 
435  if (!(link = rtnl_link_alloc()))
436  return NULL;
437 
438  if ((err = rtnl_link_set_type(link, "vxlan")) < 0) {
439  rtnl_link_put(link);
440  return NULL;
441  }
442 
443  return link;
444 }
445 
446 /**
447  * Check if link is a VXLAN link
448  * @arg link Link object
449  *
450  * @return True if link is a VXLAN link, otherwise false is returned.
451  */
452 int rtnl_link_is_vxlan(struct rtnl_link *link)
453 {
454  return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vxlan");
455 }
456 
457 /**
458  * Set VXLAN Network Identifier
459  * @arg link Link object
460  * @arg id VXLAN network identifier (or VXLAN segment identifier)
461  *
462  * @return 0 on success or a negative error code
463  */
464 int rtnl_link_vxlan_set_id(struct rtnl_link *link, uint32_t id)
465 {
466  struct vxlan_info *vxi = link->l_info;
467 
468  IS_VXLAN_LINK_ASSERT(link);
469 
470  if (id > VXLAN_ID_MAX)
471  return -NLE_INVAL;
472 
473  vxi->vxi_id = id;
474  vxi->vxi_mask |= VXLAN_HAS_ID;
475 
476  return 0;
477 }
478 
479 /**
480  * Get VXLAN Network Identifier
481  * @arg link Link object
482  * @arg id Pointer to store network identifier
483  *
484  * @return 0 on success or a negative error code
485  */
486 int rtnl_link_vxlan_get_id(struct rtnl_link *link, uint32_t *id)
487 {
488  struct vxlan_info *vxi = link->l_info;
489 
490  IS_VXLAN_LINK_ASSERT(link);
491 
492  if(!id)
493  return -NLE_INVAL;
494 
495  if (vxi->vxi_mask & VXLAN_HAS_ID)
496  *id = vxi->vxi_id;
497  else
498  return -NLE_AGAIN;
499 
500  return 0;
501 }
502 
503 /**
504  * Set VXLAN multicast IP address
505  * @arg link Link object
506  * @arg addr Multicast IP address to join
507  *
508  * @return 0 on success or a negative error code
509  */
510 int rtnl_link_vxlan_set_group(struct rtnl_link *link, struct nl_addr *addr)
511 {
512  struct vxlan_info *vxi = link->l_info;
513 
514  IS_VXLAN_LINK_ASSERT(link);
515 
516  if ((nl_addr_get_family(addr) != AF_INET) ||
517  (nl_addr_get_len(addr) != sizeof(vxi->vxi_group)))
518  return -NLE_INVAL;
519 
520  memcpy(&vxi->vxi_group, nl_addr_get_binary_addr(addr),
521  sizeof(vxi->vxi_group));
522  vxi->vxi_mask |= VXLAN_HAS_GROUP;
523 
524  return 0;
525 }
526 
527 /**
528  * Get VXLAN multicast IP address
529  * @arg link Link object
530  * @arg addr Pointer to store multicast IP address
531  *
532  * @return 0 on success or a negative error code
533  */
534 int rtnl_link_vxlan_get_group(struct rtnl_link *link, struct nl_addr **addr)
535 {
536  struct vxlan_info *vxi = link->l_info;
537 
538  IS_VXLAN_LINK_ASSERT(link);
539 
540  if (!addr)
541  return -NLE_INVAL;
542 
543  if (!(vxi->vxi_mask & VXLAN_HAS_GROUP))
544  return -NLE_AGAIN;
545 
546  *addr = nl_addr_build(AF_INET, &vxi->vxi_group, sizeof(vxi->vxi_group));
547 
548  return 0;
549 }
550 
551 /**
552  * Set physical device to use for VXLAN
553  * @arg link Link object
554  * @arg index Interface index
555  *
556  * @return 0 on success or a negative error code
557  */
558 int rtnl_link_vxlan_set_link(struct rtnl_link *link, uint32_t index)
559 {
560  struct vxlan_info *vxi = link->l_info;
561 
562  IS_VXLAN_LINK_ASSERT(link);
563 
564  vxi->vxi_link = index;
565  vxi->vxi_mask |= VXLAN_HAS_LINK;
566 
567  return 0;
568 }
569 
570 /**
571  * Get physical device to use for VXLAN
572  * @arg link Link object
573  * @arg index Pointer to store interface index
574  *
575  * @return 0 on success or a negative error code
576  */
577 int rtnl_link_vxlan_get_link(struct rtnl_link *link, uint32_t *index)
578 {
579  struct vxlan_info *vxi = link->l_info;
580 
581  IS_VXLAN_LINK_ASSERT(link);
582 
583  if (!index)
584  return -NLE_INVAL;
585 
586  if (!(vxi->vxi_mask & VXLAN_HAS_LINK))
587  return -NLE_AGAIN;
588 
589  *index = vxi->vxi_link;
590 
591  return 0;
592 }
593 
594 /**
595  * Set source address to use for VXLAN
596  * @arg link Link object
597  * @arg addr Local address
598  *
599  * @return 0 on success or a negative error code
600  */
601 int rtnl_link_vxlan_set_local(struct rtnl_link *link, struct nl_addr *addr)
602 {
603  struct vxlan_info *vxi = link->l_info;
604 
605  IS_VXLAN_LINK_ASSERT(link);
606 
607  if ((nl_addr_get_family(addr) != AF_INET) ||
608  (nl_addr_get_len(addr) != sizeof(vxi->vxi_local)))
609  return -NLE_INVAL;
610 
611  memcpy(&vxi->vxi_local, nl_addr_get_binary_addr(addr),
612  sizeof(vxi->vxi_local));
613  vxi->vxi_mask |= VXLAN_HAS_LOCAL;
614 
615  return 0;
616 }
617 
618 /**
619  * Get source address to use for VXLAN
620  * @arg link Link object
621  * @arg addr Pointer to store local address
622  *
623  * @return 0 on success or a negative error code
624  */
625 int rtnl_link_vxlan_get_local(struct rtnl_link *link, struct nl_addr **addr)
626 {
627  struct vxlan_info *vxi = link->l_info;
628 
629  IS_VXLAN_LINK_ASSERT(link);
630 
631  if (!addr)
632  return -NLE_INVAL;
633 
634  if (!(vxi->vxi_mask & VXLAN_HAS_LOCAL))
635  return -NLE_AGAIN;
636 
637  *addr = nl_addr_build(AF_INET, &vxi->vxi_local, sizeof(vxi->vxi_local));
638 
639  return 0;
640 }
641 
642 /**
643  * Set IP TTL value to use for VXLAN
644  * @arg link Link object
645  * @arg ttl TTL value
646  *
647  * @return 0 on success or a negative error code
648  */
649 int rtnl_link_vxlan_set_ttl(struct rtnl_link *link, uint8_t ttl)
650 {
651  struct vxlan_info *vxi = link->l_info;
652 
653  IS_VXLAN_LINK_ASSERT(link);
654 
655  vxi->vxi_ttl = ttl;
656  vxi->vxi_mask |= VXLAN_HAS_TTL;
657 
658  return 0;
659 }
660 
661 /**
662  * Get IP TTL value to use for VXLAN
663  * @arg link Link object
664  *
665  * @return TTL value on success or a negative error code
666  */
668 {
669  struct vxlan_info *vxi = link->l_info;
670 
671  IS_VXLAN_LINK_ASSERT(link);
672 
673  if (!(vxi->vxi_mask & VXLAN_HAS_TTL))
674  return -NLE_AGAIN;
675 
676  return vxi->vxi_ttl;
677 }
678 
679 /**
680  * Set IP ToS value to use for VXLAN
681  * @arg link Link object
682  * @arg tos ToS value
683  *
684  * @return 0 on success or a negative error code
685  */
686 int rtnl_link_vxlan_set_tos(struct rtnl_link *link, uint8_t tos)
687 {
688  struct vxlan_info *vxi = link->l_info;
689 
690  IS_VXLAN_LINK_ASSERT(link);
691 
692  vxi->vxi_tos = tos;
693  vxi->vxi_mask |= VXLAN_HAS_TOS;
694 
695  return 0;
696 }
697 
698 /**
699  * Get IP ToS value to use for VXLAN
700  * @arg link Link object
701  *
702  * @return ToS value on success or a negative error code
703  */
705 {
706  struct vxlan_info *vxi = link->l_info;
707 
708  IS_VXLAN_LINK_ASSERT(link);
709 
710  if (!(vxi->vxi_mask & VXLAN_HAS_TOS))
711  return -NLE_AGAIN;
712 
713  return vxi->vxi_tos;
714 }
715 
716 /**
717  * Set VXLAN learning status
718  * @arg link Link object
719  * @arg learning Learning status value
720  *
721  * @return 0 on success or a negative error code
722  */
723 int rtnl_link_vxlan_set_learning(struct rtnl_link *link, uint8_t learning)
724 {
725  struct vxlan_info *vxi = link->l_info;
726 
727  IS_VXLAN_LINK_ASSERT(link);
728 
729  vxi->vxi_learning = learning;
730  vxi->vxi_mask |= VXLAN_HAS_LEARNING;
731 
732  return 0;
733 }
734 
735 /**
736  * Get VXLAN learning status
737  * @arg link Link object
738  *
739  * @return Learning status value on success or a negative error code
740  */
742 {
743  struct vxlan_info *vxi = link->l_info;
744 
745  IS_VXLAN_LINK_ASSERT(link);
746 
747  if (!(vxi->vxi_mask & VXLAN_HAS_LEARNING))
748  return -NLE_AGAIN;
749 
750  return vxi->vxi_learning;
751 }
752 
753 /**
754  * Enable VXLAN address learning
755  * @arg link Link object
756  *
757  * @return 0 on success or a negative error code
758  */
760 {
761  return rtnl_link_vxlan_set_learning(link, 1);
762 }
763 
764 /**
765  * Disable VXLAN address learning
766  * @arg link Link object
767  *
768  * @return 0 on success or a negative error code
769  */
771 {
772  return rtnl_link_vxlan_set_learning(link, 0);
773 }
774 
775 /**
776  * Set expiration timer value to use for VXLAN
777  * @arg link Link object
778  * @arg expiry Expiration timer value
779  *
780  * @return 0 on success or a negative error code
781  */
782 int rtnl_link_vxlan_set_ageing(struct rtnl_link *link, uint32_t expiry)
783 {
784  struct vxlan_info *vxi = link->l_info;
785 
786  IS_VXLAN_LINK_ASSERT(link);
787 
788  vxi->vxi_ageing = expiry;
789  vxi->vxi_mask |= VXLAN_HAS_AGEING;
790 
791  return 0;
792 }
793 
794 /**
795  * Get expiration timer value to use for VXLAN
796  * @arg link Link object
797  * @arg expiry Pointer to store expiration timer value
798  *
799  * @return 0 on success or a negative error code
800  */
801 int rtnl_link_vxlan_get_ageing(struct rtnl_link *link, uint32_t *expiry)
802 {
803  struct vxlan_info *vxi = link->l_info;
804 
805  IS_VXLAN_LINK_ASSERT(link);
806 
807  if (!expiry)
808  return -NLE_INVAL;
809 
810  if (vxi->vxi_mask & VXLAN_HAS_AGEING)
811  *expiry = vxi->vxi_ageing;
812  else
813  return -NLE_AGAIN;
814 
815  return 0;
816 }
817 
818 /**
819  * Set maximum number of forwarding database entries to use for VXLAN
820  * @arg link Link object
821  * @arg limit Maximum number
822  *
823  * @return 0 on success or a negative error code
824  */
825 int rtnl_link_vxlan_set_limit(struct rtnl_link *link, uint32_t limit)
826 {
827  struct vxlan_info *vxi = link->l_info;
828 
829  IS_VXLAN_LINK_ASSERT(link);
830 
831  vxi->vxi_limit = limit;
832  vxi->vxi_mask |= VXLAN_HAS_LIMIT;
833 
834  return 0;
835 }
836 
837 /**
838  * Get maximum number of forwarding database entries to use for VXLAN
839  * @arg link Link object
840  * @arg limit Pointer to store maximum number
841  *
842  * @return 0 on success or a negative error code
843  */
844 int rtnl_link_vxlan_get_limit(struct rtnl_link *link, uint32_t *limit)
845 {
846  struct vxlan_info *vxi = link->l_info;
847 
848  IS_VXLAN_LINK_ASSERT(link);
849 
850  if (!limit)
851  return -NLE_INVAL;
852 
853  if (vxi->vxi_mask & VXLAN_HAS_LIMIT)
854  *limit = vxi->vxi_limit;
855  else
856  return -NLE_AGAIN;
857 
858  return 0;
859 }
860 
861 /**
862  * Set range of UDP port numbers to use for VXLAN
863  * @arg link Link object
864  * @arg range Port number range
865  *
866  * @return 0 on success or a negative error code
867  */
869  struct ifla_vxlan_port_range *range)
870 {
871  struct vxlan_info *vxi = link->l_info;
872 
873  IS_VXLAN_LINK_ASSERT(link);
874 
875  if (!range)
876  return -NLE_INVAL;
877 
878  memcpy(&vxi->vxi_port_range, range, sizeof(vxi->vxi_port_range));
879  vxi->vxi_mask |= VXLAN_HAS_PORT_RANGE;
880 
881  return 0;
882 }
883 
884 /**
885  * Get range of UDP port numbers to use for VXLAN
886  * @arg link Link object
887  * @arg range Pointer to store port range
888  *
889  * @return 0 on success or a negative error code
890  */
892  struct ifla_vxlan_port_range *range)
893 {
894  struct vxlan_info *vxi = link->l_info;
895 
896  IS_VXLAN_LINK_ASSERT(link);
897 
898  if (!range)
899  return -NLE_INVAL;
900 
901  if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
902  memcpy(range, &vxi->vxi_port_range, sizeof(*range));
903  else
904  return -NLE_AGAIN;
905 
906  return 0;
907 }
908 
909 /**
910  * Set ARP proxy status to use for VXLAN
911  * @arg link Link object
912  * @arg proxy Status value
913  *
914  * @return 0 on success or a negative error code
915  */
916 int rtnl_link_vxlan_set_proxy(struct rtnl_link *link, uint8_t proxy)
917 {
918  struct vxlan_info *vxi = link->l_info;
919 
920  IS_VXLAN_LINK_ASSERT(link);
921 
922  vxi->vxi_proxy = proxy;
923  vxi->vxi_mask |= VXLAN_HAS_PROXY;
924 
925  return 0;
926 }
927 
928 /**
929  * Get ARP proxy status to use for VXLAN
930  * @arg link Link object
931  *
932  * @return Status value on success or a negative error code
933  */
935 {
936  struct vxlan_info *vxi = link->l_info;
937 
938  IS_VXLAN_LINK_ASSERT(link);
939 
940  if (!(vxi->vxi_mask & VXLAN_HAS_PROXY))
941  return -NLE_AGAIN;
942 
943  return vxi->vxi_proxy;
944 }
945 
946 /**
947  * Enable ARP proxy
948  * @arg link Link object
949  *
950  * @return 0 on success or a negative error code
951  */
953 {
954  return rtnl_link_vxlan_set_proxy(link, 1);
955 }
956 
957 /**
958  * Disable ARP proxy
959  * @arg link Link object
960  *
961  * @return 0 on success or a negative error code
962  */
964 {
965  return rtnl_link_vxlan_set_proxy(link, 0);
966 }
967 
968 /**
969  * Set Route Short Circuit status to use for VXLAN
970  * @arg link Link object
971  * @arg rsc Status value
972  *
973  * @return 0 on success or a negative error code
974  */
975 int rtnl_link_vxlan_set_rsc(struct rtnl_link *link, uint8_t rsc)
976 {
977  struct vxlan_info *vxi = link->l_info;
978 
979  IS_VXLAN_LINK_ASSERT(link);
980 
981  vxi->vxi_rsc = rsc;
982  vxi->vxi_mask |= VXLAN_HAS_RSC;
983 
984  return 0;
985 }
986 
987 /**
988  * Get Route Short Circuit status to use for VXLAN
989  * @arg link Link object
990  *
991  * @return Status value on success or a negative error code
992  */
994 {
995  struct vxlan_info *vxi = link->l_info;
996 
997  IS_VXLAN_LINK_ASSERT(link);
998 
999  if (!(vxi->vxi_mask & VXLAN_HAS_RSC))
1000  return -NLE_AGAIN;
1001 
1002  return vxi->vxi_rsc;
1003 }
1004 
1005 /**
1006  * Enable Route Short Circuit
1007  * @arg link Link object
1008  *
1009  * @return 0 on success or a negative error code
1010  */
1012 {
1013  return rtnl_link_vxlan_set_rsc(link, 1);
1014 }
1015 
1016 /**
1017  * Disable Route Short Circuit
1018  * @arg link Link object
1019  *
1020  * @return 0 on success or a negative error code
1021  */
1023 {
1024  return rtnl_link_vxlan_set_rsc(link, 0);
1025 }
1026 
1027 /**
1028  * Set netlink LLADDR miss notification status to use for VXLAN
1029  * @arg link Link object
1030  * @arg miss Status value
1031  *
1032  * @return 0 on success or a negative error code
1033  */
1034 int rtnl_link_vxlan_set_l2miss(struct rtnl_link *link, uint8_t miss)
1035 {
1036  struct vxlan_info *vxi = link->l_info;
1037 
1038  IS_VXLAN_LINK_ASSERT(link);
1039 
1040  vxi->vxi_l2miss = miss;
1041  vxi->vxi_mask |= VXLAN_HAS_L2MISS;
1042 
1043  return 0;
1044 }
1045 
1046 /**
1047  * Get netlink LLADDR miss notification status to use for VXLAN
1048  * @arg link Link object
1049  *
1050  * @return Status value on success or a negative error code
1051  */
1053 {
1054  struct vxlan_info *vxi = link->l_info;
1055 
1056  IS_VXLAN_LINK_ASSERT(link);
1057 
1058  if (!(vxi->vxi_mask & VXLAN_HAS_L2MISS))
1059  return -NLE_AGAIN;
1060 
1061  return vxi->vxi_l2miss;
1062 }
1063 
1064 /**
1065  * Enable netlink LLADDR miss notifications
1066  * @arg link Link object
1067  *
1068  * @return 0 on success or a negative error code
1069  */
1071 {
1072  return rtnl_link_vxlan_set_l2miss(link, 1);
1073 }
1074 
1075 /**
1076  * Disable netlink LLADDR miss notifications
1077  * @arg link Link object
1078  *
1079  * @return 0 on success or a negative error code
1080  */
1082 {
1083  return rtnl_link_vxlan_set_l2miss(link, 0);
1084 }
1085 
1086 /**
1087  * Set netlink IP ADDR miss notification status to use for VXLAN
1088  * @arg link Link object
1089  * @arg miss Status value
1090  *
1091  * @return 0 on success or a negative error code
1092  */
1093 int rtnl_link_vxlan_set_l3miss(struct rtnl_link *link, uint8_t miss)
1094 {
1095  struct vxlan_info *vxi = link->l_info;
1096 
1097  IS_VXLAN_LINK_ASSERT(link);
1098 
1099  vxi->vxi_l3miss = miss;
1100  vxi->vxi_mask |= VXLAN_HAS_L3MISS;
1101 
1102  return 0;
1103 }
1104 
1105 /**
1106  * Get netlink IP ADDR miss notification status to use for VXLAN
1107  * @arg link Link object
1108  *
1109  * @return Status value on success or a negative error code
1110  */
1112 {
1113  struct vxlan_info *vxi = link->l_info;
1114 
1115  IS_VXLAN_LINK_ASSERT(link);
1116 
1117  if (!(vxi->vxi_mask & VXLAN_HAS_L3MISS))
1118  return -NLE_AGAIN;
1119 
1120  return vxi->vxi_l3miss;
1121 }
1122 
1123 /**
1124  * Enable netlink IP DDR miss notifications
1125  * @arg link Link object
1126  *
1127  * @return 0 on success or a negative error code
1128  */
1130 {
1131  return rtnl_link_vxlan_set_l3miss(link, 1);
1132 }
1133 
1134 /**
1135  * Disable netlink IP ADDR miss notifications
1136  * @arg link Link object
1137  *
1138  * @return 0 on success or a negative error code
1139  */
1141 {
1142  return rtnl_link_vxlan_set_l3miss(link, 0);
1143 }
1144 
1145 /** @} */
1146 
1147 static void __init vxlan_init(void)
1148 {
1149  rtnl_link_register_info(&vxlan_info_ops);
1150 }
1151 
1152 static void __exit vxlan_exit(void)
1153 {
1154  rtnl_link_unregister_info(&vxlan_info_ops);
1155 }
1156 
1157 /** @} */