xref: /freebsd/sbin/ifconfig/ifvxlan.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
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(if_ctx *ctx, u_long op, void *arg, size_t argsize, int set)
77 {
78 	struct ifdrv ifd = {};
79 
80 	strlcpy(ifd.ifd_name, ctx->ifname, sizeof(ifd.ifd_name));
81 	ifd.ifd_cmd = op;
82 	ifd.ifd_len = argsize;
83 	ifd.ifd_data = arg;
84 
85 	return (ioctl_ctx(ctx, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
86 }
87 
88 static int
89 vxlan_exists(if_ctx *ctx)
90 {
91 	struct ifvxlancfg cfg;
92 
93 	bzero(&cfg, sizeof(cfg));
94 
95 	return (do_cmd(ctx, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1);
96 }
97 
98 static void
99 vxlan_status(if_ctx *ctx)
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(ctx, 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 = satosin(rsa);
130 		mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr));
131 	} else {
132 		struct sockaddr_in6 *sin6 = satosin6(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 (ctx->args->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
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
180 vxlan_create(if_ctx *ctx, struct ifreq *ifr)
181 {
182 
183 	vxlan_check_params();
184 
185 	ifr->ifr_data = (caddr_t) &params;
186 	ifcreate_ioctl(ctx, ifr);
187 }
188 
189 static void
190 setvxlan_vni(if_ctx *ctx, const char *arg, int dummy __unused)
191 {
192 	struct ifvxlancmd cmd;
193 	u_long val;
194 
195 	if (get_val(arg, &val) < 0 || val >= VXLAN_VNI_MAX)
196 		errx(1, "invalid network identifier: %s", arg);
197 
198 	if (!vxlan_exists(ctx)) {
199 		params.vxlp_with |= VXLAN_PARAM_WITH_VNI;
200 		params.vxlp_vni = val;
201 		return;
202 	}
203 
204 	bzero(&cmd, sizeof(cmd));
205 	cmd.vxlcmd_vni = val;
206 
207 	if (do_cmd(ctx, VXLAN_CMD_SET_VNI, &cmd, sizeof(cmd), 1) < 0)
208 		err(1, "VXLAN_CMD_SET_VNI");
209 }
210 
211 static void
212 setvxlan_local(if_ctx *ctx, const char *addr, int dummy __unused)
213 {
214 	struct ifvxlancmd cmd;
215 	struct addrinfo *ai;
216 #if (defined INET || defined INET6)
217 	struct sockaddr *sa;
218 #endif
219 	int error;
220 
221 	bzero(&cmd, sizeof(cmd));
222 
223 	if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
224 		errx(1, "error in parsing local address string: %s",
225 		    gai_strerror(error));
226 
227 #if (defined INET || defined INET6)
228 	sa = ai->ai_addr;
229 #endif
230 
231 	switch (ai->ai_family) {
232 #ifdef INET
233 	case AF_INET: {
234 		struct sockaddr_in *sin = satosin(sa);
235 
236 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
237 			errx(1, "local address cannot be multicast");
238 
239 		cmd.vxlcmd_sa.in4 = *sin;
240 		break;
241 	}
242 #endif
243 #ifdef INET6
244 	case AF_INET6: {
245 		struct sockaddr_in6 *sin6 = satosin6(sa);
246 
247 		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
248 			errx(1, "local address cannot be multicast");
249 
250 		cmd.vxlcmd_sa.in6 = *sin6;
251 		break;
252 	}
253 #endif
254 	default:
255 		errx(1, "local address %s not supported", addr);
256 	}
257 
258 	freeaddrinfo(ai);
259 
260 	if (!vxlan_exists(ctx)) {
261 		if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
262 			params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4;
263 			params.vxlp_local_sa.in4 = cmd.vxlcmd_sa.in4;
264 		} else {
265 			params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6;
266 			params.vxlp_local_sa.in6 = cmd.vxlcmd_sa.in6;
267 		}
268 		return;
269 	}
270 
271 	if (do_cmd(ctx, VXLAN_CMD_SET_LOCAL_ADDR, &cmd, sizeof(cmd), 1) < 0)
272 		err(1, "VXLAN_CMD_SET_LOCAL_ADDR");
273 }
274 
275 static void
276 setvxlan_remote(if_ctx *ctx, const char *addr, int dummy __unused)
277 {
278 	struct ifvxlancmd cmd;
279 	struct addrinfo *ai;
280 #if (defined INET || defined INET6)
281 	struct sockaddr *sa;
282 #endif
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 #if (defined INET || defined INET6)
292 	sa = ai->ai_addr;
293 #endif
294 
295 	switch (ai->ai_family) {
296 #ifdef INET
297 	case AF_INET: {
298 		struct sockaddr_in *sin = satosin(sa);
299 
300 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
301 			errx(1, "remote address cannot be multicast");
302 
303 		cmd.vxlcmd_sa.in4 = *sin;
304 		break;
305 	}
306 #endif
307 #ifdef INET6
308 	case AF_INET6: {
309 		struct sockaddr_in6 *sin6 = satosin6(sa);
310 
311 		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
312 			errx(1, "remote address cannot be multicast");
313 
314 		cmd.vxlcmd_sa.in6 = *sin6;
315 		break;
316 	}
317 #endif
318 	default:
319 		errx(1, "remote address %s not supported", addr);
320 	}
321 
322 	freeaddrinfo(ai);
323 
324 	if (!vxlan_exists(ctx)) {
325 		if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
326 			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
327 			params.vxlp_remote_sa.in4 = cmd.vxlcmd_sa.in4;
328 		} else {
329 			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
330 			params.vxlp_remote_sa.in6 = cmd.vxlcmd_sa.in6;
331 		}
332 		return;
333 	}
334 
335 	if (do_cmd(ctx, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
336 		err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
337 }
338 
339 static void
340 setvxlan_group(if_ctx *ctx, const char *addr, int dummy __unused)
341 {
342 	struct ifvxlancmd cmd;
343 	struct addrinfo *ai;
344 #if (defined INET || defined INET6)
345 	struct sockaddr *sa;
346 #endif
347 	int error;
348 
349 	bzero(&cmd, sizeof(cmd));
350 
351 	if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
352 		errx(1, "error in parsing group address string: %s",
353 		    gai_strerror(error));
354 
355 #if (defined INET || defined INET6)
356 	sa = ai->ai_addr;
357 #endif
358 
359 	switch (ai->ai_family) {
360 #ifdef INET
361 	case AF_INET: {
362 		struct sockaddr_in *sin = satosin(sa);
363 
364 		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
365 			errx(1, "group address must be multicast");
366 
367 		cmd.vxlcmd_sa.in4 = *sin;
368 		break;
369 	}
370 #endif
371 #ifdef INET6
372 	case AF_INET6: {
373 		struct sockaddr_in6 *sin6 = satosin6(sa);
374 
375 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
376 			errx(1, "group address must be multicast");
377 
378 		cmd.vxlcmd_sa.in6 = *sin6;
379 		break;
380 	}
381 #endif
382 	default:
383 		errx(1, "group address %s not supported", addr);
384 	}
385 
386 	freeaddrinfo(ai);
387 
388 	if (!vxlan_exists(ctx)) {
389 		if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
390 			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
391 			params.vxlp_remote_sa.in4 = cmd.vxlcmd_sa.in4;
392 		} else {
393 			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
394 			params.vxlp_remote_sa.in6 = cmd.vxlcmd_sa.in6;
395 		}
396 		return;
397 	}
398 
399 	if (do_cmd(ctx, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
400 		err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
401 }
402 
403 static void
404 setvxlan_local_port(if_ctx *ctx, const char *arg, int dummy __unused)
405 {
406 	struct ifvxlancmd cmd;
407 	u_long val;
408 
409 	if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
410 		errx(1, "invalid local port: %s", arg);
411 
412 	if (!vxlan_exists(ctx)) {
413 		params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT;
414 		params.vxlp_local_port = val;
415 		return;
416 	}
417 
418 	bzero(&cmd, sizeof(cmd));
419 	cmd.vxlcmd_port = val;
420 
421 	if (do_cmd(ctx, VXLAN_CMD_SET_LOCAL_PORT, &cmd, sizeof(cmd), 1) < 0)
422 		err(1, "VXLAN_CMD_SET_LOCAL_PORT");
423 }
424 
425 static void
426 setvxlan_remote_port(if_ctx *ctx, const char *arg, int dummy __unused)
427 {
428 	struct ifvxlancmd cmd;
429 	u_long val;
430 
431 	if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
432 		errx(1, "invalid remote port: %s", arg);
433 
434 	if (!vxlan_exists(ctx)) {
435 		params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT;
436 		params.vxlp_remote_port = val;
437 		return;
438 	}
439 
440 	bzero(&cmd, sizeof(cmd));
441 	cmd.vxlcmd_port = val;
442 
443 	if (do_cmd(ctx, VXLAN_CMD_SET_REMOTE_PORT, &cmd, sizeof(cmd), 1) < 0)
444 		err(1, "VXLAN_CMD_SET_REMOTE_PORT");
445 }
446 
447 static void
448 setvxlan_port_range(if_ctx *ctx, const char *arg1, const char *arg2)
449 {
450 	struct ifvxlancmd cmd;
451 	u_long min, max;
452 
453 	if (get_val(arg1, &min) < 0 || min >= UINT16_MAX)
454 		errx(1, "invalid port range minimum: %s", arg1);
455 	if (get_val(arg2, &max) < 0 || max >= UINT16_MAX)
456 		errx(1, "invalid port range maximum: %s", arg2);
457 	if (max < min)
458 		errx(1, "invalid port range");
459 
460 	if (!vxlan_exists(ctx)) {
461 		params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE;
462 		params.vxlp_min_port = min;
463 		params.vxlp_max_port = max;
464 		return;
465 	}
466 
467 	bzero(&cmd, sizeof(cmd));
468 	cmd.vxlcmd_port_min = min;
469 	cmd.vxlcmd_port_max = max;
470 
471 	if (do_cmd(ctx, VXLAN_CMD_SET_PORT_RANGE, &cmd, sizeof(cmd), 1) < 0)
472 		err(1, "VXLAN_CMD_SET_PORT_RANGE");
473 }
474 
475 static void
476 setvxlan_timeout(if_ctx *ctx, const char *arg, int dummy __unused)
477 {
478 	struct ifvxlancmd cmd;
479 	u_long val;
480 
481 	if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
482 		errx(1, "invalid timeout value: %s", arg);
483 
484 	if (!vxlan_exists(ctx)) {
485 		params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT;
486 		params.vxlp_ftable_timeout = val & 0xFFFFFFFF;
487 		return;
488 	}
489 
490 	bzero(&cmd, sizeof(cmd));
491 	cmd.vxlcmd_ftable_timeout = val & 0xFFFFFFFF;
492 
493 	if (do_cmd(ctx, VXLAN_CMD_SET_FTABLE_TIMEOUT, &cmd, sizeof(cmd), 1) < 0)
494 		err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT");
495 }
496 
497 static void
498 setvxlan_maxaddr(if_ctx *ctx, const char *arg, int dummy __unused)
499 {
500 	struct ifvxlancmd cmd;
501 	u_long val;
502 
503 	if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
504 		errx(1, "invalid maxaddr value: %s",  arg);
505 
506 	if (!vxlan_exists(ctx)) {
507 		params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX;
508 		params.vxlp_ftable_max = val & 0xFFFFFFFF;
509 		return;
510 	}
511 
512 	bzero(&cmd, sizeof(cmd));
513 	cmd.vxlcmd_ftable_max = val & 0xFFFFFFFF;
514 
515 	if (do_cmd(ctx, VXLAN_CMD_SET_FTABLE_MAX, &cmd, sizeof(cmd), 1) < 0)
516 		err(1, "VXLAN_CMD_SET_FTABLE_MAX");
517 }
518 
519 static void
520 setvxlan_dev(if_ctx *ctx, const char *arg, int dummy __unused)
521 {
522 	struct ifvxlancmd cmd;
523 
524 	if (!vxlan_exists(ctx)) {
525 		params.vxlp_with |= VXLAN_PARAM_WITH_MULTICAST_IF;
526 		strlcpy(params.vxlp_mc_ifname, arg,
527 		    sizeof(params.vxlp_mc_ifname));
528 		return;
529 	}
530 
531 	bzero(&cmd, sizeof(cmd));
532 	strlcpy(cmd.vxlcmd_ifname, arg, sizeof(cmd.vxlcmd_ifname));
533 
534 	if (do_cmd(ctx, VXLAN_CMD_SET_MULTICAST_IF, &cmd, sizeof(cmd), 1) < 0)
535 		err(1, "VXLAN_CMD_SET_MULTICAST_IF");
536 }
537 
538 static void
539 setvxlan_ttl(if_ctx *ctx, const char *arg, int dummy __unused)
540 {
541 	struct ifvxlancmd cmd;
542 	u_long val;
543 
544 	if (get_val(arg, &val) < 0 || val > 256)
545 		errx(1, "invalid TTL value: %s", arg);
546 
547 	if (!vxlan_exists(ctx)) {
548 		params.vxlp_with |= VXLAN_PARAM_WITH_TTL;
549 		params.vxlp_ttl = val;
550 		return;
551 	}
552 
553 	bzero(&cmd, sizeof(cmd));
554 	cmd.vxlcmd_ttl = val;
555 
556 	if (do_cmd(ctx, VXLAN_CMD_SET_TTL, &cmd, sizeof(cmd), 1) < 0)
557 		err(1, "VXLAN_CMD_SET_TTL");
558 }
559 
560 static void
561 setvxlan_learn(if_ctx *ctx, const char *arg __unused, int d)
562 {
563 	struct ifvxlancmd cmd;
564 
565 	if (!vxlan_exists(ctx)) {
566 		params.vxlp_with |= VXLAN_PARAM_WITH_LEARN;
567 		params.vxlp_learn = d;
568 		return;
569 	}
570 
571 	bzero(&cmd, sizeof(cmd));
572 	if (d != 0)
573 		cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_LEARN;
574 
575 	if (do_cmd(ctx, VXLAN_CMD_SET_LEARN, &cmd, sizeof(cmd), 1) < 0)
576 		err(1, "VXLAN_CMD_SET_LEARN");
577 }
578 
579 static void
580 setvxlan_flush(if_ctx *ctx, const char *val __unused, int d)
581 {
582 	struct ifvxlancmd cmd;
583 
584 	bzero(&cmd, sizeof(cmd));
585 	if (d != 0)
586 		cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_FLUSH_ALL;
587 
588 	if (do_cmd(ctx, VXLAN_CMD_FLUSH, &cmd, sizeof(cmd), 1) < 0)
589 		err(1, "VXLAN_CMD_FLUSH");
590 }
591 
592 static struct cmd vxlan_cmds[] = {
593 
594 	DEF_CLONE_CMD_ARG("vni",                setvxlan_vni),
595 	DEF_CLONE_CMD_ARG("vxlanid",		setvxlan_vni),
596 	DEF_CLONE_CMD_ARG("vxlanlocal",		setvxlan_local),
597 	DEF_CLONE_CMD_ARG("vxlanremote",	setvxlan_remote),
598 	DEF_CLONE_CMD_ARG("vxlangroup",		setvxlan_group),
599 	DEF_CLONE_CMD_ARG("vxlanlocalport",	setvxlan_local_port),
600 	DEF_CLONE_CMD_ARG("vxlanremoteport",	setvxlan_remote_port),
601 	DEF_CLONE_CMD_ARG2("vxlanportrange",	setvxlan_port_range),
602 	DEF_CLONE_CMD_ARG("vxlantimeout",	setvxlan_timeout),
603 	DEF_CLONE_CMD_ARG("vxlanmaxaddr",	setvxlan_maxaddr),
604 	DEF_CLONE_CMD_ARG("vxlandev",		setvxlan_dev),
605 	DEF_CLONE_CMD_ARG("vxlanttl",		setvxlan_ttl),
606 	DEF_CLONE_CMD("vxlanlearn", 1,		setvxlan_learn),
607 	DEF_CLONE_CMD("-vxlanlearn", 0,		setvxlan_learn),
608 
609 	DEF_CMD_ARG("vni",			setvxlan_vni),
610 	DEF_CMD_ARG("vxlanid",			setvxlan_vni),
611 	DEF_CMD_ARG("vxlanlocal",		setvxlan_local),
612 	DEF_CMD_ARG("vxlanremote",		setvxlan_remote),
613 	DEF_CMD_ARG("vxlangroup",		setvxlan_group),
614 	DEF_CMD_ARG("vxlanlocalport",		setvxlan_local_port),
615 	DEF_CMD_ARG("vxlanremoteport",		setvxlan_remote_port),
616 	DEF_CMD_ARG2("vxlanportrange",		setvxlan_port_range),
617 	DEF_CMD_ARG("vxlantimeout",		setvxlan_timeout),
618 	DEF_CMD_ARG("vxlanmaxaddr",		setvxlan_maxaddr),
619 	DEF_CMD_ARG("vxlandev",			setvxlan_dev),
620 	DEF_CMD_ARG("vxlanttl",			setvxlan_ttl),
621 	DEF_CMD("vxlanlearn", 1,		setvxlan_learn),
622 	DEF_CMD("-vxlanlearn", 0,		setvxlan_learn),
623 
624 	DEF_CMD("vxlanflush", 0,		setvxlan_flush),
625 	DEF_CMD("vxlanflushall", 1,		setvxlan_flush),
626 
627 	DEF_CMD("vxlanhwcsum",	IFCAP_VXLAN_HWCSUM,	setifcap),
628 	DEF_CMD("-vxlanhwcsum",	IFCAP_VXLAN_HWCSUM,	clearifcap),
629 	DEF_CMD("vxlanhwtso",	IFCAP_VXLAN_HWTSO,	setifcap),
630 	DEF_CMD("-vxlanhwtso",	IFCAP_VXLAN_HWTSO,	clearifcap),
631 };
632 
633 static struct afswtch af_vxlan = {
634 	.af_name		= "af_vxlan",
635 	.af_af			= AF_UNSPEC,
636 	.af_other_status	= vxlan_status,
637 };
638 
639 static __constructor void
640 vxlan_ctor(void)
641 {
642 	size_t i;
643 
644 	for (i = 0; i < nitems(vxlan_cmds); i++)
645 		cmd_register(&vxlan_cmds[i]);
646 	af_register(&af_vxlan);
647 	clone_setdefcallback_prefix("vxlan", vxlan_create);
648 }
649