xref: /freebsd-13-stable/sbin/ifconfig/ifvxlan.c (revision 3d497e17ebd33fe0f58d773e35ab994d750258d6)
1 /*-
2  * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 #include <sys/param.h>
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
31 #include <sys/sockio.h>
32 
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <unistd.h>
36 #include <netdb.h>
37 
38 #include <net/ethernet.h>
39 #include <net/if.h>
40 #include <net/if_vxlan.h>
41 #include <net/route.h>
42 #include <netinet/in.h>
43 
44 #include <ctype.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <err.h>
50 #include <errno.h>
51 
52 #include "ifconfig.h"
53 
54 static struct ifvxlanparam params = {
55 	.vxlp_vni	= VXLAN_VNI_MAX,
56 };
57 
58 static int
get_val(const char * cp,u_long * valp)59 get_val(const char *cp, u_long *valp)
60 {
61 	char *endptr;
62 	u_long val;
63 
64 	errno = 0;
65 	val = strtoul(cp, &endptr, 0);
66 	if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
67 		return (-1);
68 
69 	*valp = val;
70 	return (0);
71 }
72 
73 static int
do_cmd(int sock,u_long op,void * arg,size_t argsize,int set)74 do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
75 {
76 	struct ifdrv ifd;
77 
78 	bzero(&ifd, sizeof(ifd));
79 
80 	strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
81 	ifd.ifd_cmd = op;
82 	ifd.ifd_len = argsize;
83 	ifd.ifd_data = arg;
84 
85 	return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
86 }
87 
88 static int
vxlan_exists(int sock)89 vxlan_exists(int sock)
90 {
91 	struct ifvxlancfg cfg;
92 
93 	bzero(&cfg, sizeof(cfg));
94 
95 	return (do_cmd(sock, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1);
96 }
97 
98 static void
vxlan_status(int s)99 vxlan_status(int s)
100 {
101 	struct ifvxlancfg cfg;
102 	char src[NI_MAXHOST], dst[NI_MAXHOST];
103 	char srcport[NI_MAXSERV], dstport[NI_MAXSERV];
104 	struct sockaddr *lsa, *rsa;
105 	int vni, mc, ipv6;
106 
107 	bzero(&cfg, sizeof(cfg));
108 
109 	if (do_cmd(s, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) < 0)
110 		return;
111 
112 	vni = cfg.vxlc_vni;
113 	lsa = &cfg.vxlc_local_sa.sa;
114 	rsa = &cfg.vxlc_remote_sa.sa;
115 	ipv6 = rsa->sa_family == AF_INET6;
116 
117 	/* Just report nothing if the network identity isn't set yet. */
118 	if (vni >= VXLAN_VNI_MAX)
119 		return;
120 
121 	if (getnameinfo(lsa, lsa->sa_len, src, sizeof(src),
122 	    srcport, sizeof(srcport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
123 		src[0] = srcport[0] = '\0';
124 	if (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst),
125 	    dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
126 		dst[0] = dstport[0] = '\0';
127 
128 	if (!ipv6) {
129 		struct sockaddr_in *sin = (struct sockaddr_in *)rsa;
130 		mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr));
131 	} else {
132 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rsa;
133 		mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr);
134 	}
135 
136 	printf("\tvxlan vni %d", vni);
137 	printf(" local %s%s%s:%s", ipv6 ? "[" : "", src, ipv6 ? "]" : "",
138 	    srcport);
139 	printf(" %s %s%s%s:%s", mc ? "group" : "remote", ipv6 ? "[" : "",
140 	    dst, ipv6 ? "]" : "", dstport);
141 
142 	if (verbose) {
143 		printf("\n\t\tconfig: ");
144 		printf("%slearning portrange %d-%d ttl %d",
145 		    cfg.vxlc_learn ? "" : "no", cfg.vxlc_port_min,
146 		    cfg.vxlc_port_max, cfg.vxlc_ttl);
147 		printf("\n\t\tftable: ");
148 		printf("cnt %d max %d timeout %d",
149 		    cfg.vxlc_ftable_cnt, cfg.vxlc_ftable_max,
150 		    cfg.vxlc_ftable_timeout);
151 	}
152 
153 	putchar('\n');
154 }
155 
156 #define _LOCAL_ADDR46 \
157     (VXLAN_PARAM_WITH_LOCAL_ADDR4 | VXLAN_PARAM_WITH_LOCAL_ADDR6)
158 #define _REMOTE_ADDR46 \
159     (VXLAN_PARAM_WITH_REMOTE_ADDR4 | VXLAN_PARAM_WITH_REMOTE_ADDR6)
160 
161 static void
vxlan_check_params(void)162 vxlan_check_params(void)
163 {
164 
165 	if ((params.vxlp_with & _LOCAL_ADDR46) == _LOCAL_ADDR46)
166 		errx(1, "cannot specify both local IPv4 and IPv6 addresses");
167 	if ((params.vxlp_with & _REMOTE_ADDR46) == _REMOTE_ADDR46)
168 		errx(1, "cannot specify both remote IPv4 and IPv6 addresses");
169 	if ((params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR4 &&
170 	     params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) ||
171 	    (params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR6 &&
172 	     params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4))
173 		errx(1, "cannot mix IPv4 and IPv6 addresses");
174 }
175 
176 #undef _LOCAL_ADDR46
177 #undef _REMOTE_ADDR46
178 
179 static void
vxlan_cb(int s,void * arg)180 vxlan_cb(int s, void *arg)
181 {
182 
183 }
184 
185 static void
vxlan_create(int s,struct ifreq * ifr)186 vxlan_create(int s, struct ifreq *ifr)
187 {
188 
189 	vxlan_check_params();
190 
191 	ifr->ifr_data = (caddr_t) &params;
192 	ioctl_ifcreate(s, ifr);
193 }
194 
195 static
DECL_CMD_FUNC(setvxlan_vni,arg,d)196 DECL_CMD_FUNC(setvxlan_vni, arg, d)
197 {
198 	struct ifvxlancmd cmd;
199 	u_long val;
200 
201 	if (get_val(arg, &val) < 0 || val >= VXLAN_VNI_MAX)
202 		errx(1, "invalid network identifier: %s", arg);
203 
204 	if (!vxlan_exists(s)) {
205 		params.vxlp_with |= VXLAN_PARAM_WITH_VNI;
206 		params.vxlp_vni = val;
207 		return;
208 	}
209 
210 	bzero(&cmd, sizeof(cmd));
211 	cmd.vxlcmd_vni = val;
212 
213 	if (do_cmd(s, VXLAN_CMD_SET_VNI, &cmd, sizeof(cmd), 1) < 0)
214 		err(1, "VXLAN_CMD_SET_VNI");
215 }
216 
217 static
DECL_CMD_FUNC(setvxlan_local,addr,d)218 DECL_CMD_FUNC(setvxlan_local, addr, d)
219 {
220 	struct ifvxlancmd cmd;
221 	struct addrinfo *ai;
222 	struct sockaddr *sa;
223 	int error;
224 
225 	bzero(&cmd, sizeof(cmd));
226 
227 	if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
228 		errx(1, "error in parsing local address string: %s",
229 		    gai_strerror(error));
230 
231 	sa = ai->ai_addr;
232 
233 	switch (ai->ai_family) {
234 #ifdef INET
235 	case AF_INET: {
236 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
237 
238 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
239 			errx(1, "local address cannot be multicast");
240 
241 		cmd.vxlcmd_sa.in4 = *sin;
242 		break;
243 	}
244 #endif
245 #ifdef INET6
246 	case AF_INET6: {
247 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
248 
249 		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
250 			errx(1, "local address cannot be multicast");
251 
252 		cmd.vxlcmd_sa.in6 = *sin6;
253 		break;
254 	}
255 #endif
256 	default:
257 		errx(1, "local address %s not supported", addr);
258 	}
259 
260 	freeaddrinfo(ai);
261 
262 	if (!vxlan_exists(s)) {
263 		if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
264 			params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4;
265 			params.vxlp_local_sa.in4 = cmd.vxlcmd_sa.in4;
266 		} else {
267 			params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6;
268 			params.vxlp_local_sa.in6 = cmd.vxlcmd_sa.in6;
269 		}
270 		return;
271 	}
272 
273 	if (do_cmd(s, VXLAN_CMD_SET_LOCAL_ADDR, &cmd, sizeof(cmd), 1) < 0)
274 		err(1, "VXLAN_CMD_SET_LOCAL_ADDR");
275 }
276 
277 static
DECL_CMD_FUNC(setvxlan_remote,addr,d)278 DECL_CMD_FUNC(setvxlan_remote, addr, d)
279 {
280 	struct ifvxlancmd cmd;
281 	struct addrinfo *ai;
282 	struct sockaddr *sa;
283 	int error;
284 
285 	bzero(&cmd, sizeof(cmd));
286 
287 	if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
288 		errx(1, "error in parsing remote address string: %s",
289 		    gai_strerror(error));
290 
291 	sa = ai->ai_addr;
292 
293 	switch (ai->ai_family) {
294 #ifdef INET
295 	case AF_INET: {
296 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
297 
298 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
299 			errx(1, "remote address cannot be multicast");
300 
301 		cmd.vxlcmd_sa.in4 = *sin;
302 		break;
303 	}
304 #endif
305 #ifdef INET6
306 	case AF_INET6: {
307 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
308 
309 		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
310 			errx(1, "remote address cannot be multicast");
311 
312 		cmd.vxlcmd_sa.in6 = *sin6;
313 		break;
314 	}
315 #endif
316 	default:
317 		errx(1, "remote address %s not supported", addr);
318 	}
319 
320 	freeaddrinfo(ai);
321 
322 	if (!vxlan_exists(s)) {
323 		if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
324 			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
325 			params.vxlp_remote_sa.in4 = cmd.vxlcmd_sa.in4;
326 		} else {
327 			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
328 			params.vxlp_remote_sa.in6 = cmd.vxlcmd_sa.in6;
329 		}
330 		return;
331 	}
332 
333 	if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
334 		err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
335 }
336 
337 static
DECL_CMD_FUNC(setvxlan_group,addr,d)338 DECL_CMD_FUNC(setvxlan_group, addr, d)
339 {
340 	struct ifvxlancmd cmd;
341 	struct addrinfo *ai;
342 	struct sockaddr *sa;
343 	int error;
344 
345 	bzero(&cmd, sizeof(cmd));
346 
347 	if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
348 		errx(1, "error in parsing group address string: %s",
349 		    gai_strerror(error));
350 
351 	sa = ai->ai_addr;
352 
353 	switch (ai->ai_family) {
354 #ifdef INET
355 	case AF_INET: {
356 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
357 
358 		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
359 			errx(1, "group address must be multicast");
360 
361 		cmd.vxlcmd_sa.in4 = *sin;
362 		break;
363 	}
364 #endif
365 #ifdef INET6
366 	case AF_INET6: {
367 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
368 
369 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
370 			errx(1, "group address must be multicast");
371 
372 		cmd.vxlcmd_sa.in6 = *sin6;
373 		break;
374 	}
375 #endif
376 	default:
377 		errx(1, "group address %s not supported", addr);
378 	}
379 
380 	freeaddrinfo(ai);
381 
382 	if (!vxlan_exists(s)) {
383 		if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
384 			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
385 			params.vxlp_remote_sa.in4 = cmd.vxlcmd_sa.in4;
386 		} else {
387 			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
388 			params.vxlp_remote_sa.in6 = cmd.vxlcmd_sa.in6;
389 		}
390 		return;
391 	}
392 
393 	if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
394 		err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
395 }
396 
397 static
DECL_CMD_FUNC(setvxlan_local_port,arg,d)398 DECL_CMD_FUNC(setvxlan_local_port, arg, d)
399 {
400 	struct ifvxlancmd cmd;
401 	u_long val;
402 
403 	if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
404 		errx(1, "invalid local port: %s", arg);
405 
406 	if (!vxlan_exists(s)) {
407 		params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT;
408 		params.vxlp_local_port = val;
409 		return;
410 	}
411 
412 	bzero(&cmd, sizeof(cmd));
413 	cmd.vxlcmd_port = val;
414 
415 	if (do_cmd(s, VXLAN_CMD_SET_LOCAL_PORT, &cmd, sizeof(cmd), 1) < 0)
416 		err(1, "VXLAN_CMD_SET_LOCAL_PORT");
417 }
418 
419 static
DECL_CMD_FUNC(setvxlan_remote_port,arg,d)420 DECL_CMD_FUNC(setvxlan_remote_port, arg, d)
421 {
422 	struct ifvxlancmd cmd;
423 	u_long val;
424 
425 	if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
426 		errx(1, "invalid remote port: %s", arg);
427 
428 	if (!vxlan_exists(s)) {
429 		params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT;
430 		params.vxlp_remote_port = val;
431 		return;
432 	}
433 
434 	bzero(&cmd, sizeof(cmd));
435 	cmd.vxlcmd_port = val;
436 
437 	if (do_cmd(s, VXLAN_CMD_SET_REMOTE_PORT, &cmd, sizeof(cmd), 1) < 0)
438 		err(1, "VXLAN_CMD_SET_REMOTE_PORT");
439 }
440 
441 static
DECL_CMD_FUNC2(setvxlan_port_range,arg1,arg2)442 DECL_CMD_FUNC2(setvxlan_port_range, arg1, arg2)
443 {
444 	struct ifvxlancmd cmd;
445 	u_long min, max;
446 
447 	if (get_val(arg1, &min) < 0 || min >= UINT16_MAX)
448 		errx(1, "invalid port range minimum: %s", arg1);
449 	if (get_val(arg2, &max) < 0 || max >= UINT16_MAX)
450 		errx(1, "invalid port range maximum: %s", arg2);
451 	if (max < min)
452 		errx(1, "invalid port range");
453 
454 	if (!vxlan_exists(s)) {
455 		params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE;
456 		params.vxlp_min_port = min;
457 		params.vxlp_max_port = max;
458 		return;
459 	}
460 
461 	bzero(&cmd, sizeof(cmd));
462 	cmd.vxlcmd_port_min = min;
463 	cmd.vxlcmd_port_max = max;
464 
465 	if (do_cmd(s, VXLAN_CMD_SET_PORT_RANGE, &cmd, sizeof(cmd), 1) < 0)
466 		err(1, "VXLAN_CMD_SET_PORT_RANGE");
467 }
468 
469 static
DECL_CMD_FUNC(setvxlan_timeout,arg,d)470 DECL_CMD_FUNC(setvxlan_timeout, arg, d)
471 {
472 	struct ifvxlancmd cmd;
473 	u_long val;
474 
475 	if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
476 		errx(1, "invalid timeout value: %s", arg);
477 
478 	if (!vxlan_exists(s)) {
479 		params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT;
480 		params.vxlp_ftable_timeout = val & 0xFFFFFFFF;
481 		return;
482 	}
483 
484 	bzero(&cmd, sizeof(cmd));
485 	cmd.vxlcmd_ftable_timeout = val & 0xFFFFFFFF;
486 
487 	if (do_cmd(s, VXLAN_CMD_SET_FTABLE_TIMEOUT, &cmd, sizeof(cmd), 1) < 0)
488 		err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT");
489 }
490 
491 static
DECL_CMD_FUNC(setvxlan_maxaddr,arg,d)492 DECL_CMD_FUNC(setvxlan_maxaddr, arg, d)
493 {
494 	struct ifvxlancmd cmd;
495 	u_long val;
496 
497 	if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
498 		errx(1, "invalid maxaddr value: %s",  arg);
499 
500 	if (!vxlan_exists(s)) {
501 		params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX;
502 		params.vxlp_ftable_max = val & 0xFFFFFFFF;
503 		return;
504 	}
505 
506 	bzero(&cmd, sizeof(cmd));
507 	cmd.vxlcmd_ftable_max = val & 0xFFFFFFFF;
508 
509 	if (do_cmd(s, VXLAN_CMD_SET_FTABLE_MAX, &cmd, sizeof(cmd), 1) < 0)
510 		err(1, "VXLAN_CMD_SET_FTABLE_MAX");
511 }
512 
513 static
DECL_CMD_FUNC(setvxlan_dev,arg,d)514 DECL_CMD_FUNC(setvxlan_dev, arg, d)
515 {
516 	struct ifvxlancmd cmd;
517 
518 	if (!vxlan_exists(s)) {
519 		params.vxlp_with |= VXLAN_PARAM_WITH_MULTICAST_IF;
520 		strlcpy(params.vxlp_mc_ifname, arg,
521 		    sizeof(params.vxlp_mc_ifname));
522 		return;
523 	}
524 
525 	bzero(&cmd, sizeof(cmd));
526 	strlcpy(cmd.vxlcmd_ifname, arg, sizeof(cmd.vxlcmd_ifname));
527 
528 	if (do_cmd(s, VXLAN_CMD_SET_MULTICAST_IF, &cmd, sizeof(cmd), 1) < 0)
529 		err(1, "VXLAN_CMD_SET_MULTICAST_IF");
530 }
531 
532 static
DECL_CMD_FUNC(setvxlan_ttl,arg,d)533 DECL_CMD_FUNC(setvxlan_ttl, arg, d)
534 {
535 	struct ifvxlancmd cmd;
536 	u_long val;
537 
538 	if (get_val(arg, &val) < 0 || val > 256)
539 		errx(1, "invalid TTL value: %s", arg);
540 
541 	if (!vxlan_exists(s)) {
542 		params.vxlp_with |= VXLAN_PARAM_WITH_TTL;
543 		params.vxlp_ttl = val;
544 		return;
545 	}
546 
547 	bzero(&cmd, sizeof(cmd));
548 	cmd.vxlcmd_ttl = val;
549 
550 	if (do_cmd(s, VXLAN_CMD_SET_TTL, &cmd, sizeof(cmd), 1) < 0)
551 		err(1, "VXLAN_CMD_SET_TTL");
552 }
553 
554 static
DECL_CMD_FUNC(setvxlan_learn,arg,d)555 DECL_CMD_FUNC(setvxlan_learn, arg, d)
556 {
557 	struct ifvxlancmd cmd;
558 
559 	if (!vxlan_exists(s)) {
560 		params.vxlp_with |= VXLAN_PARAM_WITH_LEARN;
561 		params.vxlp_learn = d;
562 		return;
563 	}
564 
565 	bzero(&cmd, sizeof(cmd));
566 	if (d != 0)
567 		cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_LEARN;
568 
569 	if (do_cmd(s, VXLAN_CMD_SET_LEARN, &cmd, sizeof(cmd), 1) < 0)
570 		err(1, "VXLAN_CMD_SET_LEARN");
571 }
572 
573 static void
setvxlan_flush(const char * val,int d,int s,const struct afswtch * afp)574 setvxlan_flush(const char *val, int d, int s, const struct afswtch *afp)
575 {
576 	struct ifvxlancmd cmd;
577 
578 	bzero(&cmd, sizeof(cmd));
579 	if (d != 0)
580 		cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_FLUSH_ALL;
581 
582 	if (do_cmd(s, VXLAN_CMD_FLUSH, &cmd, sizeof(cmd), 1) < 0)
583 		err(1, "VXLAN_CMD_FLUSH");
584 }
585 
586 static struct cmd vxlan_cmds[] = {
587 
588 	DEF_CLONE_CMD_ARG("vni",                setvxlan_vni),
589 	DEF_CLONE_CMD_ARG("vxlanid",		setvxlan_vni),
590 	DEF_CLONE_CMD_ARG("vxlanlocal",		setvxlan_local),
591 	DEF_CLONE_CMD_ARG("vxlanremote",	setvxlan_remote),
592 	DEF_CLONE_CMD_ARG("vxlangroup",		setvxlan_group),
593 	DEF_CLONE_CMD_ARG("vxlanlocalport",	setvxlan_local_port),
594 	DEF_CLONE_CMD_ARG("vxlanremoteport",	setvxlan_remote_port),
595 	DEF_CLONE_CMD_ARG2("vxlanportrange",	setvxlan_port_range),
596 	DEF_CLONE_CMD_ARG("vxlantimeout",	setvxlan_timeout),
597 	DEF_CLONE_CMD_ARG("vxlanmaxaddr",	setvxlan_maxaddr),
598 	DEF_CLONE_CMD_ARG("vxlandev",		setvxlan_dev),
599 	DEF_CLONE_CMD_ARG("vxlanttl",		setvxlan_ttl),
600 	DEF_CLONE_CMD("vxlanlearn", 1,		setvxlan_learn),
601 	DEF_CLONE_CMD("-vxlanlearn", 0,		setvxlan_learn),
602 
603 	DEF_CMD_ARG("vni",			setvxlan_vni),
604 	DEF_CMD_ARG("vxlanid",			setvxlan_vni),
605 	DEF_CMD_ARG("vxlanlocal",		setvxlan_local),
606 	DEF_CMD_ARG("vxlanremote",		setvxlan_remote),
607 	DEF_CMD_ARG("vxlangroup",		setvxlan_group),
608 	DEF_CMD_ARG("vxlanlocalport",		setvxlan_local_port),
609 	DEF_CMD_ARG("vxlanremoteport",		setvxlan_remote_port),
610 	DEF_CMD_ARG2("vxlanportrange",		setvxlan_port_range),
611 	DEF_CMD_ARG("vxlantimeout",		setvxlan_timeout),
612 	DEF_CMD_ARG("vxlanmaxaddr",		setvxlan_maxaddr),
613 	DEF_CMD_ARG("vxlandev",			setvxlan_dev),
614 	DEF_CMD_ARG("vxlanttl",			setvxlan_ttl),
615 	DEF_CMD("vxlanlearn", 1,		setvxlan_learn),
616 	DEF_CMD("-vxlanlearn", 0,		setvxlan_learn),
617 
618 	DEF_CMD("vxlanflush", 0,		setvxlan_flush),
619 	DEF_CMD("vxlanflushall", 1,		setvxlan_flush),
620 
621 	DEF_CMD("vxlanhwcsum",	IFCAP_VXLAN_HWCSUM,	setifcap),
622 	DEF_CMD("-vxlanhwcsum",	-IFCAP_VXLAN_HWCSUM,	setifcap),
623 	DEF_CMD("vxlanhwtso",	IFCAP_VXLAN_HWTSO,	setifcap),
624 	DEF_CMD("-vxlanhwtso",	-IFCAP_VXLAN_HWTSO,	setifcap),
625 };
626 
627 static struct afswtch af_vxlan = {
628 	.af_name		= "af_vxlan",
629 	.af_af			= AF_UNSPEC,
630 	.af_other_status	= vxlan_status,
631 };
632 
633 static __constructor void
vxlan_ctor(void)634 vxlan_ctor(void)
635 {
636 	size_t i;
637 
638 	for (i = 0; i < nitems(vxlan_cmds); i++)
639 		cmd_register(&vxlan_cmds[i]);
640 	af_register(&af_vxlan);
641 	callback_register(vxlan_cb, NULL);
642 	clone_setdefcallback_prefix("vxlan", vxlan_create);
643 }
644