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: releng/11.0/sbin/ifconfig/ifvxlan.c 288305 2015-09-27 07:51:18Z ngie $"); 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_vxlan.h> 43273331Sbryanv#include <net/route.h> 44273331Sbryanv#include <netinet/in.h> 45273331Sbryanv 46273331Sbryanv#include <ctype.h> 47273331Sbryanv#include <stdio.h> 48273331Sbryanv#include <string.h> 49273331Sbryanv#include <stdlib.h> 50273331Sbryanv#include <unistd.h> 51273331Sbryanv#include <err.h> 52273331Sbryanv#include <errno.h> 53273331Sbryanv 54273331Sbryanv#include "ifconfig.h" 55273331Sbryanv 56273331Sbryanvstatic struct ifvxlanparam params = { 57273331Sbryanv .vxlp_vni = VXLAN_VNI_MAX, 58273331Sbryanv}; 59273331Sbryanv 60273331Sbryanvstatic int 61273331Sbryanvget_val(const char *cp, u_long *valp) 62273331Sbryanv{ 63273331Sbryanv char *endptr; 64273331Sbryanv u_long val; 65273331Sbryanv 66273331Sbryanv errno = 0; 67273331Sbryanv val = strtoul(cp, &endptr, 0); 68273331Sbryanv if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 69273331Sbryanv return (-1); 70273331Sbryanv 71273331Sbryanv *valp = val; 72273331Sbryanv return (0); 73273331Sbryanv} 74273331Sbryanv 75273331Sbryanvstatic int 76273331Sbryanvdo_cmd(int sock, u_long op, void *arg, size_t argsize, int set) 77273331Sbryanv{ 78273331Sbryanv struct ifdrv ifd; 79273331Sbryanv 80273331Sbryanv bzero(&ifd, sizeof(ifd)); 81273331Sbryanv 82273331Sbryanv strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); 83273331Sbryanv ifd.ifd_cmd = op; 84273331Sbryanv ifd.ifd_len = argsize; 85273331Sbryanv ifd.ifd_data = arg; 86273331Sbryanv 87273331Sbryanv return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); 88273331Sbryanv} 89273331Sbryanv 90273331Sbryanvstatic int 91273331Sbryanvvxlan_exists(int sock) 92273331Sbryanv{ 93273331Sbryanv struct ifvxlancfg cfg; 94273331Sbryanv 95273331Sbryanv bzero(&cfg, sizeof(cfg)); 96273331Sbryanv 97273331Sbryanv return (do_cmd(sock, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1); 98273331Sbryanv} 99273331Sbryanv 100273331Sbryanvstatic void 101273331Sbryanvvxlan_status(int s) 102273331Sbryanv{ 103273331Sbryanv struct ifvxlancfg cfg; 104273331Sbryanv char src[NI_MAXHOST], dst[NI_MAXHOST]; 105273331Sbryanv char srcport[NI_MAXSERV], dstport[NI_MAXSERV]; 106273331Sbryanv struct sockaddr *lsa, *rsa; 107273331Sbryanv int vni, mc, ipv6; 108273331Sbryanv 109273331Sbryanv bzero(&cfg, sizeof(cfg)); 110273331Sbryanv 111273331Sbryanv if (do_cmd(s, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) < 0) 112273331Sbryanv return; 113273331Sbryanv 114273331Sbryanv vni = cfg.vxlc_vni; 115273331Sbryanv lsa = &cfg.vxlc_local_sa.sa; 116273331Sbryanv rsa = &cfg.vxlc_remote_sa.sa; 117273331Sbryanv ipv6 = rsa->sa_family == AF_INET6; 118273331Sbryanv 119273331Sbryanv /* Just report nothing if the network identity isn't set yet. */ 120273331Sbryanv if (vni >= VXLAN_VNI_MAX) 121273331Sbryanv return; 122273331Sbryanv 123273331Sbryanv if (getnameinfo(lsa, lsa->sa_len, src, sizeof(src), 124273331Sbryanv srcport, sizeof(srcport), NI_NUMERICHOST | NI_NUMERICSERV) != 0) 125273331Sbryanv src[0] = srcport[0] = '\0'; 126273331Sbryanv if (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst), 127273331Sbryanv dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0) 128273331Sbryanv dst[0] = dstport[0] = '\0'; 129273331Sbryanv 130273331Sbryanv if (!ipv6) { 131273331Sbryanv struct sockaddr_in *sin = (struct sockaddr_in *)rsa; 132273331Sbryanv mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr)); 133273331Sbryanv } else { 134273331Sbryanv struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rsa; 135273331Sbryanv mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr); 136273331Sbryanv } 137273331Sbryanv 138273331Sbryanv printf("\tvxlan vni %d", vni); 139273331Sbryanv printf(" local %s%s%s:%s", ipv6 ? "[" : "", src, ipv6 ? "]" : "", 140273331Sbryanv srcport); 141273331Sbryanv printf(" %s %s%s%s:%s", mc ? "group" : "remote", ipv6 ? "[" : "", 142273331Sbryanv dst, ipv6 ? "]" : "", dstport); 143273331Sbryanv 144273331Sbryanv if (verbose) { 145273331Sbryanv printf("\n\t\tconfig: "); 146273331Sbryanv printf("%slearning portrange %d-%d ttl %d", 147273331Sbryanv cfg.vxlc_learn ? "" : "no", cfg.vxlc_port_min, 148273331Sbryanv cfg.vxlc_port_max, cfg.vxlc_ttl); 149273331Sbryanv printf("\n\t\tftable: "); 150273331Sbryanv printf("cnt %d max %d timeout %d", 151273331Sbryanv cfg.vxlc_ftable_cnt, cfg.vxlc_ftable_max, 152273331Sbryanv cfg.vxlc_ftable_timeout); 153273331Sbryanv } 154273331Sbryanv 155273331Sbryanv putchar('\n'); 156273331Sbryanv} 157273331Sbryanv 158273331Sbryanv#define _LOCAL_ADDR46 \ 159273331Sbryanv (VXLAN_PARAM_WITH_LOCAL_ADDR4 | VXLAN_PARAM_WITH_LOCAL_ADDR6) 160273331Sbryanv#define _REMOTE_ADDR46 \ 161273331Sbryanv (VXLAN_PARAM_WITH_REMOTE_ADDR4 | VXLAN_PARAM_WITH_REMOTE_ADDR6) 162273331Sbryanv 163273331Sbryanvstatic void 164273331Sbryanvvxlan_check_params(void) 165273331Sbryanv{ 166273331Sbryanv 167273331Sbryanv if ((params.vxlp_with & _LOCAL_ADDR46) == _LOCAL_ADDR46) 168273331Sbryanv errx(1, "cannot specify both local IPv4 and IPv6 addresses"); 169273331Sbryanv if ((params.vxlp_with & _REMOTE_ADDR46) == _REMOTE_ADDR46) 170273331Sbryanv errx(1, "cannot specify both remote IPv4 and IPv6 addresses"); 171273331Sbryanv if ((params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR4 && 172273331Sbryanv params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) || 173273331Sbryanv (params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR6 && 174273331Sbryanv params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4)) 175273331Sbryanv errx(1, "cannot mix IPv4 and IPv6 addresses"); 176273331Sbryanv} 177273331Sbryanv 178273331Sbryanv#undef _LOCAL_ADDR46 179273331Sbryanv#undef _REMOTE_ADDR46 180273331Sbryanv 181273331Sbryanvstatic void 182273331Sbryanvvxlan_cb(int s, void *arg) 183273331Sbryanv{ 184273331Sbryanv 185273331Sbryanv} 186273331Sbryanv 187273331Sbryanvstatic void 188273331Sbryanvvxlan_create(int s, struct ifreq *ifr) 189273331Sbryanv{ 190273331Sbryanv 191273331Sbryanv vxlan_check_params(); 192273331Sbryanv 193273331Sbryanv ifr->ifr_data = (caddr_t) ¶ms; 194273331Sbryanv if (ioctl(s, SIOCIFCREATE2, ifr) < 0) 195273331Sbryanv err(1, "SIOCIFCREATE2"); 196273331Sbryanv} 197273331Sbryanv 198273331Sbryanvstatic 199273331SbryanvDECL_CMD_FUNC(setvxlan_vni, arg, d) 200273331Sbryanv{ 201273331Sbryanv struct ifvxlancmd cmd; 202273331Sbryanv u_long val; 203273331Sbryanv 204273331Sbryanv if (get_val(arg, &val) < 0 || val >= VXLAN_VNI_MAX) 205273331Sbryanv errx(1, "invalid network identifier: %s", arg); 206273331Sbryanv 207273331Sbryanv if (!vxlan_exists(s)) { 208273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_VNI; 209273331Sbryanv params.vxlp_vni = val; 210273331Sbryanv return; 211273331Sbryanv } 212273331Sbryanv 213273331Sbryanv bzero(&cmd, sizeof(cmd)); 214273331Sbryanv cmd.vxlcmd_vni = val; 215273331Sbryanv 216273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_VNI, &cmd, sizeof(cmd), 1) < 0) 217273331Sbryanv err(1, "VXLAN_CMD_SET_VNI"); 218273331Sbryanv} 219273331Sbryanv 220273331Sbryanvstatic 221273331SbryanvDECL_CMD_FUNC(setvxlan_local, addr, d) 222273331Sbryanv{ 223273331Sbryanv struct ifvxlancmd cmd; 224273331Sbryanv struct addrinfo *ai; 225273331Sbryanv struct sockaddr *sa; 226273331Sbryanv int error; 227273331Sbryanv 228273331Sbryanv bzero(&cmd, sizeof(cmd)); 229273331Sbryanv 230273331Sbryanv if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) 231273331Sbryanv errx(1, "error in parsing local address string: %s", 232273331Sbryanv gai_strerror(error)); 233273331Sbryanv 234273331Sbryanv sa = ai->ai_addr; 235273331Sbryanv 236273331Sbryanv switch (ai->ai_family) { 237273331Sbryanv#ifdef INET 238273331Sbryanv case AF_INET: { 239273331Sbryanv struct in_addr addr = ((struct sockaddr_in *) sa)->sin_addr; 240273331Sbryanv 241273331Sbryanv if (IN_MULTICAST(ntohl(addr.s_addr))) 242273331Sbryanv errx(1, "local address cannot be multicast"); 243273331Sbryanv 244273331Sbryanv cmd.vxlcmd_sa.in4.sin_family = AF_INET; 245273331Sbryanv cmd.vxlcmd_sa.in4.sin_addr = addr; 246273331Sbryanv break; 247273331Sbryanv } 248273331Sbryanv#endif 249273331Sbryanv#ifdef INET6 250273331Sbryanv case AF_INET6: { 251273331Sbryanv struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; 252273331Sbryanv 253273331Sbryanv if (IN6_IS_ADDR_MULTICAST(addr)) 254273331Sbryanv errx(1, "local address cannot be multicast"); 255273331Sbryanv 256273331Sbryanv cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; 257273331Sbryanv cmd.vxlcmd_sa.in6.sin6_addr = *addr; 258273331Sbryanv break; 259273331Sbryanv } 260273331Sbryanv#endif 261273331Sbryanv default: 262273331Sbryanv errx(1, "local address %s not supported", addr); 263273331Sbryanv } 264273331Sbryanv 265273331Sbryanv freeaddrinfo(ai); 266273331Sbryanv 267273331Sbryanv if (!vxlan_exists(s)) { 268273331Sbryanv if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { 269273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4; 270273331Sbryanv params.vxlp_local_in4 = cmd.vxlcmd_sa.in4.sin_addr; 271273331Sbryanv } else { 272273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6; 273273331Sbryanv params.vxlp_local_in6 = cmd.vxlcmd_sa.in6.sin6_addr; 274273331Sbryanv } 275273331Sbryanv return; 276273331Sbryanv } 277273331Sbryanv 278273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_LOCAL_ADDR, &cmd, sizeof(cmd), 1) < 0) 279273331Sbryanv err(1, "VXLAN_CMD_SET_LOCAL_ADDR"); 280273331Sbryanv} 281273331Sbryanv 282273331Sbryanvstatic 283273331SbryanvDECL_CMD_FUNC(setvxlan_remote, addr, d) 284273331Sbryanv{ 285273331Sbryanv struct ifvxlancmd cmd; 286273331Sbryanv struct addrinfo *ai; 287273331Sbryanv struct sockaddr *sa; 288273331Sbryanv int error; 289273331Sbryanv 290273331Sbryanv bzero(&cmd, sizeof(cmd)); 291273331Sbryanv 292273331Sbryanv if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) 293273331Sbryanv errx(1, "error in parsing remote address string: %s", 294273331Sbryanv gai_strerror(error)); 295273331Sbryanv 296273331Sbryanv sa = ai->ai_addr; 297273331Sbryanv 298273331Sbryanv switch (ai->ai_family) { 299273331Sbryanv#ifdef INET 300273331Sbryanv case AF_INET: { 301273331Sbryanv struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; 302273331Sbryanv 303273331Sbryanv if (IN_MULTICAST(ntohl(addr.s_addr))) 304273331Sbryanv errx(1, "remote address cannot be multicast"); 305273331Sbryanv 306273331Sbryanv cmd.vxlcmd_sa.in4.sin_family = AF_INET; 307273331Sbryanv cmd.vxlcmd_sa.in4.sin_addr = addr; 308273331Sbryanv break; 309273331Sbryanv } 310273331Sbryanv#endif 311273331Sbryanv#ifdef INET6 312273331Sbryanv case AF_INET6: { 313273331Sbryanv struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; 314273331Sbryanv 315273331Sbryanv if (IN6_IS_ADDR_MULTICAST(addr)) 316273331Sbryanv errx(1, "remote address cannot be multicast"); 317273331Sbryanv 318273331Sbryanv cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; 319273331Sbryanv cmd.vxlcmd_sa.in6.sin6_addr = *addr; 320273331Sbryanv break; 321273331Sbryanv } 322273331Sbryanv#endif 323273331Sbryanv default: 324273331Sbryanv errx(1, "remote address %s not supported", addr); 325273331Sbryanv } 326273331Sbryanv 327273331Sbryanv freeaddrinfo(ai); 328273331Sbryanv 329273331Sbryanv if (!vxlan_exists(s)) { 330273331Sbryanv if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { 331273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; 332273331Sbryanv params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr; 333273331Sbryanv } else { 334273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; 335273331Sbryanv params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr; 336273331Sbryanv } 337273331Sbryanv return; 338273331Sbryanv } 339273331Sbryanv 340273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0) 341273331Sbryanv err(1, "VXLAN_CMD_SET_REMOTE_ADDR"); 342273331Sbryanv} 343273331Sbryanv 344273331Sbryanvstatic 345273331SbryanvDECL_CMD_FUNC(setvxlan_group, addr, d) 346273331Sbryanv{ 347273331Sbryanv struct ifvxlancmd cmd; 348273331Sbryanv struct addrinfo *ai; 349273331Sbryanv struct sockaddr *sa; 350273331Sbryanv int error; 351273331Sbryanv 352273331Sbryanv bzero(&cmd, sizeof(cmd)); 353273331Sbryanv 354273331Sbryanv if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) 355273331Sbryanv errx(1, "error in parsing group address string: %s", 356273331Sbryanv gai_strerror(error)); 357273331Sbryanv 358273331Sbryanv sa = ai->ai_addr; 359273331Sbryanv 360273331Sbryanv switch (ai->ai_family) { 361273331Sbryanv#ifdef INET 362273331Sbryanv case AF_INET: { 363273331Sbryanv struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; 364273331Sbryanv 365273331Sbryanv if (!IN_MULTICAST(ntohl(addr.s_addr))) 366273331Sbryanv errx(1, "group address must be multicast"); 367273331Sbryanv 368273331Sbryanv cmd.vxlcmd_sa.in4.sin_family = AF_INET; 369273331Sbryanv cmd.vxlcmd_sa.in4.sin_addr = addr; 370273331Sbryanv break; 371273331Sbryanv } 372273331Sbryanv#endif 373273331Sbryanv#ifdef INET6 374273331Sbryanv case AF_INET6: { 375273331Sbryanv struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; 376273331Sbryanv 377273331Sbryanv if (!IN6_IS_ADDR_MULTICAST(addr)) 378273331Sbryanv errx(1, "group address must be multicast"); 379273331Sbryanv 380273331Sbryanv cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; 381273331Sbryanv cmd.vxlcmd_sa.in6.sin6_addr = *addr; 382273331Sbryanv break; 383273331Sbryanv } 384273331Sbryanv#endif 385273331Sbryanv default: 386273331Sbryanv errx(1, "group address %s not supported", addr); 387273331Sbryanv } 388273331Sbryanv 389273331Sbryanv freeaddrinfo(ai); 390273331Sbryanv 391273331Sbryanv if (!vxlan_exists(s)) { 392273331Sbryanv if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { 393273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; 394273331Sbryanv params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr; 395273331Sbryanv } else { 396273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; 397273331Sbryanv params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr; 398273331Sbryanv } 399273331Sbryanv return; 400273331Sbryanv } 401273331Sbryanv 402273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0) 403273331Sbryanv err(1, "VXLAN_CMD_SET_REMOTE_ADDR"); 404273331Sbryanv} 405273331Sbryanv 406273331Sbryanvstatic 407273331SbryanvDECL_CMD_FUNC(setvxlan_local_port, arg, d) 408273331Sbryanv{ 409273331Sbryanv struct ifvxlancmd cmd; 410273331Sbryanv u_long val; 411273331Sbryanv 412273331Sbryanv if (get_val(arg, &val) < 0 || val >= UINT16_MAX) 413273331Sbryanv errx(1, "invalid local port: %s", arg); 414273331Sbryanv 415273331Sbryanv if (!vxlan_exists(s)) { 416273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT; 417273331Sbryanv params.vxlp_local_port = val; 418273331Sbryanv return; 419273331Sbryanv } 420273331Sbryanv 421273331Sbryanv bzero(&cmd, sizeof(cmd)); 422273331Sbryanv cmd.vxlcmd_port = val; 423273331Sbryanv 424273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_LOCAL_PORT, &cmd, sizeof(cmd), 1) < 0) 425273331Sbryanv err(1, "VXLAN_CMD_SET_LOCAL_PORT"); 426273331Sbryanv} 427273331Sbryanv 428273331Sbryanvstatic 429273331SbryanvDECL_CMD_FUNC(setvxlan_remote_port, arg, d) 430273331Sbryanv{ 431273331Sbryanv struct ifvxlancmd cmd; 432273331Sbryanv u_long val; 433273331Sbryanv 434273331Sbryanv if (get_val(arg, &val) < 0 || val >= UINT16_MAX) 435273331Sbryanv errx(1, "invalid remote port: %s", arg); 436273331Sbryanv 437273331Sbryanv if (!vxlan_exists(s)) { 438273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT; 439273331Sbryanv params.vxlp_remote_port = val; 440273331Sbryanv return; 441273331Sbryanv } 442273331Sbryanv 443273331Sbryanv bzero(&cmd, sizeof(cmd)); 444273331Sbryanv cmd.vxlcmd_port = val; 445273331Sbryanv 446273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_REMOTE_PORT, &cmd, sizeof(cmd), 1) < 0) 447273331Sbryanv err(1, "VXLAN_CMD_SET_REMOTE_PORT"); 448273331Sbryanv} 449273331Sbryanv 450273331Sbryanvstatic 451273331SbryanvDECL_CMD_FUNC2(setvxlan_port_range, arg1, arg2) 452273331Sbryanv{ 453273331Sbryanv struct ifvxlancmd cmd; 454273331Sbryanv u_long min, max; 455273331Sbryanv 456273331Sbryanv if (get_val(arg1, &min) < 0 || min >= UINT16_MAX) 457273331Sbryanv errx(1, "invalid port range minimum: %s", arg1); 458273331Sbryanv if (get_val(arg2, &max) < 0 || max >= UINT16_MAX) 459273331Sbryanv errx(1, "invalid port range maximum: %s", arg2); 460273331Sbryanv if (max < min) 461273331Sbryanv errx(1, "invalid port range"); 462273331Sbryanv 463273331Sbryanv if (!vxlan_exists(s)) { 464273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE; 465273331Sbryanv params.vxlp_min_port = min; 466273331Sbryanv params.vxlp_max_port = max; 467273331Sbryanv return; 468273331Sbryanv } 469273331Sbryanv 470273331Sbryanv bzero(&cmd, sizeof(cmd)); 471273331Sbryanv cmd.vxlcmd_port_min = min; 472273331Sbryanv cmd.vxlcmd_port_max = max; 473273331Sbryanv 474273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_PORT_RANGE, &cmd, sizeof(cmd), 1) < 0) 475273331Sbryanv err(1, "VXLAN_CMD_SET_PORT_RANGE"); 476273331Sbryanv} 477273331Sbryanv 478273331Sbryanvstatic 479273331SbryanvDECL_CMD_FUNC(setvxlan_timeout, arg, d) 480273331Sbryanv{ 481273331Sbryanv struct ifvxlancmd cmd; 482273331Sbryanv u_long val; 483273331Sbryanv 484273331Sbryanv if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0) 485273331Sbryanv errx(1, "invalid timeout value: %s", arg); 486273331Sbryanv 487273331Sbryanv if (!vxlan_exists(s)) { 488273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT; 489273331Sbryanv params.vxlp_ftable_timeout = val & 0xFFFFFFFF; 490273331Sbryanv return; 491273331Sbryanv } 492273331Sbryanv 493273331Sbryanv bzero(&cmd, sizeof(cmd)); 494273331Sbryanv cmd.vxlcmd_ftable_timeout = val & 0xFFFFFFFF; 495273331Sbryanv 496273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_FTABLE_TIMEOUT, &cmd, sizeof(cmd), 1) < 0) 497273331Sbryanv err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT"); 498273331Sbryanv} 499273331Sbryanv 500273331Sbryanvstatic 501273331SbryanvDECL_CMD_FUNC(setvxlan_maxaddr, arg, d) 502273331Sbryanv{ 503273331Sbryanv struct ifvxlancmd cmd; 504273331Sbryanv u_long val; 505273331Sbryanv 506273331Sbryanv if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0) 507273331Sbryanv errx(1, "invalid maxaddr value: %s", arg); 508273331Sbryanv 509273331Sbryanv if (!vxlan_exists(s)) { 510273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX; 511273331Sbryanv params.vxlp_ftable_max = val & 0xFFFFFFFF; 512273331Sbryanv return; 513273331Sbryanv } 514273331Sbryanv 515273331Sbryanv bzero(&cmd, sizeof(cmd)); 516273331Sbryanv cmd.vxlcmd_ftable_max = val & 0xFFFFFFFF; 517273331Sbryanv 518273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_FTABLE_MAX, &cmd, sizeof(cmd), 1) < 0) 519273331Sbryanv err(1, "VXLAN_CMD_SET_FTABLE_MAX"); 520273331Sbryanv} 521273331Sbryanv 522273331Sbryanvstatic 523273331SbryanvDECL_CMD_FUNC(setvxlan_dev, arg, d) 524273331Sbryanv{ 525273331Sbryanv struct ifvxlancmd cmd; 526273331Sbryanv 527273331Sbryanv if (!vxlan_exists(s)) { 528273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_MULTICAST_IF; 529273331Sbryanv strlcpy(params.vxlp_mc_ifname, arg, 530273331Sbryanv sizeof(params.vxlp_mc_ifname)); 531273331Sbryanv return; 532273331Sbryanv } 533273331Sbryanv 534273331Sbryanv bzero(&cmd, sizeof(cmd)); 535273331Sbryanv strlcpy(cmd.vxlcmd_ifname, arg, sizeof(cmd.vxlcmd_ifname)); 536273331Sbryanv 537273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_MULTICAST_IF, &cmd, sizeof(cmd), 1) < 0) 538273331Sbryanv err(1, "VXLAN_CMD_SET_MULTICAST_IF"); 539273331Sbryanv} 540273331Sbryanv 541273331Sbryanvstatic 542273331SbryanvDECL_CMD_FUNC(setvxlan_ttl, arg, d) 543273331Sbryanv{ 544273331Sbryanv struct ifvxlancmd cmd; 545273331Sbryanv u_long val; 546273331Sbryanv 547273331Sbryanv if (get_val(arg, &val) < 0 || val > 256) 548273331Sbryanv errx(1, "invalid TTL value: %s", arg); 549273331Sbryanv 550273331Sbryanv if (!vxlan_exists(s)) { 551273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_TTL; 552273331Sbryanv params.vxlp_ttl = val; 553273331Sbryanv return; 554273331Sbryanv } 555273331Sbryanv 556273331Sbryanv bzero(&cmd, sizeof(cmd)); 557273331Sbryanv cmd.vxlcmd_ttl = val; 558273331Sbryanv 559273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_TTL, &cmd, sizeof(cmd), 1) < 0) 560273331Sbryanv err(1, "VXLAN_CMD_SET_TTL"); 561273331Sbryanv} 562273331Sbryanv 563273331Sbryanvstatic 564273331SbryanvDECL_CMD_FUNC(setvxlan_learn, arg, d) 565273331Sbryanv{ 566273331Sbryanv struct ifvxlancmd cmd; 567273331Sbryanv 568273331Sbryanv if (!vxlan_exists(s)) { 569273331Sbryanv params.vxlp_with |= VXLAN_PARAM_WITH_LEARN; 570273331Sbryanv params.vxlp_learn = d; 571273331Sbryanv return; 572273331Sbryanv } 573273331Sbryanv 574273331Sbryanv bzero(&cmd, sizeof(cmd)); 575273331Sbryanv if (d != 0) 576273331Sbryanv cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_LEARN; 577273331Sbryanv 578273331Sbryanv if (do_cmd(s, VXLAN_CMD_SET_LEARN, &cmd, sizeof(cmd), 1) < 0) 579273331Sbryanv err(1, "VXLAN_CMD_SET_LEARN"); 580273331Sbryanv} 581273331Sbryanv 582273331Sbryanvstatic void 583273331Sbryanvsetvxlan_flush(const char *val, int d, int s, const struct afswtch *afp) 584273331Sbryanv{ 585273331Sbryanv struct ifvxlancmd cmd; 586273331Sbryanv 587273331Sbryanv bzero(&cmd, sizeof(cmd)); 588273331Sbryanv if (d != 0) 589273331Sbryanv cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_FLUSH_ALL; 590273331Sbryanv 591273331Sbryanv if (do_cmd(s, VXLAN_CMD_FLUSH, &cmd, sizeof(cmd), 1) < 0) 592273331Sbryanv err(1, "VXLAN_CMD_FLUSH"); 593273331Sbryanv} 594273331Sbryanv 595273331Sbryanvstatic struct cmd vxlan_cmds[] = { 596273331Sbryanv 597275851Sbryanv DEF_CLONE_CMD_ARG("vxlanid", setvxlan_vni), 598275851Sbryanv DEF_CLONE_CMD_ARG("vxlanlocal", setvxlan_local), 599275851Sbryanv DEF_CLONE_CMD_ARG("vxlanremote", setvxlan_remote), 600275851Sbryanv DEF_CLONE_CMD_ARG("vxlangroup", setvxlan_group), 601275851Sbryanv DEF_CLONE_CMD_ARG("vxlanlocalport", setvxlan_local_port), 602275851Sbryanv DEF_CLONE_CMD_ARG("vxlanremoteport", setvxlan_remote_port), 603275851Sbryanv DEF_CLONE_CMD_ARG2("vxlanportrange", setvxlan_port_range), 604275851Sbryanv DEF_CLONE_CMD_ARG("vxlantimeout", setvxlan_timeout), 605275851Sbryanv DEF_CLONE_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr), 606273331Sbryanv DEF_CLONE_CMD_ARG("vxlandev", setvxlan_dev), 607275851Sbryanv DEF_CLONE_CMD_ARG("vxlanttl", setvxlan_ttl), 608275851Sbryanv DEF_CLONE_CMD("vxlanlearn", 1, setvxlan_learn), 609275851Sbryanv DEF_CLONE_CMD("-vxlanlearn", 0, setvxlan_learn), 610273331Sbryanv 611275851Sbryanv DEF_CMD_ARG("vxlanvni", setvxlan_vni), 612275851Sbryanv DEF_CMD_ARG("vxlanlocal", setvxlan_local), 613275851Sbryanv DEF_CMD_ARG("vxlanremote", setvxlan_remote), 614275851Sbryanv DEF_CMD_ARG("vxlangroup", setvxlan_group), 615275851Sbryanv DEF_CMD_ARG("vxlanlocalport", setvxlan_local_port), 616275851Sbryanv DEF_CMD_ARG("vxlanremoteport", setvxlan_remote_port), 617275851Sbryanv DEF_CMD_ARG2("vxlanportrange", setvxlan_port_range), 618275851Sbryanv DEF_CMD_ARG("vxlantimeout", setvxlan_timeout), 619275851Sbryanv DEF_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr), 620273331Sbryanv DEF_CMD_ARG("vxlandev", setvxlan_dev), 621275851Sbryanv DEF_CMD_ARG("vxlanttl", setvxlan_ttl), 622275851Sbryanv DEF_CMD("vxlanlearn", 1, setvxlan_learn), 623275851Sbryanv DEF_CMD("-vxlanlearn", 0, setvxlan_learn), 624273331Sbryanv 625275851Sbryanv DEF_CMD("vxlanflush", 0, setvxlan_flush), 626275851Sbryanv DEF_CMD("vxlanflushall", 1, setvxlan_flush), 627273331Sbryanv}; 628273331Sbryanv 629273331Sbryanvstatic struct afswtch af_vxlan = { 630273331Sbryanv .af_name = "af_vxlan", 631273331Sbryanv .af_af = AF_UNSPEC, 632273331Sbryanv .af_other_status = vxlan_status, 633273331Sbryanv}; 634273331Sbryanv 635273331Sbryanvstatic __constructor void 636273331Sbryanvvxlan_ctor(void) 637273331Sbryanv{ 638273331Sbryanv size_t i; 639273331Sbryanv 640288305Sngie for (i = 0; i < nitems(vxlan_cmds); i++) 641273331Sbryanv cmd_register(&vxlan_cmds[i]); 642273331Sbryanv af_register(&af_vxlan); 643273331Sbryanv callback_register(vxlan_cb, NULL); 644273331Sbryanv clone_setdefcallback("vxlan", vxlan_create); 645273331Sbryanv} 646