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