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