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