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