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
vxlan_alloc(struct rtnl_link * link)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
vxlan_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)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
vxlan_free(struct rtnl_link * link)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
vxlan_dump_line(struct rtnl_link * link,struct nl_dump_params * p)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
vxlan_dump_details(struct rtnl_link * link,struct nl_dump_params * p)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
vxlan_clone(struct rtnl_link * dst,struct rtnl_link * src)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
vxlan_put_attrs(struct nl_msg * msg,struct rtnl_link * link)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 */
rtnl_link_vxlan_alloc(void)430 struct rtnl_link *rtnl_link_vxlan_alloc(void)
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 */
rtnl_link_is_vxlan(struct rtnl_link * link)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 */
rtnl_link_vxlan_set_id(struct rtnl_link * link,uint32_t id)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 */
rtnl_link_vxlan_get_id(struct rtnl_link * link,uint32_t * id)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 */
rtnl_link_vxlan_set_group(struct rtnl_link * link,struct nl_addr * addr)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 */
rtnl_link_vxlan_get_group(struct rtnl_link * link,struct nl_addr ** addr)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 */
rtnl_link_vxlan_set_link(struct rtnl_link * link,uint32_t index)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 */
rtnl_link_vxlan_get_link(struct rtnl_link * link,uint32_t * index)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 */
rtnl_link_vxlan_set_local(struct rtnl_link * link,struct nl_addr * addr)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 */
rtnl_link_vxlan_get_local(struct rtnl_link * link,struct nl_addr ** addr)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 */
rtnl_link_vxlan_set_ttl(struct rtnl_link * link,uint8_t ttl)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 */
rtnl_link_vxlan_get_ttl(struct rtnl_link * link)667 int rtnl_link_vxlan_get_ttl(struct rtnl_link *link)
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 */
rtnl_link_vxlan_set_tos(struct rtnl_link * link,uint8_t tos)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 */
rtnl_link_vxlan_get_tos(struct rtnl_link * link)704 int rtnl_link_vxlan_get_tos(struct rtnl_link *link)
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 */
rtnl_link_vxlan_set_learning(struct rtnl_link * link,uint8_t learning)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 */
rtnl_link_vxlan_get_learning(struct rtnl_link * link)741 int rtnl_link_vxlan_get_learning(struct rtnl_link *link)
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 */
rtnl_link_vxlan_enable_learning(struct rtnl_link * link)759 int rtnl_link_vxlan_enable_learning(struct rtnl_link *link)
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 */
rtnl_link_vxlan_disable_learning(struct rtnl_link * link)770 int rtnl_link_vxlan_disable_learning(struct rtnl_link *link)
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 */
rtnl_link_vxlan_set_ageing(struct rtnl_link * link,uint32_t expiry)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 */
rtnl_link_vxlan_get_ageing(struct rtnl_link * link,uint32_t * expiry)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 */
rtnl_link_vxlan_set_limit(struct rtnl_link * link,uint32_t limit)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 */
rtnl_link_vxlan_get_limit(struct rtnl_link * link,uint32_t * limit)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 */
rtnl_link_vxlan_set_port_range(struct rtnl_link * link,struct ifla_vxlan_port_range * range)868 int rtnl_link_vxlan_set_port_range(struct rtnl_link *link,
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 */
rtnl_link_vxlan_get_port_range(struct rtnl_link * link,struct ifla_vxlan_port_range * range)891 int rtnl_link_vxlan_get_port_range(struct rtnl_link *link,
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 */
rtnl_link_vxlan_set_proxy(struct rtnl_link * link,uint8_t proxy)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 */
rtnl_link_vxlan_get_proxy(struct rtnl_link * link)934 int rtnl_link_vxlan_get_proxy(struct rtnl_link *link)
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 */
rtnl_link_vxlan_enable_proxy(struct rtnl_link * link)952 int rtnl_link_vxlan_enable_proxy(struct rtnl_link *link)
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 */
rtnl_link_vxlan_disable_proxy(struct rtnl_link * link)963 int rtnl_link_vxlan_disable_proxy(struct rtnl_link *link)
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 */
rtnl_link_vxlan_set_rsc(struct rtnl_link * link,uint8_t rsc)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 */
rtnl_link_vxlan_get_rsc(struct rtnl_link * link)993 int rtnl_link_vxlan_get_rsc(struct rtnl_link *link)
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 */
rtnl_link_vxlan_enable_rsc(struct rtnl_link * link)1011 int rtnl_link_vxlan_enable_rsc(struct rtnl_link *link)
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 */
rtnl_link_vxlan_disable_rsc(struct rtnl_link * link)1022 int rtnl_link_vxlan_disable_rsc(struct rtnl_link *link)
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 */
rtnl_link_vxlan_set_l2miss(struct rtnl_link * link,uint8_t miss)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 */
rtnl_link_vxlan_get_l2miss(struct rtnl_link * link)1052 int rtnl_link_vxlan_get_l2miss(struct rtnl_link *link)
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 */
rtnl_link_vxlan_enable_l2miss(struct rtnl_link * link)1070 int rtnl_link_vxlan_enable_l2miss(struct rtnl_link *link)
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 */
rtnl_link_vxlan_disable_l2miss(struct rtnl_link * link)1081 int rtnl_link_vxlan_disable_l2miss(struct rtnl_link *link)
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 */
rtnl_link_vxlan_set_l3miss(struct rtnl_link * link,uint8_t miss)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 */
rtnl_link_vxlan_get_l3miss(struct rtnl_link * link)1111 int rtnl_link_vxlan_get_l3miss(struct rtnl_link *link)
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 */
rtnl_link_vxlan_enable_l3miss(struct rtnl_link * link)1129 int rtnl_link_vxlan_enable_l3miss(struct rtnl_link *link)
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 */
rtnl_link_vxlan_disable_l3miss(struct rtnl_link * link)1140 int rtnl_link_vxlan_disable_l3miss(struct rtnl_link *link)
1141 {
1142 return rtnl_link_vxlan_set_l3miss(link, 0);
1143 }
1144
1145 /** @} */
1146
vxlan_init(void)1147 static void __init vxlan_init(void)
1148 {
1149 rtnl_link_register_info(&vxlan_info_ops);
1150 }
1151
vxlan_exit(void)1152 static void __exit vxlan_exit(void)
1153 {
1154 rtnl_link_unregister_info(&vxlan_info_ops);
1155 }
1156
1157 /** @} */
1158