Date: Wed, 28 May 2014 03:10:17 +0000 (UTC) From: Bryan Venteicher <bryanv@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r266781 - in projects/vxlan: sbin/ifconfig sys/net Message-ID: <201405280310.s4S3AHRl088243@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: bryanv Date: Wed May 28 03:10:16 2014 New Revision: 266781 URL: http://svnweb.freebsd.org/changeset/base/266781 Log: Better IPv4 multicast support and more 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 Wed May 28 00:45:35 2014 (r266780) +++ projects/vxlan/sbin/ifconfig/ifvxlan.c Wed May 28 03:10:16 2014 (r266781) @@ -499,6 +499,25 @@ DECL_CMD_FUNC(setvxlan_maxaddr, arg, d) } static +DECL_CMD_FUNC(setvxlan_dev, arg, d) +{ + struct ifvxlancmd cmd; + + if (!vxlan_exists(s)) { + params.vxlp_with |= VXLAN_PARAM_WITH_MC_INTERFACE; + strlcpy(params.vxlp_mc_ifname, arg, + sizeof(params.vxlp_mc_ifname)); + return; + } + + bzero(&cmd, sizeof(cmd)); + strlcpy(cmd.vxlcmd_ifname, arg, sizeof(cmd.vxlcmd_ifname)); + + if (do_cmd(s, VXLAN_CMD_SET_MC_INTERFACE, &cmd, sizeof(cmd), 1) < 0) + err(1, "VXLAN_CMD_SET_MC_INTERFACE"); +} + +static DECL_CMD_FUNC(setvxlan_ttl, arg, d) { struct ifvxlancmd cmd; @@ -563,6 +582,7 @@ static struct cmd vxlan_cmds[] = { DEF_CLONE_CMD_ARG2("portrange", setvxlan_port_range), DEF_CLONE_CMD_ARG("timeout", setvxlan_timeout), DEF_CLONE_CMD_ARG("maxaddr", setvxlan_maxaddr), + DEF_CLONE_CMD_ARG("vxlandev", setvxlan_dev), DEF_CLONE_CMD_ARG("ttl", setvxlan_ttl), DEF_CLONE_CMD("learn", 1, setvxlan_learn), DEF_CLONE_CMD("-learn", 0, setvxlan_learn), @@ -576,6 +596,7 @@ static struct cmd vxlan_cmds[] = { DEF_CMD_ARG2("portrange", setvxlan_port_range), DEF_CMD_ARG("timeout", setvxlan_timeout), DEF_CMD_ARG("maxaddr", setvxlan_maxaddr), + DEF_CMD_ARG("vxlandev", setvxlan_dev), DEF_CMD_ARG("ttl", setvxlan_ttl), DEF_CMD("learn", 1, setvxlan_learn), DEF_CMD("-learn", 0, setvxlan_learn), Modified: projects/vxlan/sys/net/if_vxlan.c ============================================================================== --- projects/vxlan/sys/net/if_vxlan.c Wed May 28 00:45:35 2014 (r266780) +++ projects/vxlan/sys/net/if_vxlan.c Wed May 28 03:10:16 2014 (r266781) @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/eventhandler.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/hash.h> @@ -42,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/priv.h> #include <sys/proc.h> #include <sys/queue.h> +#include <sys/sbuf.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/sockio.h> @@ -70,13 +72,8 @@ __FBSDID("$FreeBSD$"); #include <netinet/udp_var.h> struct vxlan_softc; -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; @@ -84,7 +81,9 @@ struct vxlan_socket_mc_info { int vxlsomc_users; }; -#define VXLAN_SO_VNI_HASH_SHIFT 5 +#define VXLAN_SO_MC_MAX_GROUPS 32 + +#define VXLAN_SO_VNI_HASH_SHIFT 6 #define VXLAN_SO_VNI_HASH_SIZE (1 << VXLAN_SO_VNI_HASH_SHIFT) #define VXLAN_SO_VNI_HASH(_vni) ((_vni) % VXLAN_SO_VNI_HASH_SIZE) @@ -125,15 +124,17 @@ struct vxlan_ftable_entry { #define VXLAN_FE_IS_DYNAMIC(_fe) \ ((_fe)->vxlfe_flags & VXLAN_FE_FLAG_DYNAMIC) -#define VXLAN_SC_FTABLE_SHIFT 8 +#define VXLAN_SC_FTABLE_SHIFT 9 #define VXLAN_SC_FTABLE_SIZE (1 << VXLAN_SC_FTABLE_SHIFT) #define VXLAN_SC_FTABLE_MASK (VXLAN_SC_FTABLE_SIZE - 1) #define VXLAN_SC_FTABLE_HASH(_sc, _mac) \ (vxlan_mac_hash(_sc, _mac) % VXLAN_SC_FTABLE_SIZE) +LIST_HEAD(vxlan_ftable_head, vxlan_ftable_entry); + struct vxlan_statistics { uint32_t ftable_nospace; - uint32_t ftable_lock_upgrade; + uint32_t ftable_lock_upgrade_failed; }; struct vxlan_softc { @@ -164,22 +165,21 @@ struct vxlan_softc { /* Derived from vxl_dst_addr. */ struct vxlan_ftable_entry vxl_default_fe; -#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]; + int vxl_mc_ifindex; + struct ifnet *vxl_mc_ifp; + char vxl_mc_ifname[IFNAMSIZ]; LIST_ENTRY(vxlan_softc) vxl_entry; + LIST_ENTRY(vxlan_softc) vxl_ifdetach_list; }; #define VXLAN_RLOCK(_sc) rw_rlock(&(_sc)->vxl_lock) @@ -204,38 +204,49 @@ static int vxlan_ftable_addr_cmp(const u static void vxlan_ftable_init(struct vxlan_softc *); static void vxlan_ftable_fini(struct vxlan_softc *); static void vxlan_ftable_flush(struct vxlan_softc *, int); +static void vxlan_ftable_expire(struct vxlan_softc *); +static int vxlan_ftable_update_locked(struct vxlan_softc *, + const struct sockaddr *, const uint8_t *); +static int vxlan_ftable_update(struct vxlan_softc *, + const struct sockaddr *, const uint8_t *); +static int vxlan_ftable_sysctl_dump(SYSCTL_HANDLER_ARGS); + static struct vxlan_ftable_entry * vxlan_ftable_entry_alloc(void); +static void vxlan_ftable_entry_free(struct vxlan_ftable_entry *); static void vxlan_ftable_entry_init(struct vxlan_softc *, struct vxlan_ftable_entry *, const uint8_t *, const struct sockaddr *, uint32_t); -static void vxlan_ftable_entry_free(struct vxlan_ftable_entry *); +static void vxlan_ftable_entry_destroy(struct vxlan_softc *, + struct vxlan_ftable_entry *); +static int vxlan_ftable_entry_insert(struct vxlan_softc *, + struct vxlan_ftable_entry *); static struct vxlan_ftable_entry * vxlan_ftable_entry_lookup(struct vxlan_softc *, const uint8_t *); -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 *); -static int vxlan_ftable_update(struct vxlan_softc *, - const struct sockaddr *, const uint8_t *); -static void vxlan_ftable_expire(struct vxlan_softc *); +static void vxlan_ftable_entry_dump(struct vxlan_ftable_entry *, + struct sbuf *); static struct vxlan_socket * vxlan_socket_alloc(const union vxlan_sockaddr *); static void vxlan_socket_destroy(struct vxlan_socket *); +static void vxlan_socket_release(struct vxlan_socket *); +static struct vxlan_socket * + vxlan_socket_lookup(union vxlan_sockaddr *vxlsa); +static void vxlan_socket_insert(struct vxlan_socket *); +static int vxlan_socket_init(struct vxlan_socket *, struct ifnet *); +static int vxlan_socket_bind(struct vxlan_socket *, 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 *); -static struct vxlan_softc * - vxlan_socket_lookup_softc_locked(struct vxlan_socket *, - uint32_t); -static struct vxlan_softc * - vxlan_socket_lookup_softc(struct vxlan_socket *, uint32_t); +static void vxlan_socket_ifdetach(struct vxlan_socket *, + struct ifnet *, struct vxlan_softc_head *); static struct vxlan_socket * vxlan_socket_mc_lookup(const union vxlan_sockaddr *); +static int vxlan_sockaddr_mc_info_match( + const struct vxlan_socket_mc_info *, + const union vxlan_sockaddr *, + const union vxlan_sockaddr *, int); static int vxlan_socket_mc_join_group(struct vxlan_socket *, const union vxlan_sockaddr *, const union vxlan_sockaddr *, int *, union vxlan_sockaddr *); @@ -248,29 +259,35 @@ static int vxlan_socket_mc_add_group(str 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 struct vxlan_softc * + vxlan_socket_lookup_softc_locked(struct vxlan_socket *, + uint32_t); +static struct vxlan_softc * + vxlan_socket_lookup_softc(struct vxlan_socket *, uint32_t); +static int vxlan_socket_insert_softc(struct vxlan_socket *, + struct vxlan_softc *); +static void vxlan_socket_remove_softc(struct vxlan_socket *, + struct vxlan_softc *); + +static struct ifnet * + vxlan_multicast_if_ref(struct vxlan_softc *, int); +static void vxlan_free_multicast(struct vxlan_softc *); +static int vxlan_setup_multicast_interface(struct vxlan_softc *); +static int vxlan_setup_multicast(struct vxlan_softc *); +static int vxlan_setup_socket(struct vxlan_softc *); static int vxlan_valid_init_config(struct vxlan_softc *); +static void vxlan_init_wait(struct vxlan_softc *); +static void vxlan_init_complete(struct vxlan_softc *); static void vxlan_init(void *); static void vxlan_release(struct vxlan_softc *); +static void vxlan_teardown_wait(struct vxlan_softc *); +static void vxlan_teardown_complete(struct vxlan_softc *); +static void vxlan_teardown_locked(struct vxlan_softc *); static void vxlan_teardown(struct vxlan_softc *); +static void vxlan_ifdetach(struct vxlan_softc *, struct ifnet *, + struct vxlan_softc_head *); static void vxlan_timer(void *); -static uint16_t vxlan_pick_source_port(struct vxlan_softc *, - const struct ether_header *); -static void vxlan_encap_header(struct vxlan_softc *, struct mbuf *, - 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 *); - -static void vxlan_rcv_udp_packet(struct mbuf *, int, struct inpcb *, - const struct sockaddr *); -static int vxlan_input(struct vxlan_socket *, uint32_t, struct mbuf **, - const struct sockaddr *); static int vxlan_ctrl_get_config(struct vxlan_softc *, void *); static int vxlan_ctrl_set_vni(struct vxlan_softc *, void *); @@ -281,6 +298,7 @@ static int vxlan_ctrl_set_remote_port(st 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_mc_interface(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 *); @@ -291,6 +309,21 @@ static int vxlan_ioctl_drvspec(struct vx static int vxlan_ioctl_ifflags(struct vxlan_softc *); static int vxlan_ioctl(struct ifnet *, u_long, caddr_t); +static uint16_t vxlan_pick_source_port(struct vxlan_softc *, + const struct ether_header *); +static void vxlan_encap_header(struct vxlan_softc *, struct mbuf *, + 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 *); +static void vxlan_rcv_udp_packet(struct mbuf *, int, struct inpcb *, + const struct sockaddr *); +static int vxlan_input(struct vxlan_socket *, uint32_t, struct mbuf **, + const struct sockaddr *); + static void vxlan_set_default_config(struct vxlan_softc *); static int vxlan_set_user_config(struct vxlan_softc *, struct ifvxlanparam *); @@ -299,6 +332,7 @@ static void vxlan_clone_destroy(struct i static uint32_t vxlan_mac_hash(struct vxlan_softc *, const uint8_t *); static void vxlan_fakeaddr(struct vxlan_softc *); + static int vxlan_sockaddr_cmp(const union vxlan_sockaddr *, const struct sockaddr *); static void vxlan_sockaddr_copy(union vxlan_sockaddr *, @@ -307,6 +341,7 @@ static int vxlan_sockaddr_in_equal(const const struct sockaddr *); static void vxlan_sockaddr_in_copy(union vxlan_sockaddr *, const struct sockaddr *); +static int vxlan_sockaddr_supported(const union vxlan_sockaddr *, int); static int vxlan_sockaddr_in_any(const union vxlan_sockaddr *); static int vxlan_sockaddr_in_multicast(const union vxlan_sockaddr *); @@ -320,6 +355,11 @@ static void vxlan_sysctl_setup(struct vx static void vxlan_sysctl_destroy(struct vxlan_softc *); static int vxlan_tunable_int(struct vxlan_softc *, const char *, int); +static void vxlan_ifdetach_event(void *, struct ifnet *); +static void vxlan_load(void); +static void vxlan_unload(void); +static int vxlan_modevent(module_t, int, void *); + static const char vxlan_name[] = "vxlan"; static MALLOC_DEFINE(M_VXLAN, vxlan_name, "Virtual eXtensible LAN Interface"); @@ -327,6 +367,8 @@ static struct if_clone *vxlan_cloner; static struct mtx vxlan_list_mtx; static LIST_HEAD(, vxlan_socket) vxlan_socket_list; +static eventhandler_tag vxlan_ifdetach_event_tag; + SYSCTL_DECL(_net_link); SYSCTL_NODE(_net_link, OID_AUTO, vxlan, CTLFLAG_RW, 0, "Virtual eXtensible Local Area Network"); @@ -372,86 +414,77 @@ struct vxlan_control { static const struct vxlan_control vxlan_control_table[] = { [VXLAN_CMD_GET_CONFIG] = - { vxlan_ctrl_get_config, - sizeof(struct ifvxlancfg), + { vxlan_ctrl_get_config, sizeof(struct ifvxlancfg), VXLAN_CTRL_FLAG_COPYOUT }, [VXLAN_CMD_SET_VNI] = - { vxlan_ctrl_set_vni, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_vni, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_LOCAL_ADDR] = - { vxlan_ctrl_set_local_addr, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_local_addr, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_REMOTE_ADDR] = - { vxlan_ctrl_set_remote_addr, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_remote_addr, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_LOCAL_PORT] = - { vxlan_ctrl_set_local_port, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_local_port, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_REMOTE_PORT] = - { vxlan_ctrl_set_remote_port, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_remote_port, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_PORT_RANGE] = - { vxlan_ctrl_set_port_range, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_port_range, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_FTABLE_TIMEOUT] = - { vxlan_ctrl_set_ftable_timeout, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_ftable_timeout, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_FTABLE_MAX] = - { vxlan_ctrl_set_ftable_max, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_ftable_max, sizeof(struct ifvxlancmd), + VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, + }, + + [VXLAN_CMD_SET_MC_INTERFACE] = + { vxlan_ctrl_set_mc_interface, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_TTL] = - { vxlan_ctrl_set_ttl, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_ttl, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_SET_LEARN] = - { vxlan_ctrl_set_learn, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_set_learn, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_FTABLE_ENTRY_ADD] = - { vxlan_ctrl_ftable_entry_add, - sizeof(struct ifvxlancmd), + { 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_ftable_entry_rem, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, [VXLAN_CMD_FLUSH] = - { vxlan_ctrl_flush, - sizeof(struct ifvxlancmd), + { vxlan_ctrl_flush, sizeof(struct ifvxlancmd), VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER, }, }; @@ -463,7 +496,6 @@ vxlan_ftable_addr_cmp(const uint8_t *a, { int i, d; - /* Same MAC comparison as done in if_bridge. */ for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) d = ((int)a[i]) - ((int)b[i]); @@ -488,9 +520,10 @@ vxlan_ftable_fini(struct vxlan_softc *sc { int i; - for (i = 0; i < VXLAN_SC_FTABLE_SIZE; i++) + for (i = 0; i < VXLAN_SC_FTABLE_SIZE; i++) { KASSERT(LIST_EMPTY(&sc->vxl_ftable[i]), ("%s: vxlan %p ftable[%d] not empty", __func__, sc, i)); + } MPASS(sc->vxl_ftable_cnt == 0); free(sc->vxl_ftable, M_VXLAN); @@ -546,7 +579,6 @@ again: */ fe = vxlan_ftable_entry_lookup(sc, mac); if (fe != NULL) { - /* Accept the race if we only hold the read lock. */ fe->vxlfe_expire = time_uptime + sc->vxl_ftable_timeout; if (!VXLAN_FE_IS_DYNAMIC(fe)) @@ -556,7 +588,7 @@ again: if (!VXLAN_LOCK_WOWNED(sc) && VXLAN_LOCK_UPGRADE(sc) == 0) { VXLAN_RUNLOCK(sc); VXLAN_WLOCK(sc); - sc->vxl_stats.ftable_lock_upgrade++; + sc->vxl_stats.ftable_lock_upgrade_failed++; goto again; } vxlan_sockaddr_in_copy(&fe->vxlfe_raddr, sa); @@ -566,7 +598,7 @@ again: if (!VXLAN_LOCK_WOWNED(sc) && VXLAN_LOCK_UPGRADE(sc) == 0) { VXLAN_RUNLOCK(sc); VXLAN_WLOCK(sc); - sc->vxl_stats.ftable_lock_upgrade++; + sc->vxl_stats.ftable_lock_upgrade_failed++; goto again; } @@ -609,6 +641,46 @@ vxlan_ftable_update(struct vxlan_softc * return (error); } +static int +vxlan_ftable_sysctl_dump(SYSCTL_HANDLER_ARGS) +{ + struct sbuf sb; + struct vxlan_softc *sc; + struct vxlan_ftable_entry *fe; + size_t size; + int i, error; + + /* + * This is mostly intended for debugging during development. It is + * not practical to dump an entire large table this way. + */ + + sc = arg1; + size = PAGE_SIZE; /* Calculate later. */ + + sbuf_new(&sb, NULL, size, SBUF_FIXEDLEN); + sbuf_putc(&sb, '\n'); + + VXLAN_RLOCK(sc); + for (i = 0; i < VXLAN_SC_FTABLE_SIZE; i++) { + LIST_FOREACH(fe, &sc->vxl_ftable[i], vxlfe_hash) { + if (sbuf_error(&sb) != 0) + break; + vxlan_ftable_entry_dump(fe, &sb); + } + } + VXLAN_RUNLOCK(sc); + + if (sbuf_len(&sb) == 1) + sbuf_setpos(&sb, 0); + + sbuf_finish(&sb); + error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); + sbuf_delete(&sb); + + return (error); +} + static struct vxlan_ftable_entry * vxlan_ftable_entry_alloc(void) { @@ -647,27 +719,6 @@ vxlan_ftable_entry_destroy(struct vxlan_ vxlan_ftable_entry_free(fe); } -static struct vxlan_ftable_entry * -vxlan_ftable_entry_lookup(struct vxlan_softc *sc, const uint8_t *mac) -{ - struct vxlan_ftable_entry *fe; - uint32_t hash; - int dir; - - VXLAN_LOCK_ASSERT(sc); - hash = VXLAN_SC_FTABLE_HASH(sc, mac); - - LIST_FOREACH(fe, &sc->vxl_ftable[hash], vxlfe_hash) { - dir = vxlan_ftable_addr_cmp(fe->vxlfe_mac, mac); - if (dir == 0) - return (fe); - if (dir > 0) - break; - } - - return (NULL); -} - static int vxlan_ftable_entry_insert(struct vxlan_softc *sc, struct vxlan_ftable_entry *fe) @@ -704,6 +755,65 @@ out: return (0); } +static struct vxlan_ftable_entry * +vxlan_ftable_entry_lookup(struct vxlan_softc *sc, const uint8_t *mac) +{ + struct vxlan_ftable_entry *fe; + uint32_t hash; + int dir; + + VXLAN_LOCK_ASSERT(sc); + hash = VXLAN_SC_FTABLE_HASH(sc, mac); + + LIST_FOREACH(fe, &sc->vxl_ftable[hash], vxlfe_hash) { + dir = vxlan_ftable_addr_cmp(fe->vxlfe_mac, mac); + if (dir == 0) + return (fe); + if (dir > 0) + break; + } + + return (NULL); +} + +static void +vxlan_ftable_entry_dump(struct vxlan_ftable_entry *fe, struct sbuf *sb) +{ + char buf[64]; + const union vxlan_sockaddr *sa; + const void *addr; + int i, len, af, width; + + sa = &fe->vxlfe_raddr; + af = sa->sa.sa_family; + len = sbuf_len(sb); + + sbuf_printf(sb, "%c 0x%02X ", VXLAN_FE_IS_DYNAMIC(fe) ? 'D' : 'S', + fe->vxlfe_flags); + + for (i = 0; i < ETHER_ADDR_LEN - 1; i++) + sbuf_printf(sb, "%02X:", fe->vxlfe_mac[i]); + sbuf_printf(sb, "%02X ", fe->vxlfe_mac[i]); + + if (af == AF_INET) { + addr = &sa->in4.sin_addr; + width = INET_ADDRSTRLEN - 1; + } else { + addr = &sa->in6.sin6_addr; + width = INET6_ADDRSTRLEN - 1; + } + inet_ntop(af, addr, buf, sizeof(buf)); + sbuf_printf(sb, "%*s ", width, buf); + + sbuf_printf(sb, "%08ld", fe->vxlfe_expire); + + sbuf_putc(sb, '\n'); + + /* Truncate a partial line. */ + if (sbuf_error(sb) != 0) + sbuf_setpos(sb, len); +} + static struct vxlan_socket * vxlan_socket_alloc(const union vxlan_sockaddr *sa) { @@ -902,8 +1012,9 @@ vxlan_socket_create(struct ifnet *ifp, i goto fail; /* - * There is a small window between the bind and the insert, but - * let's not worry about that for now. + * There is a small window between the bind completing and + * inserting the socket, so that a concurrent create may fail. + * Let's not worry about that for now. */ vxlan_socket_insert(vso); *vsop = vso; @@ -916,6 +1027,21 @@ fail: return (error); } +static void +vxlan_socket_ifdetach(struct vxlan_socket *vso, struct ifnet *ifp, + struct vxlan_softc_head *list) +{ + struct vxlan_softc *sc; + int i; + + VXLAN_SO_RLOCK(vso); + for (i = 0; i < VXLAN_SO_VNI_HASH_SIZE; i++) { + LIST_FOREACH(sc, &vso->vxlso_vni_hash[i], vxl_entry) + vxlan_ifdetach(sc, ifp, list); + } + VXLAN_SO_RUNLOCK(vso); +} + static struct vxlan_socket * vxlan_socket_mc_lookup(const union vxlan_sockaddr *vxlsa) { @@ -999,7 +1125,6 @@ vxlan_socket_mc_join_group(struct vxlan_ source->in4.sin_addr = local->in4.sin_addr; *ifidx = 0; #endif - } else if (VXLAN_SOCKADDR_IS_IPV6(group)) { struct ipv6_mreq mreq; @@ -1033,7 +1158,6 @@ vxlan_socket_mc_join_group(struct vxlan_ #else *ifidx = 0; #endif - } else error = EAFNOSUPPORT; @@ -1092,8 +1216,8 @@ vxlan_socket_mc_add_group(struct vxlan_s /* * Within a socket, the same multicast group may be used by multiple - * interfaces, each with a different network identifier. A socket may - * only join each multicast group once, so keep track of the users + * interfaces, each with a different network identifier. But a socket + * may only join a multicast group once, so keep track of the users * here. */ @@ -1242,42 +1366,105 @@ vxlan_socket_remove_softc(struct vxlan_s vxlan_release(sc); } -/* - * Initialize an multicast options structure that is sufficiently populated - * for use in the respective IP output routine. This structure is typically - * stored in the socket, but our sockets may be shared among many interfaces. - * - * BMV: TODO We should convert our interface index into its pointer. - */ +static struct ifnet * +vxlan_multicast_if_ref(struct vxlan_softc *sc, int ipv4) +{ + struct ifnet *ifp; + + VXLAN_LOCK_ASSERT(sc); + + if (ipv4 && sc->vxl_im4o != NULL) + ifp = sc->vxl_im4o->imo_multicast_ifp; + else if (!ipv4 && sc->vxl_im6o != NULL) + ifp = sc->vxl_im6o->im6o_multicast_ifp; + else + ifp = NULL; + + if (ifp != NULL) + if_ref(ifp); + + return (ifp); +} + +static void +vxlan_free_multicast(struct vxlan_softc *sc) +{ + + if (sc->vxl_mc_ifp != NULL) { + if_rele(sc->vxl_mc_ifp); + sc->vxl_mc_ifp = NULL; + sc->vxl_mc_ifindex = 0; + } + + if (sc->vxl_im4o != NULL) { + free(sc->vxl_im4o, M_VXLAN); + sc->vxl_im4o = NULL; + } + + if (sc->vxl_im6o != NULL) { + free(sc->vxl_im6o, M_VXLAN); + sc->vxl_im6o = NULL; + } +} + static int -vxlan_setup_multicast_options(struct vxlan_softc *sc) +vxlan_setup_multicast_interface(struct vxlan_softc *sc) +{ + struct ifnet *ifp; + + ifp = ifunit_ref(sc->vxl_mc_ifname); + if (ifp == NULL) { + if_printf(sc->vxl_ifp, "multicast interfaces %s does " + "not exist\n", sc->vxl_mc_ifname); + return (ENOENT); + } + + if ((ifp->if_flags & IFF_MULTICAST) == 0) { + if_printf(sc->vxl_ifp, "interface %s does not support " + "multicast\n", sc->vxl_mc_ifname); + if_rele(ifp); + return (ENOTSUP); + } + + sc->vxl_mc_ifp = ifp; + sc->vxl_mc_ifindex = ifp->if_index; + + return (0); +} + +static int +vxlan_setup_multicast(struct vxlan_softc *sc) { const union vxlan_sockaddr *group; int error; group = &sc->vxl_dst_addr; + error = 0; + if (sc->vxl_mc_ifname[0] != '\0') { + error = vxlan_setup_multicast_interface(sc); + if (error) + return (error); + } + + /* + * Initialize an multicast options structure that is sufficiently + * populated for use in the respective IP output routine. This + * structure is typically stored in the socket, but our sockets + * may be shared among multiple interfaces. + */ if (VXLAN_SOCKADDR_IS_IPV4(group)) { sc->vxl_im4o = malloc(sizeof(struct ip_moptions), M_VXLAN, - M_ZERO | M_NOWAIT); - if (sc->vxl_im4o != NULL) { - sc->vxl_im4o->imo_multicast_ttl = sc->vxl_ttl; - sc->vxl_im4o->imo_multicast_vif = -1; - error = 0; - } else - error = ENOMEM; - + M_ZERO | M_WAITOK); + sc->vxl_im4o->imo_multicast_ifp = sc->vxl_mc_ifp; + sc->vxl_im4o->imo_multicast_ttl = sc->vxl_ttl; + sc->vxl_im4o->imo_multicast_vif = -1; } else if (VXLAN_SOCKADDR_IS_IPV6(group)) { sc->vxl_im6o = malloc(sizeof(struct ip6_moptions), M_VXLAN, - M_ZERO | M_NOWAIT); - if (sc->vxl_im6o != NULL) { - sc->vxl_im6o->im6o_multicast_hlim = sc->vxl_ttl; - error = 0; - } else - error = ENOMEM; - - } else - error = EAFNOSUPPORT; + M_ZERO | M_WAITOK); + sc->vxl_im6o->im6o_multicast_ifp = sc->vxl_mc_ifp; + sc->vxl_im6o->im6o_multicast_hlim = sc->vxl_ttl; + } return (error); } @@ -1288,33 +1475,41 @@ vxlan_setup_socket(struct vxlan_softc *s struct vxlan_socket *vso; struct ifnet *ifp; union vxlan_sockaddr *saddr, *daddr; - int ifidx, multicast, error; + int multicast, error; ifp = sc->vxl_ifp; saddr = &sc->vxl_src_addr; daddr = &sc->vxl_dst_addr; - ifidx = sc->vxl_ifindex; - multicast = vxlan_sockaddr_in_multicast(daddr); + multicast = vxlan_sockaddr_in_multicast(daddr); + MPASS(multicast != -1); sc->vxl_vso_mc_index = -1; /* * Try to create the socket. If that fails, attempt to use an - * existing socket that is already bound. + * existing socket. */ error = vxlan_socket_create(ifp, multicast, saddr, &vso); - if (error != 0) { + if (error) { if (multicast != 0) vso = vxlan_socket_mc_lookup(saddr); else vso = vxlan_socket_lookup(saddr); - if (vso == NULL) + + if (vso == NULL) { + if_printf(ifp, "cannot create socket (error: %d), " + "and no existing socket found\n", error); goto out; + } } if (multicast != 0) { - error = vxlan_socket_mc_add_group(vso, daddr, saddr, ifidx, - &sc->vxl_vso_mc_index); + error = vxlan_setup_multicast(sc); + if (error) + goto out; + + error = vxlan_socket_mc_add_group(vso, daddr, saddr, + sc->vxl_mc_ifindex, &sc->vxl_vso_mc_index); if (error) goto out; } @@ -1323,34 +1518,25 @@ vxlan_setup_socket(struct vxlan_softc *s error = vxlan_socket_insert_softc(vso, sc); if (error) { sc->vxl_sock = NULL; + if_printf(ifp, "network identifier %d already exists in " + "this socket\n", sc->vxl_vni); goto out; } - if (multicast != 0) { - error = vxlan_setup_multicast_options(sc); - if (error) - goto out; - } - return (0); out: if (vso != NULL) { - if (sc->vxl_sock != NULL) { - vxlan_socket_remove_softc(vso, sc); - sc->vxl_sock = NULL; - } if (sc->vxl_vso_mc_index != -1) { vxlan_socket_mc_release_group_by_idx(vso, sc->vxl_vso_mc_index); sc->vxl_vso_mc_index = -1; } + if (multicast != 0) + vxlan_free_multicast(sc); vxlan_socket_release(vso); } - if_printf(ifp, "%s: cannot create socket (%d), and no existing " - "socket found\n", __func__, error); - return (error); } @@ -1360,7 +1546,17 @@ vxlan_valid_init_config(struct vxlan_sof const char *reason; if (vxlan_check_vni(sc->vxl_vni) != 0) { - reason = "no valid virtual network identifier specified"; + reason = "invalid virtual network identifier specified"; + goto fail; + } + + if (vxlan_sockaddr_supported(&sc->vxl_src_addr, 1) == 0) { + reason = "source address type is not supported"; + goto fail; + } + + if (vxlan_sockaddr_supported(&sc->vxl_dst_addr, 0) == 0) { + reason = "destination address type is not supported"; goto fail; } @@ -1370,16 +1566,16 @@ vxlan_valid_init_config(struct vxlan_sof } if (vxlan_sockaddr_in_multicast(&sc->vxl_dst_addr) == 0 && - sc->vxl_ifindex != 0) { - reason = "can only specify the interface with a group address"; + sc->vxl_mc_ifname[0] != '\0') { + reason = "can only specify interface with a group address"; goto fail; } if (vxlan_sockaddr_in_any(&sc->vxl_src_addr) == 0) { if (VXLAN_SOCKADDR_IS_IPV4(&sc->vxl_src_addr) ^ VXLAN_SOCKADDR_IS_IPV4(&sc->vxl_dst_addr)) { - reason = "source and destination address must be " - "both IPv4 or IPv6"; + reason = "source and destination address must both " + "be either IPv4 or IPv6"; goto fail; } } @@ -1397,15 +1593,34 @@ vxlan_valid_init_config(struct vxlan_sof return (0); fail: - if_printf(sc->vxl_ifp, "cannot init interface: %s\n", reason); + if_printf(sc->vxl_ifp, "cannot initialize interface: %s\n", reason); return (EINVAL); } static void +vxlan_init_wait(struct vxlan_softc *sc) +{ + + VXLAN_LOCK_ASSERT(sc); + while (sc->vxl_flags & VXLAN_FLAG_INIT) + rw_sleep(sc, &sc->vxl_lock, 0, "vxlint", hz); +} + +static void +vxlan_init_complete(struct vxlan_softc *sc) +{ + + VXLAN_WLOCK(sc); + sc->vxl_flags &= ~VXLAN_FLAG_INIT; + wakeup(sc); + VXLAN_WUNLOCK(sc); +} + +static void vxlan_init(void *xsc) { - static const uint8_t mac[ETHER_ADDR_LEN]; + static const uint8_t empty_mac[ETHER_ADDR_LEN]; struct vxlan_softc *sc; struct ifnet *ifp; @@ -1426,37 +1641,55 @@ vxlan_init(void *xsc) if (vxlan_setup_socket(sc) != 0) goto out; - vxlan_ftable_entry_init(sc, &sc->vxl_default_fe, mac, + vxlan_ftable_entry_init(sc, &sc->vxl_default_fe, empty_mac, &sc->vxl_dst_addr.sa, VXLAN_FE_FLAG_STATIC); VXLAN_WLOCK(sc); ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->vxl_callout, vxlan_ftable_prune_period * hz, vxlan_timer, sc); - sc->vxl_flags &= ~VXLAN_FLAG_INIT; VXLAN_WUNLOCK(sc); - return; - out: - VXLAN_WLOCK(sc); - sc->vxl_flags &= ~VXLAN_FLAG_INIT; - VXLAN_WUNLOCK(sc); + vxlan_init_complete(sc); + } static void vxlan_release(struct vxlan_softc *sc) { - if (VXLAN_RELEASE(sc) != 0) { *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405280310.s4S3AHRl088243>