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