1273331Sbryanv/*- 2273331Sbryanv * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org> 3273331Sbryanv * All rights reserved. 4273331Sbryanv * 5273331Sbryanv * Redistribution and use in source and binary forms, with or without 6273331Sbryanv * modification, are permitted provided that the following conditions 7273331Sbryanv * are met: 8273331Sbryanv * 1. Redistributions of source code must retain the above copyright 9273331Sbryanv * notice unmodified, this list of conditions, and the following 10273331Sbryanv * disclaimer. 11273331Sbryanv * 2. Redistributions in binary form must reproduce the above copyright 12273331Sbryanv * notice, this list of conditions and the following disclaimer in the 13273331Sbryanv * documentation and/or other materials provided with the distribution. 14273331Sbryanv * 15273331Sbryanv * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16273331Sbryanv * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17273331Sbryanv * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18273331Sbryanv * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19273331Sbryanv * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20273331Sbryanv * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21273331Sbryanv * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22273331Sbryanv * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23273331Sbryanv * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24273331Sbryanv * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25273331Sbryanv */ 26273331Sbryanv 27273331Sbryanv#include <sys/cdefs.h> 28273331Sbryanv__FBSDID("$FreeBSD$"); 29273331Sbryanv 30273331Sbryanv#include <sys/param.h> 31273331Sbryanv#include <sys/ioctl.h> 32273331Sbryanv#include <sys/socket.h> 33273331Sbryanv#include <sys/sockio.h> 34273331Sbryanv 35273331Sbryanv#include <stdlib.h> 36273331Sbryanv#include <stdint.h> 37273331Sbryanv#include <unistd.h> 38273331Sbryanv#include <netdb.h> 39273331Sbryanv 40273331Sbryanv#include <net/ethernet.h> 41273331Sbryanv#include <net/if.h> 42273331Sbryanv#include <net/if_var.h> 43273331Sbryanv#include <net/if_vxlan.h> 44273331Sbryanv#include <net/route.h> 45273331Sbryanv#include <netinet/in.h> 46273331Sbryanv 47273331Sbryanv#include <ctype.h> 48273331Sbryanv#include <stdio.h> 49273331Sbryanv#include <string.h> 50273331Sbryanv#include <stdlib.h> 51273331Sbryanv#include <unistd.h> 52273331Sbryanv#include <err.h> 53273331Sbryanv#include <errno.h> 54273331Sbryanv 55273331Sbryanv#include "ifconfig.h" 56273331Sbryanv 57273331Sbryanvstatic struct ifvxlanparam params = { 58273331Sbryanv .vxlp_vni = VXLAN_VNI_MAX, 59273331Sbryanv}; 60273331Sbryanv 61273331Sbryanvstatic int 62273331Sbryanvget_val(const char *cp, u_long *valp) 63273331Sbryanv{ 64273331Sbryanv char *endptr; 65273331Sbryanv u_long val; 66273331Sbryanv 67273331Sbryanv errno = 0; 68273331Sbryanv val = strtoul(cp, &endptr, 0); 69273331Sbryanv if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 70273331Sbryanv return (-1); 71273331Sbryanv 72273331Sbryanv *valp = val; 73273331Sbryanv return (0); 74273331Sbryanv} 75273331Sbryanv 76273331Sbryanvstatic int 77273331Sbryanvdo_cmd(int sock, u_long op, void *arg, size_t argsize, int set) 78273331Sbryanv{ 79273331Sbryanv struct ifdrv ifd; 80273331Sbryanv 81273331Sbryanv bzero(&ifd, sizeof(ifd)); 82273331Sbryanv 83273331Sbryanv strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); 84273331Sbryanv ifd.ifd_cmd = op; 85273331Sbryanv ifd.ifd_len = argsize; 86273331Sbryanv ifd.ifd_data = arg; 87273331Sbryanv 88273331Sbryanv return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); 89273331Sbryanv} 90273331Sbryanv 91273331Sbryanvstatic int 92273331Sbryanvvxlan_exists(int sock) 93273331Sbryanv{ 94273331Sbryanv struct ifvxlancfg cfg; 95273331Sbryanv 96273331Sbryanv bzero(&cfg, sizeof(cfg)); 97273331Sbryanv 98273331Sbryanv return (do_cmd(sock, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1); 99273331Sbryanv} 100273331Sbryanv 101273331Sbryanvstatic void 102273331Sbryanvvxlan_status(int s) 103273331Sbryanv{ 104273331Sbryanv struct ifvxlancfg cfg; 105273331Sbryanv char src[NI_MAXHOST], dst[NI_MAXHOST]; 106273331Sbryanv char srcport[NI_MAXSERV], dstport[NI_MAXSERV]; 107273331Sbryanv struct sockaddr *lsa, *rsa; 108273331Sbryanv int vni, mc, ipv6; 109273331Sbryanv 110273331Sbryanv bzero(&cfg, sizeof(cfg)); 111273331Sbryanv 112273331Sbryanv if (do_cmd(s, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) < 0) 113273331Sbryanv return; 114273331Sbryanv 115273331Sbryanv vni = cfg.vxlc_vni; 116273331Sbryanv lsa = &cfg.vxlc_local_sa.sa; 117273331Sbryanv rsa = &cfg.vxlc_remote_sa.sa; 118273331Sbryanv ipv6 = rsa->sa_family == AF_INET6; 119273331Sbryanv 120273331Sbryanv /* Just report nothing if the network identity isn't set yet. */ 121273331Sbryanv if (vni >= VXLAN_VNI_MAX) 122273331Sbryanv return; 123273331Sbryanv 124273331Sbryanv if (getnameinfo(lsa, lsa->sa_len, src, sizeof(src), 125273331Sbryanv srcport, sizeof(srcport), NI_NUMERICHOST | NI_NUMERICSERV) != 0) 126273331Sbryanv src[0] = srcport[0] = '\0'; 127273331Sbryanv if (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst), 128273331Sbryanv dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0) 129273331Sbryanv dst[0] = dstport[0] = '\0'; 130273331Sbryanv 131273331Sbryanv if (!ipv6) { 132273331Sbryanv struct sockaddr_in *sin = (struct sockaddr_in *)rsa; 133273331Sbryanv mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr)); 134273331Sbryanv } else { 135273331Sbryanv struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rsa; 136273331Sbryanv mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr); 137273331Sbryanv } 138273331Sbryanv 139273331Sbryanv printf("\tvxlan vni %d", vni); 140273331Sbryanv printf(" local %s%s%s:%s", ipv6 ? "[" : "", src, ipv6 ? "]" : "", 141273331Sbryanv srcport); 142273331Sbryanv printf(" %s %s%s%s:%s", mc ? "group" : "remote", ipv6 ? "[" : "", 143273331Sbryanv dst, ipv6 ? "]" : "", dstport); 144273331Sbryanv 145273331Sbryanv if (verbose) { 146273331Sbryanv printf("\n\t\tconfig: "); 147273331Sbryanv printf("%slearning portrange %d-%d ttl %d", 148273331Sbryanv cfg.vxlc_learn ? "" : "no", cfg.vxlc_port_min, 149273331Sbryanv cfg.vxlc_port_max, cfg.vxlc_ttl); 150273331Sbryanv printf("\n\t\tftable: "); 151273331Sbryanv printf("cnt %d max %d timeout %d", 152273331Sbryanv cfg.vxlc_ftable_cnt, cfg.vxlc_ftable_max, 153273331Sbryanv cfg.vxlc_ftable_timeout); 154273331Sbryanv } 155273331Sbryanv 156273331Sbryanv putchar('\n'); 157273331Sbryanv} 158273331Sbryanv 159273331Sbryanv#define _LOCAL_ADDR46 \ 160273331Sbryanv (VXLAN_PARAM_WITH_LOCAL_ADDR4 | VXLAN_PARAM_WITH_LOCAL_ADDR6) 161273331Sbryanv#define _REMOTE_ADDR46 \ 162273331Sbryanv (VXLAN_PARAM_WITH_REMOTE_ADDR4 | VXLAN_PARAM_WITH_REMOTE_ADDR6) 163273331Sbryanv 164273331Sbryanvstatic void 165273331Sbryanvvxlan_check_params(void) 166273331Sbryanv{ 167273331Sbryanv 168273331Sbryanv if ((params.vxlp_with & _LOCAL_ADDR46) == _LOCAL_ADDR46) 169273331Sbryanv errx(1, "cannot specify both local IPv4 and IPv6 addresses"); 170273331Sbryanv if ((params.vxlp_with & _REMOTE_ADDR46) == _REMOTE_ADDR46) 171273331Sbryanv errx(1, "cannot specify both remote IPv4 and IPv6 addresses"); 172273331Sbryanv if ((params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR4 && 173273331Sbryanv params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) || 174273331Sbryanv (params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR6 && 175273331Sbryanv params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4)) 176273331Sbryanv errx(1, "cannot mix IPv4 and IPv6 addresses"); 177273331Sbryanv} 178273331Sbryanv 179273331Sbryanv#undef _LOCAL_ADDR46 180273331Sbryanv#undef _REMOTE_ADDR46 181273331Sbryanv 182273331Sbryanvstatic void 183273331Sbryanvvxlan_cb(int s, void *arg) 184273331Sbryanv{ 185273331Sbryanv 186273331Sbryanv} 187273331Sbryanv 188273331Sbryanvstatic void 189273331Sbryanvvxlan_create(int s, struct ifreq *ifr) 190273331Sbryanv{ 191273331Sbryanv 192273331Sbryanv vxlan_check_params(); 193273331Sbryanv 194273331Sbryanv ifr->ifr_data = (caddr_t) ¶ms; 195273331Sbryanv if (ioctl(s, SIOCIFCREATE2, ifr) < 0) 196273331Sbryanv err(1, "SIOCIFCREATE2"); 197273331Sbryanv} 198273331Sbryanv 199273331Sbryanvstatic 200273331SbryanvDECL_CMD_FUNC(setvxlan_vni, arg, d) 201273331Sbryanv{ 202273331Sbryanv struct ifvxlancmd cmd; 203273331Sbryanv u_long val; 204273331Sbryanv 205273331Sbryanv if (get_val(arg, &val) < 0 || val >= VXLAN_VNI_MAX) 206273331Sbryanv errx(1, "invalid network identifier: %s", arg); 207273331Sbryanv 208273331Sbryanv if (!vxlan_exists(s)) { 209273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_VNI; 210273331Sbryanv params.vxlp_vni = val; 211273331Sbryanv return; 212273331Sbryanv } 213273331Sbryanv 214273331Sbryanv bzero(&cmd, sizeof(cmd)); 215273331Sbryanv cmd.vxlcmd_vni = val; 216273331Sbryanv 217273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_VNI, &cmd, sizeof(cmd), 1) < 0) 218273331Sbryanv err(1, "VXLAN_CMD_SET_VNI"); 219273331Sbryanv} 220273331Sbryanv 221273331Sbryanvstatic 222273331SbryanvDECL_CMD_FUNC(setvxlan_local, addr, d) 223273331Sbryanv{ 224273331Sbryanv struct ifvxlancmd cmd; 225273331Sbryanv struct addrinfo *ai; 226273331Sbryanv struct sockaddr *sa; 227273331Sbryanv int error; 228273331Sbryanv 229273331Sbryanv bzero(&cmd, sizeof(cmd)); 230273331Sbryanv 231273331Sbryanv if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) 232273331Sbryanv errx(1, "error in parsing local address string: %s", 233273331Sbryanv gai_strerror(error)); 234273331Sbryanv 235273331Sbryanv sa = ai->ai_addr; 236273331Sbryanv 237273331Sbryanv switch (ai->ai_family) { 238273331Sbryanv#ifdef INET 239273331Sbryanv case AF_INET: { 240273331Sbryanv struct in_addr addr = ((struct sockaddr_in *) sa)->sin_addr; 241273331Sbryanv 242273331Sbryanv if (IN_MULTICAST(ntohl(addr.s_addr))) 243273331Sbryanv errx(1, "local address cannot be multicast"); 244273331Sbryanv 245273331Sbryanv cmd.vxlcmd_sa.in4.sin_family = AF_INET; 246273331Sbryanv cmd.vxlcmd_sa.in4.sin_addr = addr; 247273331Sbryanv break; 248273331Sbryanv } 249273331Sbryanv#endif 250273331Sbryanv#ifdef INET6 251273331Sbryanv case AF_INET6: { 252273331Sbryanv struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; 253273331Sbryanv 254273331Sbryanv if (IN6_IS_ADDR_MULTICAST(addr)) 255273331Sbryanv errx(1, "local address cannot be multicast"); 256273331Sbryanv 257273331Sbryanv cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; 258273331Sbryanv cmd.vxlcmd_sa.in6.sin6_addr = *addr; 259273331Sbryanv break; 260273331Sbryanv } 261273331Sbryanv#endif 262273331Sbryanv default: 263273331Sbryanv errx(1, "local address %s not supported", addr); 264273331Sbryanv } 265273331Sbryanv 266273331Sbryanv freeaddrinfo(ai); 267273331Sbryanv 268273331Sbryanv if (!vxlan_exists(s)) { 269273331Sbryanv if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { 270273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4; 271273331Sbryanv params.vxlp_local_in4 = cmd.vxlcmd_sa.in4.sin_addr; 272273331Sbryanv } else { 273273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6; 274273331Sbryanv params.vxlp_local_in6 = cmd.vxlcmd_sa.in6.sin6_addr; 275273331Sbryanv } 276273331Sbryanv return; 277273331Sbryanv } 278273331Sbryanv 279273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_LOCAL_ADDR, &cmd, sizeof(cmd), 1) < 0) 280273331Sbryanv err(1, "VXLAN_CMD_SET_LOCAL_ADDR"); 281273331Sbryanv} 282273331Sbryanv 283273331Sbryanvstatic 284273331SbryanvDECL_CMD_FUNC(setvxlan_remote, addr, d) 285273331Sbryanv{ 286273331Sbryanv struct ifvxlancmd cmd; 287273331Sbryanv struct addrinfo *ai; 288273331Sbryanv struct sockaddr *sa; 289273331Sbryanv int error; 290273331Sbryanv 291273331Sbryanv bzero(&cmd, sizeof(cmd)); 292273331Sbryanv 293273331Sbryanv if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) 294273331Sbryanv errx(1, "error in parsing remote address string: %s", 295273331Sbryanv gai_strerror(error)); 296273331Sbryanv 297273331Sbryanv sa = ai->ai_addr; 298273331Sbryanv 299273331Sbryanv switch (ai->ai_family) { 300273331Sbryanv#ifdef INET 301273331Sbryanv case AF_INET: { 302273331Sbryanv struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; 303273331Sbryanv 304273331Sbryanv if (IN_MULTICAST(ntohl(addr.s_addr))) 305273331Sbryanv errx(1, "remote address cannot be multicast"); 306273331Sbryanv 307273331Sbryanv cmd.vxlcmd_sa.in4.sin_family = AF_INET; 308273331Sbryanv cmd.vxlcmd_sa.in4.sin_addr = addr; 309273331Sbryanv break; 310273331Sbryanv } 311273331Sbryanv#endif 312273331Sbryanv#ifdef INET6 313273331Sbryanv case AF_INET6: { 314273331Sbryanv struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; 315273331Sbryanv 316273331Sbryanv if (IN6_IS_ADDR_MULTICAST(addr)) 317273331Sbryanv errx(1, "remote address cannot be multicast"); 318273331Sbryanv 319273331Sbryanv cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; 320273331Sbryanv cmd.vxlcmd_sa.in6.sin6_addr = *addr; 321273331Sbryanv break; 322273331Sbryanv } 323273331Sbryanv#endif 324273331Sbryanv default: 325273331Sbryanv errx(1, "remote address %s not supported", addr); 326273331Sbryanv } 327273331Sbryanv 328273331Sbryanv freeaddrinfo(ai); 329273331Sbryanv 330273331Sbryanv if (!vxlan_exists(s)) { 331273331Sbryanv if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { 332273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; 333273331Sbryanv params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr; 334273331Sbryanv } else { 335273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; 336273331Sbryanv params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr; 337273331Sbryanv } 338273331Sbryanv return; 339273331Sbryanv } 340273331Sbryanv 341273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0) 342273331Sbryanv err(1, "VXLAN_CMD_SET_REMOTE_ADDR"); 343273331Sbryanv} 344273331Sbryanv 345273331Sbryanvstatic 346273331SbryanvDECL_CMD_FUNC(setvxlan_group, addr, d) 347273331Sbryanv{ 348273331Sbryanv struct ifvxlancmd cmd; 349273331Sbryanv struct addrinfo *ai; 350273331Sbryanv struct sockaddr *sa; 351273331Sbryanv int error; 352273331Sbryanv 353273331Sbryanv bzero(&cmd, sizeof(cmd)); 354273331Sbryanv 355273331Sbryanv if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) 356273331Sbryanv errx(1, "error in parsing group address string: %s", 357273331Sbryanv gai_strerror(error)); 358273331Sbryanv 359273331Sbryanv sa = ai->ai_addr; 360273331Sbryanv 361273331Sbryanv switch (ai->ai_family) { 362273331Sbryanv#ifdef INET 363273331Sbryanv case AF_INET: { 364273331Sbryanv struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; 365273331Sbryanv 366273331Sbryanv if (!IN_MULTICAST(ntohl(addr.s_addr))) 367273331Sbryanv errx(1, "group address must be multicast"); 368273331Sbryanv 369273331Sbryanv cmd.vxlcmd_sa.in4.sin_family = AF_INET; 370273331Sbryanv cmd.vxlcmd_sa.in4.sin_addr = addr; 371273331Sbryanv break; 372273331Sbryanv } 373273331Sbryanv#endif 374273331Sbryanv#ifdef INET6 375273331Sbryanv case AF_INET6: { 376273331Sbryanv struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; 377273331Sbryanv 378273331Sbryanv if (!IN6_IS_ADDR_MULTICAST(addr)) 379273331Sbryanv errx(1, "group address must be multicast"); 380273331Sbryanv 381273331Sbryanv cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; 382273331Sbryanv cmd.vxlcmd_sa.in6.sin6_addr = *addr; 383273331Sbryanv break; 384273331Sbryanv } 385273331Sbryanv#endif 386273331Sbryanv default: 387273331Sbryanv errx(1, "group address %s not supported", addr); 388273331Sbryanv } 389273331Sbryanv 390273331Sbryanv freeaddrinfo(ai); 391273331Sbryanv 392273331Sbryanv if (!vxlan_exists(s)) { 393273331Sbryanv if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { 394273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; 395273331Sbryanv params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr; 396273331Sbryanv } else { 397273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; 398273331Sbryanv params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr; 399273331Sbryanv } 400273331Sbryanv return; 401273331Sbryanv } 402273331Sbryanv 403273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0) 404273331Sbryanv err(1, "VXLAN_CMD_SET_REMOTE_ADDR"); 405273331Sbryanv} 406273331Sbryanv 407273331Sbryanvstatic 408273331SbryanvDECL_CMD_FUNC(setvxlan_local_port, arg, d) 409273331Sbryanv{ 410273331Sbryanv struct ifvxlancmd cmd; 411273331Sbryanv u_long val; 412273331Sbryanv 413273331Sbryanv if (get_val(arg, &val) < 0 || val >= UINT16_MAX) 414273331Sbryanv errx(1, "invalid local port: %s", arg); 415273331Sbryanv 416273331Sbryanv if (!vxlan_exists(s)) { 417273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT; 418273331Sbryanv params.vxlp_local_port = val; 419273331Sbryanv return; 420273331Sbryanv } 421273331Sbryanv 422273331Sbryanv bzero(&cmd, sizeof(cmd)); 423273331Sbryanv cmd.vxlcmd_port = val; 424273331Sbryanv 425273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_LOCAL_PORT, &cmd, sizeof(cmd), 1) < 0) 426273331Sbryanv err(1, "VXLAN_CMD_SET_LOCAL_PORT"); 427273331Sbryanv} 428273331Sbryanv 429273331Sbryanvstatic 430273331SbryanvDECL_CMD_FUNC(setvxlan_remote_port, arg, d) 431273331Sbryanv{ 432273331Sbryanv struct ifvxlancmd cmd; 433273331Sbryanv u_long val; 434273331Sbryanv 435273331Sbryanv if (get_val(arg, &val) < 0 || val >= UINT16_MAX) 436273331Sbryanv errx(1, "invalid remote port: %s", arg); 437273331Sbryanv 438273331Sbryanv if (!vxlan_exists(s)) { 439273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT; 440273331Sbryanv params.vxlp_remote_port = val; 441273331Sbryanv return; 442273331Sbryanv } 443273331Sbryanv 444273331Sbryanv bzero(&cmd, sizeof(cmd)); 445273331Sbryanv cmd.vxlcmd_port = val; 446273331Sbryanv 447273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_REMOTE_PORT, &cmd, sizeof(cmd), 1) < 0) 448273331Sbryanv err(1, "VXLAN_CMD_SET_REMOTE_PORT"); 449273331Sbryanv} 450273331Sbryanv 451273331Sbryanvstatic 452273331SbryanvDECL_CMD_FUNC2(setvxlan_port_range, arg1, arg2) 453273331Sbryanv{ 454273331Sbryanv struct ifvxlancmd cmd; 455273331Sbryanv u_long min, max; 456273331Sbryanv 457273331Sbryanv if (get_val(arg1, &min) < 0 || min >= UINT16_MAX) 458273331Sbryanv errx(1, "invalid port range minimum: %s", arg1); 459273331Sbryanv if (get_val(arg2, &max) < 0 || max >= UINT16_MAX) 460273331Sbryanv errx(1, "invalid port range maximum: %s", arg2); 461273331Sbryanv if (max < min) 462273331Sbryanv errx(1, "invalid port range"); 463273331Sbryanv 464273331Sbryanv if (!vxlan_exists(s)) { 465273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE; 466273331Sbryanv params.vxlp_min_port = min; 467273331Sbryanv params.vxlp_max_port = max; 468273331Sbryanv return; 469273331Sbryanv } 470273331Sbryanv 471273331Sbryanv bzero(&cmd, sizeof(cmd)); 472273331Sbryanv cmd.vxlcmd_port_min = min; 473273331Sbryanv cmd.vxlcmd_port_max = max; 474273331Sbryanv 475273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_PORT_RANGE, &cmd, sizeof(cmd), 1) < 0) 476273331Sbryanv err(1, "VXLAN_CMD_SET_PORT_RANGE"); 477273331Sbryanv} 478273331Sbryanv 479273331Sbryanvstatic 480273331SbryanvDECL_CMD_FUNC(setvxlan_timeout, arg, d) 481273331Sbryanv{ 482273331Sbryanv struct ifvxlancmd cmd; 483273331Sbryanv u_long val; 484273331Sbryanv 485273331Sbryanv if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0) 486273331Sbryanv errx(1, "invalid timeout value: %s", arg); 487273331Sbryanv 488273331Sbryanv if (!vxlan_exists(s)) { 489273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT; 490273331Sbryanv params.vxlp_ftable_timeout = val & 0xFFFFFFFF; 491273331Sbryanv return; 492273331Sbryanv } 493273331Sbryanv 494273331Sbryanv bzero(&cmd, sizeof(cmd)); 495273331Sbryanv cmd.vxlcmd_ftable_timeout = val & 0xFFFFFFFF; 496273331Sbryanv 497273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_FTABLE_TIMEOUT, &cmd, sizeof(cmd), 1) < 0) 498273331Sbryanv err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT"); 499273331Sbryanv} 500273331Sbryanv 501273331Sbryanvstatic 502273331SbryanvDECL_CMD_FUNC(setvxlan_maxaddr, arg, d) 503273331Sbryanv{ 504273331Sbryanv struct ifvxlancmd cmd; 505273331Sbryanv u_long val; 506273331Sbryanv 507273331Sbryanv if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0) 508273331Sbryanv errx(1, "invalid maxaddr value: %s", arg); 509273331Sbryanv 510273331Sbryanv if (!vxlan_exists(s)) { 511273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX; 512273331Sbryanv params.vxlp_ftable_max = val & 0xFFFFFFFF; 513273331Sbryanv return; 514273331Sbryanv } 515273331Sbryanv 516273331Sbryanv bzero(&cmd, sizeof(cmd)); 517273331Sbryanv cmd.vxlcmd_ftable_max = val & 0xFFFFFFFF; 518273331Sbryanv 519273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_FTABLE_MAX, &cmd, sizeof(cmd), 1) < 0) 520273331Sbryanv err(1, "VXLAN_CMD_SET_FTABLE_MAX"); 521273331Sbryanv} 522273331Sbryanv 523273331Sbryanvstatic 524273331SbryanvDECL_CMD_FUNC(setvxlan_dev, arg, d) 525273331Sbryanv{ 526273331Sbryanv struct ifvxlancmd cmd; 527273331Sbryanv 528273331Sbryanv if (!vxlan_exists(s)) { 529273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_MULTICAST_IF; 530273331Sbryanv strlcpy(params.vxlp_mc_ifname, arg, 531273331Sbryanv sizeof(params.vxlp_mc_ifname)); 532273331Sbryanv return; 533273331Sbryanv } 534273331Sbryanv 535273331Sbryanv bzero(&cmd, sizeof(cmd)); 536273331Sbryanv strlcpy(cmd.vxlcmd_ifname, arg, sizeof(cmd.vxlcmd_ifname)); 537273331Sbryanv 538273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_MULTICAST_IF, &cmd, sizeof(cmd), 1) < 0) 539273331Sbryanv err(1, "VXLAN_CMD_SET_MULTICAST_IF"); 540273331Sbryanv} 541273331Sbryanv 542273331Sbryanvstatic 543273331SbryanvDECL_CMD_FUNC(setvxlan_ttl, arg, d) 544273331Sbryanv{ 545273331Sbryanv struct ifvxlancmd cmd; 546273331Sbryanv u_long val; 547273331Sbryanv 548273331Sbryanv if (get_val(arg, &val) < 0 || val > 256) 549273331Sbryanv errx(1, "invalid TTL value: %s", arg); 550273331Sbryanv 551273331Sbryanv if (!vxlan_exists(s)) { 552273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_TTL; 553273331Sbryanv params.vxlp_ttl = val; 554273331Sbryanv return; 555273331Sbryanv } 556273331Sbryanv 557273331Sbryanv bzero(&cmd, sizeof(cmd)); 558273331Sbryanv cmd.vxlcmd_ttl = val; 559273331Sbryanv 560273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_TTL, &cmd, sizeof(cmd), 1) < 0) 561273331Sbryanv err(1, "VXLAN_CMD_SET_TTL"); 562273331Sbryanv} 563273331Sbryanv 564273331Sbryanvstatic 565273331SbryanvDECL_CMD_FUNC(setvxlan_learn, arg, d) 566273331Sbryanv{ 567273331Sbryanv struct ifvxlancmd cmd; 568273331Sbryanv 569273331Sbryanv if (!vxlan_exists(s)) { 570273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_LEARN; 571273331Sbryanv params.vxlp_learn = d; 572273331Sbryanv return; 573273331Sbryanv } 574273331Sbryanv 575273331Sbryanv bzero(&cmd, sizeof(cmd)); 576273331Sbryanv if (d != 0) 577273331Sbryanv cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_LEARN; 578273331Sbryanv 579273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_LEARN, &cmd, sizeof(cmd), 1) < 0) 580273331Sbryanv err(1, "VXLAN_CMD_SET_LEARN"); 581273331Sbryanv} 582273331Sbryanv 583273331Sbryanvstatic void 584273331Sbryanvsetvxlan_flush(const char *val, int d, int s, const struct afswtch *afp) 585273331Sbryanv{ 586273331Sbryanv struct ifvxlancmd cmd; 587273331Sbryanv 588273331Sbryanv bzero(&cmd, sizeof(cmd)); 589273331Sbryanv if (d != 0) 590273331Sbryanv cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_FLUSH_ALL; 591273331Sbryanv 592273331Sbryanv if (do_cmd(s, VXLAN_CMD_FLUSH, &cmd, sizeof(cmd), 1) < 0) 593273331Sbryanv err(1, "VXLAN_CMD_FLUSH"); 594273331Sbryanv} 595273331Sbryanv 596273331Sbryanvstatic struct cmd vxlan_cmds[] = { 597273331Sbryanv 598284365Sbryanv DEF_CLONE_CMD_ARG("vxlanid", setvxlan_vni), 599284365Sbryanv DEF_CLONE_CMD_ARG("vxlanlocal", setvxlan_local), 600284365Sbryanv DEF_CLONE_CMD_ARG("vxlanremote", setvxlan_remote), 601284365Sbryanv DEF_CLONE_CMD_ARG("vxlangroup", setvxlan_group), 602284365Sbryanv DEF_CLONE_CMD_ARG("vxlanlocalport", setvxlan_local_port), 603284365Sbryanv DEF_CLONE_CMD_ARG("vxlanremoteport", setvxlan_remote_port), 604284365Sbryanv DEF_CLONE_CMD_ARG2("vxlanportrange", setvxlan_port_range), 605284365Sbryanv DEF_CLONE_CMD_ARG("vxlantimeout", setvxlan_timeout), 606284365Sbryanv DEF_CLONE_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr), 607273331Sbryanv DEF_CLONE_CMD_ARG("vxlandev", setvxlan_dev), 608284365Sbryanv DEF_CLONE_CMD_ARG("vxlanttl", setvxlan_ttl), 609284365Sbryanv DEF_CLONE_CMD("vxlanlearn", 1, setvxlan_learn), 610284365Sbryanv DEF_CLONE_CMD("-vxlanlearn", 0, setvxlan_learn), 611273331Sbryanv 612284365Sbryanv DEF_CMD_ARG("vxlanvni", setvxlan_vni), 613284365Sbryanv DEF_CMD_ARG("vxlanlocal", setvxlan_local), 614284365Sbryanv DEF_CMD_ARG("vxlanremote", setvxlan_remote), 615284365Sbryanv DEF_CMD_ARG("vxlangroup", setvxlan_group), 616284365Sbryanv DEF_CMD_ARG("vxlanlocalport", setvxlan_local_port), 617284365Sbryanv DEF_CMD_ARG("vxlanremoteport", setvxlan_remote_port), 618284365Sbryanv DEF_CMD_ARG2("vxlanportrange", setvxlan_port_range), 619284365Sbryanv DEF_CMD_ARG("vxlantimeout", setvxlan_timeout), 620284365Sbryanv DEF_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr), 621273331Sbryanv DEF_CMD_ARG("vxlandev", setvxlan_dev), 622284365Sbryanv DEF_CMD_ARG("vxlanttl", setvxlan_ttl), 623284365Sbryanv DEF_CMD("vxlanlearn", 1, setvxlan_learn), 624284365Sbryanv DEF_CMD("-vxlanlearn", 0, setvxlan_learn), 625273331Sbryanv 626284365Sbryanv DEF_CMD("vxlanflush", 0, setvxlan_flush), 627284365Sbryanv DEF_CMD("vxlanflushall", 1, setvxlan_flush), 628273331Sbryanv}; 629273331Sbryanv 630273331Sbryanvstatic struct afswtch af_vxlan = { 631273331Sbryanv .af_name = "af_vxlan", 632273331Sbryanv .af_af = AF_UNSPEC, 633273331Sbryanv .af_other_status = vxlan_status, 634273331Sbryanv}; 635273331Sbryanv 636273331Sbryanvstatic __constructor void 637273331Sbryanvvxlan_ctor(void) 638273331Sbryanv{ 639273331Sbryanv size_t i; 640273331Sbryanv 641289986Sngie for (i = 0; i < nitems(vxlan_cmds); i++) 642273331Sbryanv cmd_register(&vxlan_cmds[i]); 643273331Sbryanv af_register(&af_vxlan); 644273331Sbryanv callback_register(vxlan_cb, NULL); 645273331Sbryanv clone_setdefcallback("vxlan", vxlan_create); 646273331Sbryanv} 647