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