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