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