From owner-svn-src-projects@FreeBSD.ORG Tue May 20 14:52:57 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 72A73E8C; Tue, 20 May 2014 14:52:57 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 5E9AA2DCB; Tue, 20 May 2014 14:52:57 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s4KEqvXV094460; Tue, 20 May 2014 14:52:57 GMT (envelope-from bryanv@svn.freebsd.org) Received: (from bryanv@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s4KEqvxw094457; Tue, 20 May 2014 14:52:57 GMT (envelope-from bryanv@svn.freebsd.org) Message-Id: <201405201452.s4KEqvxw094457@svn.freebsd.org> From: Bryan Venteicher Date: Tue, 20 May 2014 14:52:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r266469 - in projects/vxlan: sbin/ifconfig sys/net X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 20 May 2014 14:52:57 -0000 Author: bryanv Date: Tue May 20 14:52:56 2014 New Revision: 266469 URL: http://svnweb.freebsd.org/changeset/base/266469 Log: Add partially baked IPv4 multicast support and lots of cleanup Modified: projects/vxlan/sbin/ifconfig/ifvxlan.c projects/vxlan/sys/net/if_vxlan.c projects/vxlan/sys/net/if_vxlan.h Modified: projects/vxlan/sbin/ifconfig/ifvxlan.c ============================================================================== --- projects/vxlan/sbin/ifconfig/ifvxlan.c Tue May 20 14:39:22 2014 (r266468) +++ projects/vxlan/sbin/ifconfig/ifvxlan.c Tue May 20 14:52:56 2014 (r266469) @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -94,7 +95,7 @@ vxlan_exists(int sock) bzero(&cfg, sizeof(cfg)); - return (do_cmd(s, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg)) != -1); + return (do_cmd(sock, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1); } static void @@ -111,6 +112,10 @@ vxlan_status(int s) vni = cfg.vxlc_vni; + /* Just report nothing if the network identity isn't set yet. */ + if (vni >= VXLAN_VNI_MAX) + return; + sin = sstosin(&cfg.vxlc_local_sa); if (getnameinfo(sintosa(sin), sin->sin_len, src, sizeof(src), NULL, 0, NI_NUMERICHOST) != 0) @@ -122,7 +127,7 @@ vxlan_status(int s) NULL, 0, NI_NUMERICHOST) != 0) dst[0] = '\0'; dport = ntohs(sin->sin_port); - group = IN_MULTICAST(sin->sin_addr.s_addr); + group = IN_MULTICAST(ntohl(sin->sin_addr.s_addr)); printf("\tvxlan %d local %s:%u %s %s:%u\n", vni, src, sport, group ? "group" : "remote", dst, dport); @@ -134,13 +139,9 @@ vxlan_status(int s) (VXLAN_PARAM_WITH_REMOTE_ADDR4 | VXLAN_PARAM_WITH_REMOTE_ADDR6) static void -vxlan_verify_params(void) +vxlan_check_params(void) { - if (params.vxlp_vni == VXLAN_VNI_MAX) - errx(1, "must specify a network identifier for vxlan create"); - if ((params.vxlp_with & _REMOTE_ADDR46) == 0) - errx(1, "must specify a remote or multicast group address"); if ((params.vxlp_with & _LOCAL_ADDR46) == _LOCAL_ADDR46) errx(1, "cannot specify both local IPv4 and IPv6 addresses"); if ((params.vxlp_with & _REMOTE_ADDR46) == _REMOTE_ADDR46) @@ -149,7 +150,7 @@ vxlan_verify_params(void) params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) || (params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR6 && params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4)) - errx(1, "cannot mix IPv4/IPv6 addresses"); + errx(1, "cannot mix IPv4 and IPv6 addresses"); } #undef _LOCAL_ADDR46 @@ -159,14 +160,14 @@ static void vxlan_cb(int s, void *arg) { - //vxlan_verify_params(); + /* BMV: Anything? */ } static void vxlan_create(int s, struct ifreq *ifr) { - vxlan_verify_params(); + vxlan_check_params(); ifr->ifr_data = (caddr_t) ¶ms; if (ioctl(s, SIOCIFCREATE2, ifr) < 0) @@ -176,22 +177,35 @@ vxlan_create(int s, struct ifreq *ifr) static DECL_CMD_FUNC(setvxlan_vni, arg, d) { + struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || val >= VXLAN_VNI_MAX) errx(1, "invalid network identifier: %s", arg); - params.vxlp_with |= VXLAN_PARAM_WITH_VNI; - params.vxlp_vni = val; + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_VNI; + params.vxlp_vni = val; + return; + } + + bzero(&cmd, sizeof(cmd)); + cmd.vxlcmd_vni = val; + + if (do_cmd(s, VXLAN_CMD_SET_VNI, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_VNI"); } static DECL_CMD_FUNC(setvxlan_local, addr, d) { + struct ifvxlancmd cmd; struct addrinfo *ai; struct sockaddr *sa; int error; + bzero(&cmd, sizeof(cmd)); + if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) errx(1, "error in parsing local address string: %s", gai_strerror(error)); @@ -203,11 +217,11 @@ DECL_CMD_FUNC(setvxlan_local, addr, d) case AF_INET: { struct in_addr addr = ((struct sockaddr_in *) sa)->sin_addr; - if (IN_MULTICAST(addr.s_addr)) + if (IN_MULTICAST(ntohl(addr.s_addr))) errx(1, "local address cannot be multicast"); - params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4; - params.vxlp_local_in4 = addr; + cmd.vxlcmd_sa.in4.sin_family = AF_INET; + cmd.vxlcmd_sa.in4.sin_addr = addr; break; } #endif @@ -218,8 +232,8 @@ DECL_CMD_FUNC(setvxlan_local, addr, d) if (IN6_IS_ADDR_MULTICAST(addr)) errx(1, "local address cannot be multicast"); - params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6; - params.vxlp_local_in6 = *addr; + cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; + cmd.vxlcmd_sa.in6.sin6_addr = *addr; break; } #endif @@ -228,15 +242,32 @@ DECL_CMD_FUNC(setvxlan_local, addr, d) } freeaddrinfo(ai); + + if (!vxlan_exists(s)) { + if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { + params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4; + params.vxlp_local_in4 = cmd.vxlcmd_sa.in4.sin_addr; + } else { + params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6; + params.vxlp_local_in6 = cmd.vxlcmd_sa.in6.sin6_addr; + } + return; + } + + if (do_cmd(s, VXLAN_CMD_SET_LOCAL_ADDR, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_LOCAL_ADDR"); } static DECL_CMD_FUNC(setvxlan_remote, addr, d) { + struct ifvxlancmd cmd; struct addrinfo *ai; struct sockaddr *sa; int error; + bzero(&cmd, sizeof(cmd)); + if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) errx(1, "error in parsing remote address string: %s", gai_strerror(error)); @@ -248,11 +279,11 @@ DECL_CMD_FUNC(setvxlan_remote, addr, d) case AF_INET: { struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; - if (IN_MULTICAST(addr.s_addr)) + if (IN_MULTICAST(ntohl(addr.s_addr))) errx(1, "remote address cannot be multicast"); - params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; - params.vxlp_remote_in4 = addr; + cmd.vxlcmd_sa.in4.sin_family = AF_INET; + cmd.vxlcmd_sa.in4.sin_addr = addr; break; } #endif @@ -263,8 +294,8 @@ DECL_CMD_FUNC(setvxlan_remote, addr, d) if (IN6_IS_ADDR_MULTICAST(addr)) errx(1, "remote address cannot be multicast"); - params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; - params.vxlp_remote_in6 = *addr; + cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; + cmd.vxlcmd_sa.in6.sin6_addr = *addr; break; } #endif @@ -273,15 +304,32 @@ DECL_CMD_FUNC(setvxlan_remote, addr, d) } freeaddrinfo(ai); + + if (!vxlan_exists(s)) { + if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { + params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; + params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr; + } else { + params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; + params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr; + } + return; + } + + if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_REMOTE_ADDR"); } static DECL_CMD_FUNC(setvxlan_group, addr, d) { + struct ifvxlancmd cmd; struct addrinfo *ai; struct sockaddr *sa; int error; + bzero(&cmd, sizeof(cmd)); + if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) errx(1, "error in parsing group address string: %s", gai_strerror(error)); @@ -293,11 +341,11 @@ DECL_CMD_FUNC(setvxlan_group, addr, d) case AF_INET: { struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; - if (!IN_MULTICAST(addr.s_addr)) + if (!IN_MULTICAST(ntohl(addr.s_addr))) errx(1, "group address must be multicast"); - params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; - params.vxlp_remote_in4 = addr; + cmd.vxlcmd_sa.in4.sin_family = AF_INET; + cmd.vxlcmd_sa.in4.sin_addr = addr; break; } #endif @@ -305,11 +353,11 @@ DECL_CMD_FUNC(setvxlan_group, addr, d) case AF_INET6: { struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; - if (IN6_IS_ADDR_MULTICAST(addr)) + if (!IN6_IS_ADDR_MULTICAST(addr)) errx(1, "group address must be multicast"); - params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; - params.vxlp_remote_in6 = *addr; + cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; + cmd.vxlcmd_sa.in6.sin6_addr = *addr; break; } #endif @@ -318,35 +366,70 @@ DECL_CMD_FUNC(setvxlan_group, addr, d) } freeaddrinfo(ai); + + if (!vxlan_exists(s)) { + if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { + params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; + params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr; + } else { + params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; + params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr; + } + return; + } + + if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_REMOTE_ADDR"); } static DECL_CMD_FUNC(setvxlan_local_port, arg, d) { + struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || val >= UINT16_MAX) errx(1, "invalid local port: %s", arg); - params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT; - params.vxlp_local_port = val; + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT; + params.vxlp_local_port = val; + return; + } + + bzero(&cmd, sizeof(cmd)); + cmd.vxlcmd_port = val; + + if (do_cmd(s, VXLAN_CMD_SET_LOCAL_PORT, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_LOCAL_PORT"); } static DECL_CMD_FUNC(setvxlan_remote_port, arg, d) { + struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || val >= UINT16_MAX) errx(1, "invalid remote port: %s", arg); - params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT; - params.vxlp_remote_port = val; + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT; + params.vxlp_remote_port = val; + return; + } + + bzero(&cmd, sizeof(cmd)); + cmd.vxlcmd_port = val; + + if (do_cmd(s, VXLAN_CMD_SET_REMOTE_PORT, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_REMOTE_PORT"); } static DECL_CMD_FUNC2(setvxlan_port_range, arg1, arg2) { + struct ifvxlancmd cmd; u_long min, max; if (get_val(arg1, &min) < 0 || min >= UINT16_MAX) @@ -356,53 +439,104 @@ DECL_CMD_FUNC2(setvxlan_port_range, arg1 if (max < min) errx(1, "invalid port range"); - params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE; - params.vxlp_min_port = min; - params.vxlp_max_port = max; + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE; + params.vxlp_min_port = min; + params.vxlp_max_port = max; + return; + } + + bzero(&cmd, sizeof(cmd)); + cmd.vxlcmd_port_min = min; + cmd.vxlcmd_port_max = max; + + if (do_cmd(s, VXLAN_CMD_SET_PORT_RANGE, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_PORT_RANGE"); } static DECL_CMD_FUNC(setvxlan_timeout, arg, d) { + struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0) errx(1, "invalid timeout value: %s", arg); - params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT; - params.vxlp_ftable_timeout = val & 0xFFFFFFFF; + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT; + params.vxlp_ftable_timeout = val & 0xFFFFFFFF; + return; + } + + bzero(&cmd, sizeof(cmd)); + cmd.vxlcmd_ftable_timeout = val & 0xFFFFFFFF; + + if (do_cmd(s, VXLAN_CMD_SET_FTABLE_TIMEOUT, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT"); } static DECL_CMD_FUNC(setvxlan_maxaddr, arg, d) { + struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0) errx(1, "invalid maxaddr value: %s", arg); - params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX; - params.vxlp_ftable_max = val & 0xFFFFFFFF; + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX; + params.vxlp_ftable_max = val & 0xFFFFFFFF; + return; + } + + bzero(&cmd, sizeof(cmd)); + cmd.vxlcmd_ftable_max = val & 0xFFFFFFFF; + + if (do_cmd(s, VXLAN_CMD_SET_FTABLE_MAX, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_FTABLE_MAX"); } static DECL_CMD_FUNC(setvxlan_ttl, arg, d) { + struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || val > 256) errx(1, "invalid TTL value: %s", arg); - params.vxlp_with |= VXLAN_PARAM_WITH_TTL; - params.vxlp_ttl = val; + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_TTL; + params.vxlp_ttl = val; + return; + } + + bzero(&cmd, sizeof(cmd)); + cmd.vxlcmd_ttl = val; + + if (do_cmd(s, VXLAN_CMD_SET_TTL, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_TTL"); } static DECL_CMD_FUNC(setvxlan_learn, arg, d) { + struct ifvxlancmd cmd; + + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_LEARN; + params.vxlp_learn = d; + return; + } - params.vxlp_with |= VXLAN_PARAM_WITH_NOLEARN; - params.vxlp_nolearn = !!d; + bzero(&cmd, sizeof(cmd)); + if (d != 0) + cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_LEARN; + + if (do_cmd(s, VXLAN_CMD_SET_LEARN, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_LEARN"); } static void @@ -433,6 +567,19 @@ static struct cmd vxlan_cmds[] = { DEF_CLONE_CMD("learn", 1, setvxlan_learn), DEF_CLONE_CMD("-learn", 0, setvxlan_learn), + DEF_CMD_ARG("vni", setvxlan_vni), + DEF_CMD_ARG("local", setvxlan_local), + DEF_CMD_ARG("remote", setvxlan_remote), + DEF_CMD_ARG("group", setvxlan_group), + DEF_CMD_ARG("localport", setvxlan_local_port), + DEF_CMD_ARG("remoteport", setvxlan_remote_port), + DEF_CMD_ARG2("portrange", setvxlan_port_range), + DEF_CMD_ARG("timeout", setvxlan_timeout), + DEF_CMD_ARG("maxaddr", setvxlan_maxaddr), + DEF_CMD_ARG("ttl", setvxlan_ttl), + DEF_CMD("learn", 1, setvxlan_learn), + DEF_CMD("-learn", 0, setvxlan_learn), + DEF_CMD("flush", 0, setvxlan_flush), DEF_CMD("flushall", 1, setvxlan_flush), }; Modified: projects/vxlan/sys/net/if_vxlan.c ============================================================================== --- projects/vxlan/sys/net/if_vxlan.c Tue May 20 14:39:22 2014 (r266468) +++ projects/vxlan/sys/net/if_vxlan.c Tue May 20 14:52:56 2014 (r266469) @@ -63,7 +63,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include #include #include @@ -73,6 +75,15 @@ struct vxlan_ftable_entry; LIST_HEAD(vxlan_ftable_head, vxlan_ftable_entry); LIST_HEAD(vxlan_softc_head, vxlan_softc); +#define VXLAN_SO_MC_MAX_GROUPS 32 + +struct vxlan_socket_mc_info { + union vxlan_sockaddr vxlsomc_saddr; + union vxlan_sockaddr vxlsomc_gaddr; + int vxlsomc_ifidx; + int vxlsomc_users; +}; + #define VXLAN_SO_VNI_HASH_SHIFT 5 #define VXLAN_SO_VNI_HASH_SIZE (1 << VXLAN_SO_VNI_HASH_SHIFT) #define VXLAN_SO_VNI_HASH(_vni) ((_vni) % VXLAN_SO_VNI_HASH_SIZE) @@ -83,8 +94,8 @@ struct vxlan_socket { u_int vxlso_refcnt; union vxlan_sockaddr vxlso_laddr; LIST_ENTRY(vxlan_socket) vxlso_entry; - /* Lookup hash from VNI to vxlan softc. */ struct vxlan_softc_head vxlso_vni_hash[VXLAN_SO_VNI_HASH_SIZE]; + struct vxlan_socket_mc_info vxlso_mc[VXLAN_SO_MC_MAX_GROUPS]; }; #define VXLAN_SO_RLOCK(_vso) rw_rlock(&(_vso)->vxlso_lock) @@ -121,8 +132,8 @@ struct vxlan_ftable_entry { (vxlan_mac_hash(_sc, _mac) % VXLAN_SC_FTABLE_SIZE) struct vxlan_statistics { + uint32_t ftable_nospace; uint32_t ftable_lock_upgrade; - }; struct vxlan_softc { @@ -130,13 +141,13 @@ struct vxlan_softc { struct vxlan_socket *vxl_sock; struct rwlock vxl_lock; volatile u_int vxl_refcnt; + uint32_t vxl_vni; union vxlan_sockaddr vxl_src_addr; union vxlan_sockaddr vxl_dst_addr; - uint32_t vxl_vni; uint32_t vxl_flags; -#define VXLAN_FLAG_INITING 0x0001 -#define VXLAN_FLAG_RELEASED 0x0002 -#define VXLAN_FLAG_NOLEARN 0x0004 +#define VXLAN_FLAG_INIT 0x0001 +#define VXLAN_FLAG_TEARDOWN 0x0002 +#define VXLAN_FLAG_LEARN 0x0004 uint32_t vxl_last_port_hash; uint16_t vxl_min_port; @@ -146,7 +157,6 @@ struct vxlan_softc { /* Lookup table from MAC address to forwarding entry. */ uint32_t vxl_ftable_cnt; uint32_t vxl_ftable_max; - uint32_t vxl_ftable_nospace; uint32_t vxl_ftable_timeout; uint32_t vxl_ftable_hash_key; struct vxlan_ftable_head *vxl_ftable; @@ -154,8 +164,19 @@ struct vxlan_softc { /* Derived from vxl_dst_addr. */ struct vxlan_ftable_entry vxl_default_fe; - struct vxlan_statistics vxl_stats; +#ifdef INET + struct ip_moptions *vxl_im4o; +#endif +#ifdef INET6 + struct ip6_moptions *vxl_im6o; +#endif + int vxl_unit; + int vxl_ifindex; + int vxl_vso_mc_index; + struct vxlan_statistics vxl_stats; + struct sysctl_oid *vxl_sysctl_node; + struct sysctl_ctx_list vxl_sysctl_ctx; struct callout vxl_callout; uint8_t vxl_hwaddr[ETHER_ADDR_LEN]; LIST_ENTRY(vxlan_softc) vxl_entry; @@ -195,7 +216,7 @@ static struct vxlan_ftable_entry * static int vxlan_ftable_entry_insert(struct vxlan_softc *, struct vxlan_ftable_entry *); static void vxlan_ftable_entry_destroy(struct vxlan_softc *, - struct vxlan_ftable_entry *fe); + struct vxlan_ftable_entry *); static int vxlan_ftable_update(struct vxlan_softc *, const struct sockaddr *, const uint8_t *); static void vxlan_ftable_expire(struct vxlan_softc *); @@ -203,7 +224,7 @@ static void vxlan_ftable_expire(struct v static struct vxlan_socket * vxlan_socket_alloc(const union vxlan_sockaddr *); static void vxlan_socket_destroy(struct vxlan_socket *); -static int vxlan_socket_create(struct ifnet *, +static int vxlan_socket_create(struct ifnet *, int, const union vxlan_sockaddr *, struct vxlan_socket **); static int vxlan_socket_insert_softc(struct vxlan_socket *, struct vxlan_softc *); @@ -213,11 +234,27 @@ static struct vxlan_softc * static struct vxlan_softc * vxlan_socket_lookup_softc(struct vxlan_socket *, uint32_t); +static struct vxlan_socket * + vxlan_socket_mc_lookup(const union vxlan_sockaddr *); +static int vxlan_socket_mc_join_group(struct vxlan_socket *, + const union vxlan_sockaddr *, const union vxlan_sockaddr *, + int *, union vxlan_sockaddr *); +static int vxlan_socket_mc_leave_group(struct vxlan_socket *, + const union vxlan_sockaddr *, + const union vxlan_sockaddr *, int); +static int vxlan_socket_mc_add_group(struct vxlan_socket *, + const union vxlan_sockaddr *, const union vxlan_sockaddr *, + int, int *); +static void vxlan_socket_mc_release_group_by_idx(struct vxlan_socket *, + int); + +static struct vxlan_socket * + vxlan_socket_lookup(union vxlan_sockaddr *vxlsa); + static int vxlan_valid_init_config(struct vxlan_softc *); static void vxlan_init(void *); -static void vxlan_stop(struct vxlan_softc *); -static void vxlan_release_socket(struct vxlan_softc *); static void vxlan_release(struct vxlan_softc *); +static void vxlan_teardown(struct vxlan_softc *); static void vxlan_timer(void *); static uint16_t vxlan_pick_source_port(struct vxlan_softc *, const struct ether_header *); @@ -225,6 +262,8 @@ static void vxlan_encap_header(struct vx int, uint16_t, uint16_t); static int vxlan_encap4(struct vxlan_softc *, const union vxlan_sockaddr *, struct mbuf *); +static int vxlan_encap6(struct vxlan_softc *, + const union vxlan_sockaddr *, struct mbuf *); static int vxlan_transmit(struct ifnet *, struct mbuf *); static void vxlan_qflush(struct ifnet *); @@ -239,13 +278,14 @@ static int vxlan_ctrl_set_local_addr(str static int vxlan_ctrl_set_remote_addr(struct vxlan_softc *, void *); static int vxlan_ctrl_set_local_port(struct vxlan_softc *, void *); static int vxlan_ctrl_set_remote_port(struct vxlan_softc *, void *); -static int vxlan_ctrl_flush(struct vxlan_softc *, void *); -static int vxlan_ctrl_ftable_timeout(struct vxlan_softc *, void *); -static int vxlan_ctrl_ftable_max(struct vxlan_softc *, void *); +static int vxlan_ctrl_set_port_range(struct vxlan_softc *, void *); +static int vxlan_ctrl_set_ftable_timeout(struct vxlan_softc *, void *); +static int vxlan_ctrl_set_ftable_max(struct vxlan_softc *, void *); +static int vxlan_ctrl_set_ttl(struct vxlan_softc *, void *); +static int vxlan_ctrl_set_learn(struct vxlan_softc *, void *); static int vxlan_ctrl_ftable_entry_add(struct vxlan_softc *, void *); static int vxlan_ctrl_ftable_entry_rem(struct vxlan_softc *, void *); -static int vxlan_ctrl_ttl(struct vxlan_softc *, void *); -static int vxlan_ctrl_learn(struct vxlan_softc *, void *); +static int vxlan_ctrl_flush(struct vxlan_softc *, void *); static int vxlan_ioctl_drvspec(struct vxlan_softc *, struct ifdrv *, int); static int vxlan_ioctl_ifflags(struct vxlan_softc *); @@ -270,21 +310,16 @@ static void vxlan_sockaddr_in_copy(union static int vxlan_sockaddr_in_any(const union vxlan_sockaddr *); static int vxlan_sockaddr_in_multicast(const union vxlan_sockaddr *); -static int vxlan_initing_or_running(struct vxlan_softc *); +static int vxlan_can_change_config(struct vxlan_softc *); static int vxlan_check_vni(uint32_t); static int vxlan_check_ttl(int); static int vxlan_check_ftable_timeout(uint32_t); static int vxlan_check_ftable_max(uint32_t); +static void vxlan_sysctl_setup(struct vxlan_softc *); +static void vxlan_sysctl_destroy(struct vxlan_softc *); static int vxlan_tunable_int(struct vxlan_softc *, const char *, int); -SYSCTL_DECL(_net_link); -SYSCTL_NODE(_net_link, OID_AUTO, vxlan, CTLFLAG_RW, 0, - "Virtual eXtensible Local Area Network"); - -static int vxlan_legacy_port = 0; -TUNABLE_INT("net.link.vxlan.legacy_port", &vxlan_legacy_port); - static const char vxlan_name[] = "vxlan"; static MALLOC_DEFINE(M_VXLAN, vxlan_name, "Virtual eXtensible LAN Interface"); @@ -292,6 +327,15 @@ static struct if_clone *vxlan_cloner; static struct mtx vxlan_list_mtx; static LIST_HEAD(, vxlan_socket) vxlan_socket_list; +SYSCTL_DECL(_net_link); +SYSCTL_NODE(_net_link, OID_AUTO, vxlan, CTLFLAG_RW, 0, + "Virtual eXtensible Local Area Network"); + +static int vxlan_legacy_port = 0; +TUNABLE_INT("net.link.vxlan.legacy_port", &vxlan_legacy_port); +static int vxlan_reuse_port = 0; +TUNABLE_INT("net.link.vxlan.reuse_port", &vxlan_reuse_port); + /* Default maximum number of addresses in the forwarding table. */ #ifndef VXLAN_FTABLE_MAX #define VXLAN_FTABLE_MAX 2000 @@ -302,6 +346,14 @@ static LIST_HEAD(, vxlan_socket) vxlan_s #define VXLAN_FTABLE_TIMEOUT (20 * 60) #endif +/* + * Maximum timeout (in seconds) of addresses learned in the forwarding + * table. + */ +#ifndef VXLAN_FTABLE_MAX_TIMEOUT +#define VXLAN_FTABLE_MAX_TIMEOUT (60 * 60 * 24) +#endif + /* Number of seconds between pruning attempts of the forwarding table. */ #ifndef VXLAN_FTABLE_PRUNE #define VXLAN_FTABLE_PRUNE (5 * 60) @@ -327,72 +379,78 @@ static const struct vxlan_control vxlan_ [VXLAN_CMD_SET_VNI] = { vxlan_ctrl_set_vni, - sizeof(struct ifvxlancfg), + sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_LOCAL_ADDR] = { vxlan_ctrl_set_local_addr, - sizeof(struct ifvxlancfg), + sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_REMOTE_ADDR] = { vxlan_ctrl_set_remote_addr, - sizeof(struct ifvxlancfg), + sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_LOCAL_PORT] = { vxlan_ctrl_set_local_port, - sizeof(struct ifvxlancfg), + sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_REMOTE_PORT] = { vxlan_ctrl_set_remote_port, - sizeof(struct ifvxlancfg), + sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, - [VXLAN_CMD_FLUSH] = - { vxlan_ctrl_flush, + [VXLAN_CMD_SET_PORT_RANGE] = + { vxlan_ctrl_set_port_range, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, - [VXLAN_CMD_FTABLE_TIMEOUT] = - { vxlan_ctrl_ftable_timeout, + [VXLAN_CMD_SET_FTABLE_TIMEOUT] = + { vxlan_ctrl_set_ftable_timeout, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, - [VXLAN_CMD_FTABLE_MAX] = - { vxlan_ctrl_ftable_max, + [VXLAN_CMD_SET_FTABLE_MAX] = + { vxlan_ctrl_set_ftable_max, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, - [VXLAN_CMD_FTABLE_ENTRY_ADD] = - { vxlan_ctrl_ftable_entry_add, + [VXLAN_CMD_SET_TTL] = + { vxlan_ctrl_set_ttl, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, - [VXLAN_CMD_FTABLE_ENTRY_REM] = - { vxlan_ctrl_ftable_entry_rem, + [VXLAN_CMD_SET_LEARN] = + { vxlan_ctrl_set_learn, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, - [VXLAN_CMD_TTL] = - { vxlan_ctrl_ttl, + [VXLAN_CMD_FTABLE_ENTRY_ADD] = + { vxlan_ctrl_ftable_entry_add, + sizeof(struct ifvxlancmd), + VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, + }, + + [VXLAN_CMD_FTABLE_ENTRY_REM] = + { vxlan_ctrl_ftable_entry_rem, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, - [VXLAN_CMD_LEARN] = - { vxlan_ctrl_learn, + [VXLAN_CMD_FLUSH] = + { vxlan_ctrl_flush, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, @@ -415,7 +473,6 @@ vxlan_ftable_addr_cmp(const uint8_t *a, static void vxlan_ftable_init(struct vxlan_softc *sc) { - static const uint8_t mac[ETHER_ADDR_LEN]; int i; sc->vxl_ftable = malloc(sizeof(struct vxlan_ftable_head) * @@ -424,9 +481,6 @@ vxlan_ftable_init(struct vxlan_softc *sc for (i = 0; i < VXLAN_SC_FTABLE_SIZE; i++) LIST_INIT(&sc->vxl_ftable[i]); sc->vxl_ftable_hash_key = arc4random(); - - vxlan_ftable_entry_init(sc, &sc->vxl_default_fe, mac, - &sc->vxl_dst_addr.sa, VXLAN_FE_FLAG_STATIC); } static void @@ -517,7 +571,7 @@ again: } if (sc->vxl_ftable_cnt >= sc->vxl_ftable_max) { - sc->vxl_ftable_nospace++; + sc->vxl_stats.ftable_nospace++; return (ENOSPC); } @@ -651,7 +705,7 @@ out: } static struct vxlan_socket * -vxlan_socket_alloc(const union vxlan_sockaddr *vxlsa) +vxlan_socket_alloc(const union vxlan_sockaddr *sa) { struct vxlan_socket *vso; int i; @@ -661,7 +715,7 @@ vxlan_socket_alloc(const union vxlan_soc refcount_init(&vso->vxlso_refcnt, 0); for (i = 0; i < VXLAN_SO_VNI_HASH_SIZE; i++) LIST_INIT(&vso->vxlso_vni_hash[i]); - vso->vxlso_laddr = *vxlsa; + vso->vxlso_laddr = *sa; return (vso); } @@ -671,11 +725,20 @@ vxlan_socket_destroy(struct vxlan_socket { struct socket *so; struct inpcb *inp; + struct vxlan_socket_mc_info *mc; int i; + for (i = 0; i < VXLAN_SO_MC_MAX_GROUPS; i++) { + mc = &vso->vxlso_mc[i]; + KASSERT(mc->vxlsomc_gaddr.sa.sa_family == AF_UNSPEC, + ("%s: socket %p mc[%d] still has address", + __func__, vso, i)); + } + for (i = 0; i < VXLAN_SO_VNI_HASH_SIZE; i++) { KASSERT(LIST_EMPTY(&vso->vxlso_vni_hash[i]), - ("%s: socket %p vni_hash[%d] not empty", __func__, vso, i)); + ("%s: socket %p vni_hash[%d] not empty", + __func__, vso, i)); } so = vso->vxlso_sock; @@ -734,57 +797,114 @@ vxlan_socket_insert(struct vxlan_socket } static int -vxlan_socket_create(struct ifnet *ifp, const union vxlan_sockaddr *vxlsa, - struct vxlan_socket **vsop) +vxlan_socket_init(struct vxlan_socket *vso, struct ifnet *ifp) { - union vxlan_sockaddr baddr; - struct vxlan_socket *vso; - struct thread *td; struct inpcb *inp; + struct thread *td; int error; td = curthread; - *vsop = NULL; - - vso = vxlan_socket_alloc(vxlsa); - if (vso == NULL) - return (ENOMEM); error = socreate(vso->vxlso_laddr.sa.sa_family, &vso->vxlso_sock, SOCK_DGRAM, IPPROTO_UDP, td->td_ucred, td); if (error) { if_printf(ifp, "cannot create socket: %d\n", error); - goto fail; + return (error); } inp = sotoinpcb(vso->vxlso_sock); - /* * XXX: Use a spare field in the inpcb to obtain the vxlan socket * in the tunneling callback. We instead should be able to pass a * context to the tunneling callback. */ - INP_WLOCK(inp); MPASS(inp->inp_pspare[0] == NULL); inp->inp_pspare[0] = vso; - INP_WUNLOCK(inp); error = udp_set_kernel_tunneling(vso->vxlso_sock, vxlan_rcv_udp_packet); if (error) { if_printf(ifp, "cannot set tunneling function: %d\n", error); - goto fail; + return (error); } - baddr = vso->vxlso_laddr; - MPASS(baddr.in4.sin_port != 0); + if (vxlan_reuse_port != 0) { + struct sockopt sopt; + int val = 1; + + bzero(&sopt, sizeof(sopt)); + sopt.sopt_dir = SOPT_SET; + sopt.sopt_level = IPPROTO_IP; + sopt.sopt_name = SO_REUSEPORT; + sopt.sopt_val = &val; + sopt.sopt_valsize = sizeof(val); + error = sosetopt(vso->vxlso_sock, &sopt); + if (error) { + if_printf(ifp, + "cannot set REUSEADDR socket opt: %d\n", error); + return (error); + } + } - error = sobind(vso->vxlso_sock, &baddr.sa, td); + return (0); +} + +static int +vxlan_socket_bind(struct vxlan_socket *vso, struct ifnet *ifp) +{ + union vxlan_sockaddr laddr; + struct thread *td; + int error; + + td = curthread; + laddr = vso->vxlso_laddr; + + error = sobind(vso->vxlso_sock, &laddr.sa, td); if (error) { if (error != EADDRINUSE) if_printf(ifp, "cannot bind socket: %d\n", error); - goto fail; + return (error); + } + + return (0); +} + +static int +vxlan_socket_create(struct ifnet *ifp, int multicast, + const union vxlan_sockaddr *saddr, struct vxlan_socket **vsop) +{ + union vxlan_sockaddr laddr; + struct vxlan_socket *vso; + int error; + + laddr = *saddr; + + /* + * If this socket will be multicast, then only the local port + * must be specified when binding. + */ + if (multicast != 0) { + if (VXLAN_SOCKADDR_IS_IPV4(&laddr)) + laddr.in4.sin_addr.s_addr = INADDR_ANY; + else + laddr.in6.sin6_addr = in6addr_any; } + vso = vxlan_socket_alloc(&laddr); + if (vso == NULL) + return (ENOMEM); + + error = vxlan_socket_init(vso, ifp); + if (error) + goto fail; + + error = vxlan_socket_bind(vso, ifp); + if (error) + goto fail; + + /* + * There is a small window between the bind and the insert, but + * let's not worry about that for now. *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***