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