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