Index: sbin/ifconfig/ifvxlan.c =================================================================== --- sbin/ifconfig/ifvxlan.c +++ sbin/ifconfig/ifvxlan.c @@ -53,6 +53,9 @@ #include "ifconfig.h" +#define satosin(sa) ((struct sockaddr_in *)(sa)) +#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) + static struct ifvxlanparam params = { .vxlp_vni = VXLAN_VNI_MAX, }; @@ -87,33 +90,53 @@ return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); } -static int -vxlan_exists(int sock) -{ - struct ifvxlancfg cfg; +static struct ifvxlancfg cfg0; - bzero(&cfg, sizeof(cfg)); +static struct ifvxlancfg * +vxlan_exists(int s) +{ - return (do_cmd(sock, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1); + bzero(&cfg0, sizeof(cfg0)); + if (do_cmd(s, VXLAN_CMD_GET_CONFIG, &cfg0, sizeof(cfg0), 0) < 0) + return (NULL); + return (&cfg0); } static void vxlan_status(int s) { - struct ifvxlancfg cfg; + struct ifvxlancfg *cfg; + + if ((cfg = vxlan_exists(s)) == NULL) + return; + + if (verbose) { + printf("\tvxlan config:"); + printf("\n\t\t%slearning portrange %d-%d ttl %d", + cfg->vxlc_learn ? "" : "no", cfg->vxlc_port_min, + cfg->vxlc_port_max, cfg->vxlc_ttl); + printf("\n\t\tftable: "); + printf("cnt %d max %d timeout %d", + cfg->vxlc_ftable_cnt, cfg->vxlc_ftable_max, + cfg->vxlc_ftable_timeout); + printf("\n"); + } +} + +static void +vxlan_status_tunnel(int s) +{ + struct ifvxlancfg *cfg; + struct sockaddr *lsa, *rsa; char src[NI_MAXHOST], dst[NI_MAXHOST]; char srcport[NI_MAXSERV], dstport[NI_MAXSERV]; - struct sockaddr *lsa, *rsa; int vni, mc, ipv6; - bzero(&cfg, sizeof(cfg)); - - if (do_cmd(s, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) < 0) + if ((cfg = vxlan_exists(s)) == NULL) return; - - vni = cfg.vxlc_vni; - lsa = &cfg.vxlc_local_sa.sa; - rsa = &cfg.vxlc_remote_sa.sa; + vni = cfg->vxlc_vni; + lsa = &cfg->vxlc_local_sa.sa; + rsa = &cfg->vxlc_remote_sa.sa; ipv6 = rsa->sa_family == AF_INET6; /* Just report nothing if the network identity isn't set yet. */ @@ -127,32 +150,15 @@ dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0) dst[0] = dstport[0] = '\0'; - if (!ipv6) { - struct sockaddr_in *sin = (struct sockaddr_in *)rsa; - mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr)); - } else { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rsa; - mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr); - } - - printf("\tvxlan vni %d", vni); - printf(" local %s%s%s:%s", ipv6 ? "[" : "", src, ipv6 ? "]" : "", - srcport); - printf(" %s %s%s%s:%s", mc ? "group" : "remote", ipv6 ? "[" : "", - dst, ipv6 ? "]" : "", dstport); - - if (verbose) { - printf("\n\t\tconfig: "); - printf("%slearning portrange %d-%d ttl %d", - cfg.vxlc_learn ? "" : "no", cfg.vxlc_port_min, - cfg.vxlc_port_max, cfg.vxlc_ttl); - printf("\n\t\tftable: "); - printf("cnt %d max %d timeout %d", - cfg.vxlc_ftable_cnt, cfg.vxlc_ftable_max, - cfg.vxlc_ftable_timeout); - } - - putchar('\n'); + if (!ipv6) + mc = IN_MULTICAST(ntohl(satosin(rsa)->sin_addr.s_addr)); + else + mc = IN6_IS_ADDR_MULTICAST(&satosin6(rsa)->sin6_addr); + printf("\ttunnel %s %s%s%s:%s --> %s%s%s:%s vni %d (%s)\n", + ipv6 ? "inet6" : "inet", + ipv6 ? "[" : "", src, ipv6 ? "]" : "", srcport, + ipv6 ? "[" : "", dst, ipv6 ? "]" : "", dstport, vni, + mc ? "multicast" : "unicast"); } #define _LOCAL_ADDR46 \ @@ -222,7 +228,6 @@ { struct ifvxlancmd cmd; struct addrinfo *ai; - struct sockaddr *sa; int error; bzero(&cmd, sizeof(cmd)); @@ -231,32 +236,22 @@ errx(1, "error in parsing local address string: %s", gai_strerror(error)); - sa = ai->ai_addr; - switch (ai->ai_family) { #ifdef INET - case AF_INET: { - struct in_addr addr = ((struct sockaddr_in *) sa)->sin_addr; - - if (IN_MULTICAST(ntohl(addr.s_addr))) + case AF_INET: + if (IN_MULTICAST(ntohl(satosin(ai->ai_addr)->sin_addr.s_addr))) errx(1, "local address cannot be multicast"); - cmd.vxlcmd_sa.in4.sin_family = AF_INET; - cmd.vxlcmd_sa.in4.sin_addr = addr; + cmd.vxlcmd_sa.in4 = *satosin(ai->ai_addr); break; - } #endif #ifdef INET6 - case AF_INET6: { - struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; - - if (IN6_IS_ADDR_MULTICAST(addr)) + case AF_INET6: + if (IN6_IS_ADDR_MULTICAST(&satosin6(ai->ai_addr)->sin6_addr)) errx(1, "local address cannot be multicast"); - cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; - cmd.vxlcmd_sa.in6.sin6_addr = *addr; + cmd.vxlcmd_sa.in6 = *satosin6(ai->ai_addr); break; - } #endif default: errx(1, "local address %s not supported", addr); @@ -267,10 +262,14 @@ 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; + params.vxlp_local.in4.sin_addr = + 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; + params.vxlp_local.in6.sin6_addr = + cmd.vxlcmd_sa.in6.sin6_addr; + params.vxlp_local.in6.sin6_scope_id = + cmd.vxlcmd_sa.in6.sin6_scope_id; } return; } @@ -284,7 +283,6 @@ { struct ifvxlancmd cmd; struct addrinfo *ai; - struct sockaddr *sa; int error; bzero(&cmd, sizeof(cmd)); @@ -293,32 +291,22 @@ errx(1, "error in parsing remote address string: %s", gai_strerror(error)); - sa = ai->ai_addr; - switch (ai->ai_family) { #ifdef INET - case AF_INET: { - struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; - - if (IN_MULTICAST(ntohl(addr.s_addr))) + case AF_INET: + if (IN_MULTICAST(ntohl(satosin(ai->ai_addr)->sin_addr.s_addr))) errx(1, "remote address cannot be multicast"); - cmd.vxlcmd_sa.in4.sin_family = AF_INET; - cmd.vxlcmd_sa.in4.sin_addr = addr; + cmd.vxlcmd_sa.in4 = *satosin(ai->ai_addr); break; - } #endif #ifdef INET6 - case AF_INET6: { - struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; - - if (IN6_IS_ADDR_MULTICAST(addr)) + case AF_INET6: + if (IN6_IS_ADDR_MULTICAST(&satosin6(ai->ai_addr)->sin6_addr)) errx(1, "remote address cannot be multicast"); - cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; - cmd.vxlcmd_sa.in6.sin6_addr = *addr; + cmd.vxlcmd_sa.in6 = *satosin6(ai->ai_addr); break; - } #endif default: errx(1, "remote address %s not supported", addr); @@ -329,10 +317,14 @@ 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; + params.vxlp_remote.in4.sin_addr = + 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; + params.vxlp_remote.in6.sin6_addr = + cmd.vxlcmd_sa.in6.sin6_addr; + params.vxlp_remote.in6.sin6_scope_id = + cmd.vxlcmd_sa.in6.sin6_scope_id; } return; } @@ -346,7 +338,6 @@ { struct ifvxlancmd cmd; struct addrinfo *ai; - struct sockaddr *sa; int error; bzero(&cmd, sizeof(cmd)); @@ -355,32 +346,22 @@ errx(1, "error in parsing group address string: %s", gai_strerror(error)); - sa = ai->ai_addr; - switch (ai->ai_family) { #ifdef INET - case AF_INET: { - struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; - - if (!IN_MULTICAST(ntohl(addr.s_addr))) + case AF_INET: + if (!IN_MULTICAST(ntohl(satosin(ai->ai_addr)->sin_addr.s_addr))) errx(1, "group address must be multicast"); - cmd.vxlcmd_sa.in4.sin_family = AF_INET; - cmd.vxlcmd_sa.in4.sin_addr = addr; + cmd.vxlcmd_sa.in4 = *satosin(ai->ai_addr); break; - } #endif #ifdef INET6 - case AF_INET6: { - struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; - - if (!IN6_IS_ADDR_MULTICAST(addr)) + case AF_INET6: + if (!IN6_IS_ADDR_MULTICAST(&satosin6(ai->ai_addr)->sin6_addr)) errx(1, "group address must be multicast"); - cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; - cmd.vxlcmd_sa.in6.sin6_addr = *addr; + cmd.vxlcmd_sa.in6 = *satosin6(ai->ai_addr); break; - } #endif default: errx(1, "group address %s not supported", addr); @@ -391,10 +372,14 @@ 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; + params.vxlp_remote.in4.sin_addr = + 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; + params.vxlp_remote.in6.sin6_addr = + cmd.vxlcmd_sa.in6.sin6_addr; + params.vxlp_remote.in6.sin6_scope_id = + cmd.vxlcmd_sa.in6.sin6_scope_id; } return; } @@ -414,7 +399,8 @@ if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT; - params.vxlp_local_port = val; + /* Use sin_port for AF_INET and AF_INET6. */ + params.vxlp_local.in4.sin_port = val; return; } @@ -436,7 +422,8 @@ if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT; - params.vxlp_remote_port = val; + /* Use sin_port for AF_INET and AF_INET6. */ + params.vxlp_remote.in4.sin_port = val; return; } @@ -595,6 +582,7 @@ static struct cmd vxlan_cmds[] = { DEF_CLONE_CMD_ARG("vxlanid", setvxlan_vni), + DEF_CLONE_CMD_ARG("vni", setvxlan_vni), DEF_CLONE_CMD_ARG("vxlanlocal", setvxlan_local), DEF_CLONE_CMD_ARG("vxlanremote", setvxlan_remote), DEF_CLONE_CMD_ARG("vxlangroup", setvxlan_group), @@ -608,7 +596,8 @@ DEF_CLONE_CMD("vxlanlearn", 1, setvxlan_learn), DEF_CLONE_CMD("-vxlanlearn", 0, setvxlan_learn), - DEF_CMD_ARG("vxlanvni", setvxlan_vni), + DEF_CMD_ARG("vni", setvxlan_vni), + DEF_CMD_ARG("vxlanid", setvxlan_vni), DEF_CMD_ARG("vxlanlocal", setvxlan_local), DEF_CMD_ARG("vxlanremote", setvxlan_remote), DEF_CMD_ARG("vxlangroup", setvxlan_group), @@ -630,6 +619,7 @@ .af_name = "af_vxlan", .af_af = AF_UNSPEC, .af_other_status = vxlan_status, + .af_status_tunnel = vxlan_status_tunnel, }; static __constructor void Index: sys/net/if_vxlan.h =================================================================== --- sys/net/if_vxlan.h +++ sys/net/if_vxlan.h @@ -54,6 +54,12 @@ #define VXLAN_PORT 4789 #define VXLAN_LEGACY_PORT 8472 +union vxlan_sockaddr { + struct sockaddr sa; + struct sockaddr_in in4; + struct sockaddr_in6 in6; +}; + struct ifvxlanparam { uint64_t vxlp_with; @@ -72,12 +78,8 @@ #define VXLAN_PARAM_WITH_LEARN 0x1000 uint32_t vxlp_vni; - struct in_addr vxlp_local_in4; - struct in6_addr vxlp_local_in6; - struct in_addr vxlp_remote_in4; - struct in6_addr vxlp_remote_in6; - uint16_t vxlp_local_port; - uint16_t vxlp_remote_port; + union vxlan_sockaddr vxlp_local; + union vxlan_sockaddr vxlp_remote; uint16_t vxlp_min_port; uint16_t vxlp_max_port; char vxlp_mc_ifname[IFNAMSIZ]; @@ -87,12 +89,6 @@ uint8_t vxlp_learn; }; -union vxlan_sockaddr { - struct sockaddr sa; - struct sockaddr_in in4; - struct sockaddr_in6 in6; -}; - #define VXLAN_SOCKADDR_IS_IPV4(_vxsin) ((_vxsin)->sa.sa_family == AF_INET) #define VXLAN_SOCKADDR_IS_IPV6(_vxsin) ((_vxsin)->sa.sa_family == AF_INET6) #define VXLAN_SOCKADDR_IS_IPV46(_vxsin) \ @@ -126,6 +122,8 @@ uint16_t vxlc_port_max; uint8_t vxlc_learn; uint8_t vxlc_ttl; + uint64_t vxlc_stats_ftable_nospace; + uint64_t vxlc_stats_ftable_lock_upgrade_failed; }; struct ifvxlancmd { Index: sys/net/if_vxlan.c =================================================================== --- sys/net/if_vxlan.c +++ sys/net/if_vxlan.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,7 @@ #include #include #include +#include #include #include @@ -68,6 +70,7 @@ #include #include #include +#include #include #include @@ -132,8 +135,8 @@ LIST_HEAD(vxlan_ftable_head, vxlan_ftable_entry); struct vxlan_statistics { - uint32_t ftable_nospace; - uint32_t ftable_lock_upgrade_failed; + counter_u64_t ftable_nospace; + counter_u64_t ftable_lock_upgrade_failed; }; struct vxlan_softc { @@ -217,7 +220,7 @@ struct rm_priotracker *); static int vxlan_ftable_update(struct vxlan_softc *, const struct sockaddr *, const uint8_t *); -static int vxlan_ftable_sysctl_dump(SYSCTL_HANDLER_ARGS); +static char * vxlan_ftable_dump(struct vxlan_softc *); static struct vxlan_ftable_entry * vxlan_ftable_entry_alloc(void); @@ -361,32 +364,40 @@ 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); - 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 void vnet_vxlan_init(const void *); +static void vnet_vxlan_uninit(const void *); static const char vxlan_name[] = "vxlan"; static MALLOC_DEFINE(M_VXLAN, vxlan_name, "Virtual eXtensible LAN Interface"); -static struct if_clone *vxlan_cloner; -static struct mtx vxlan_list_mtx; -static LIST_HEAD(, vxlan_socket) vxlan_socket_list; +static VNET_DEFINE(struct if_clone *, vxlan_cloner); +#define V_vxlan_cloner VNET(vxlan_cloner) +static VNET_DEFINE(struct mtx, vxlan_list_mtx); +#define V_vxlan_list_mtx VNET(vxlan_list_mtx) +#define VXLAN_LIST_LOCK(x) mtx_lock(&V_vxlan_list_mtx) +#define VXLAN_LIST_UNLOCK(x) mtx_unlock(&V_vxlan_list_mtx) +#define VXLAN_LIST_LOCK_INIT(x) mtx_init(&V_vxlan_list_mtx, "vxlan list", \ + NULL, MTX_DEF) +#define VXLAN_LIST_LOCK_DESTROY(x) mtx_destroy(&V_vxlan_list_mtx) +static VNET_DEFINE(LIST_HEAD(, vxlan_socket), vxlan_socket_list); +#define V_vxlan_socket_list VNET(vxlan_socket_list) -static eventhandler_tag vxlan_ifdetach_event_tag; +static VNET_DEFINE(eventhandler_tag, vxlan_ifdetach_event_tag); +#define V_vxlan_ifdetach_event_tag VNET(vxlan_ifdetach_event_tag) 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); +static VNET_DEFINE(int, vxlan_legacy_port); +#define V_vxlan_legacy_port VNET(vxlan_legacy_port) +static VNET_DEFINE(int, vxlan_reuse_port); +#define V_vxlan_reuse_port VNET(vxlan_reuse_port) +SYSCTL_INT(_net_link_vxlan, OID_AUTO, legacy_port, CTLFLAG_RW | CTLFLAG_VNET, + &VNET_NAME(vxlan_legacy_port), 0, ""); +SYSCTL_INT(_net_link_vxlan, OID_AUTO, reuse_port, CTLFLAG_RW | CTLFLAG_VNET, + &VNET_NAME(vxlan_reuse_port), 0, ""); /* Default maximum number of addresses in the forwarding table. */ #ifndef VXLAN_FTABLE_MAX @@ -411,7 +422,8 @@ #define VXLAN_FTABLE_PRUNE (5 * 60) #endif -static int vxlan_ftable_prune_period = VXLAN_FTABLE_PRUNE; +static VNET_DEFINE(int, vxlan_ftable_prune_period) = VXLAN_FTABLE_PRUNE; +#define V_vxlan_ftable_prune_period VNET(vxlan_ftable_prune_period) struct vxlan_control { int (*vxlc_func)(struct vxlan_softc *, void *); @@ -523,6 +535,8 @@ for (i = 0; i < VXLAN_SC_FTABLE_SIZE; i++) LIST_INIT(&sc->vxl_ftable[i]); sc->vxl_ftable_hash_key = arc4random(); + sc->vxl_stats.ftable_nospace = counter_u64_alloc(M_WAITOK); + sc->vxl_stats.ftable_lock_upgrade_failed = counter_u64_alloc(M_WAITOK); } static void @@ -538,6 +552,10 @@ free(sc->vxl_ftable, M_VXLAN); sc->vxl_ftable = NULL; + counter_u64_free(sc->vxl_stats.ftable_nospace); + sc->vxl_stats.ftable_nospace = NULL; + counter_u64_free(sc->vxl_stats.ftable_lock_upgrade_failed); + sc->vxl_stats.ftable_lock_upgrade_failed = NULL; } static void @@ -597,7 +615,8 @@ if (!VXLAN_LOCK_WOWNED(sc)) { VXLAN_RUNLOCK(sc, tracker); VXLAN_WLOCK(sc); - sc->vxl_stats.ftable_lock_upgrade_failed++; + counter_u64_add( + sc->vxl_stats.ftable_lock_upgrade_failed, 1); goto again; } vxlan_sockaddr_in_copy(&fe->vxlfe_raddr, sa); @@ -607,12 +626,12 @@ if (!VXLAN_LOCK_WOWNED(sc)) { VXLAN_RUNLOCK(sc, tracker); VXLAN_WLOCK(sc); - sc->vxl_stats.ftable_lock_upgrade_failed++; + counter_u64_add(sc->vxl_stats.ftable_lock_upgrade_failed, 1); goto again; } if (sc->vxl_ftable_cnt >= sc->vxl_ftable_max) { - sc->vxl_stats.ftable_nospace++; + counter_u64_add(sc->vxl_stats.ftable_nospace, 1); return (ENOSPC); } @@ -621,11 +640,20 @@ return (ENOMEM); /* - * The source port may be randomly select by the remove host, so + * The source port may be randomly select by the remote host, so * use the port of the default destination address. */ vxlan_sockaddr_copy(&vxlsa, sa); - vxlsa.in4.sin_port = sc->vxl_dst_addr.in4.sin_port; + switch (vxlsa.sa.sa_family) { + case AF_INET: + vxlsa.in4.sin_port = sc->vxl_dst_addr.in4.sin_port; + break; + case AF_INET6: + vxlsa.in6.sin6_port = sc->vxl_dst_addr.in6.sin6_port; + break; + default: + return (EINVAL); + } vxlan_ftable_entry_init(sc, fe, mac, &vxlsa.sa, VXLAN_FE_FLAG_DYNAMIC); @@ -651,26 +679,21 @@ return (error); } -static int -vxlan_ftable_sysctl_dump(SYSCTL_HANDLER_ARGS) +static char * +vxlan_ftable_dump(struct vxlan_softc *sc) { struct rm_priotracker tracker; struct sbuf sb; - struct vxlan_softc *sc; struct vxlan_ftable_entry *fe; - size_t size; - int i, error; + int i; + char *str; /* * 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'); + sbuf_new(&sb, NULL, PAGE_SIZE, SBUF_FIXEDLEN); VXLAN_RLOCK(sc, &tracker); for (i = 0; i < VXLAN_SC_FTABLE_SIZE; i++) { @@ -682,14 +705,11 @@ } VXLAN_RUNLOCK(sc, &tracker); - if (sbuf_len(&sb) == 1) - sbuf_setpos(&sb, 0); - sbuf_finish(&sb); - error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); + str = strdup(sbuf_data(&sb), M_VXLAN); sbuf_delete(&sb); - return (error); + return (str); } static struct vxlan_ftable_entry * @@ -877,11 +897,11 @@ { int destroy; - mtx_lock(&vxlan_list_mtx); + VXLAN_LIST_LOCK(); destroy = VXLAN_SO_RELEASE(vso); if (destroy != 0) LIST_REMOVE(vso, vxlso_entry); - mtx_unlock(&vxlan_list_mtx); + VXLAN_LIST_UNLOCK(); if (destroy != 0) vxlan_socket_destroy(vso); @@ -892,14 +912,14 @@ { struct vxlan_socket *vso; - mtx_lock(&vxlan_list_mtx); - LIST_FOREACH(vso, &vxlan_socket_list, vxlso_entry) { + VXLAN_LIST_LOCK(); + LIST_FOREACH(vso, &V_vxlan_socket_list, vxlso_entry) { if (vxlan_sockaddr_cmp(&vso->vxlso_laddr, &vxlsa->sa) == 0) { VXLAN_SO_ACQUIRE(vso); break; } } - mtx_unlock(&vxlan_list_mtx); + VXLAN_LIST_UNLOCK(); return (vso); } @@ -908,10 +928,10 @@ vxlan_socket_insert(struct vxlan_socket *vso) { - mtx_lock(&vxlan_list_mtx); + VXLAN_LIST_LOCK(); VXLAN_SO_ACQUIRE(vso); - LIST_INSERT_HEAD(&vxlan_socket_list, vso, vxlso_entry); - mtx_unlock(&vxlan_list_mtx); + LIST_INSERT_HEAD(&V_vxlan_socket_list, vso, vxlso_entry); + VXLAN_LIST_UNLOCK(); } static int @@ -936,7 +956,7 @@ return (error); } - if (vxlan_reuse_port != 0) { + if (V_vxlan_reuse_port != 0) { struct sockopt sopt; int val = 1; @@ -1651,7 +1671,7 @@ VXLAN_WLOCK(sc); ifp->if_drv_flags |= IFF_DRV_RUNNING; - callout_reset(&sc->vxl_callout, vxlan_ftable_prune_period * hz, + callout_reset(&sc->vxl_callout, V_vxlan_ftable_prune_period * hz, vxlan_timer, sc); VXLAN_WUNLOCK(sc); @@ -1778,7 +1798,9 @@ VXLAN_LOCK_WASSERT(sc); vxlan_ftable_expire(sc); - callout_schedule(&sc->vxl_callout, vxlan_ftable_prune_period * hz); + CURVNET_SET(sc->vxl_ifp->if_vnet); + callout_schedule(&sc->vxl_callout, V_vxlan_ftable_prune_period * hz); + CURVNET_RESTORE(); } static int @@ -1814,6 +1836,12 @@ sizeof(union vxlan_sockaddr)); memcpy(&cfg->vxlc_remote_sa, &sc->vxl_dst_addr, sizeof(union vxlan_sockaddr)); +#ifdef INET6 + if (cfg->vxlc_local_sa.sa.sa_family == AF_INET6) + sa6_recoverscope(&cfg->vxlc_local_sa.in6); + if (cfg->vxlc_remote_sa.sa.sa_family == AF_INET6) + sa6_recoverscope(&cfg->vxlc_remote_sa.in6); +#endif /* INET6 */ cfg->vxlc_mc_ifindex = sc->vxl_mc_ifindex; cfg->vxlc_ftable_cnt = sc->vxl_ftable_cnt; cfg->vxlc_ftable_max = sc->vxl_ftable_max; @@ -1822,6 +1850,10 @@ cfg->vxlc_port_max = sc->vxl_max_port; cfg->vxlc_learn = (sc->vxl_flags & VXLAN_FLAG_LEARN) != 0; cfg->vxlc_ttl = sc->vxl_ttl; + cfg->vxlc_stats_ftable_nospace = + counter_u64_fetch(sc->vxl_stats.ftable_nospace); + cfg->vxlc_stats_ftable_lock_upgrade_failed = + counter_u64_fetch(sc->vxl_stats.ftable_lock_upgrade_failed); VXLAN_RUNLOCK(sc, &tracker); return (0); @@ -1863,6 +1895,12 @@ return (EINVAL); if (vxlan_sockaddr_in_multicast(vxlsa) != 0) return (EINVAL); +#ifdef INET6 + if (vxlsa->sa.sa_family == AF_INET6 && + IN6_IS_SCOPE_LINKLOCAL(&satosin6(&vxlsa->sa)->sin6_addr) && + satosin6(&vxlsa->sa)->sin6_scope_id != 0) + sa6_embedscope(&vxlsa->in6, V_ip6_use_defzone); +#endif /* INET6 */ VXLAN_WLOCK(sc); if (vxlan_can_change_config(sc)) { @@ -1887,6 +1925,12 @@ if (!VXLAN_SOCKADDR_IS_IPV46(vxlsa)) return (EINVAL); +#ifdef INET6 + if (vxlsa->sa.sa_family == AF_INET6 && + IN6_IS_SCOPE_LINKLOCAL(&satosin6(&vxlsa->sa)->sin6_addr) && + satosin6(&vxlsa->sa)->sin6_scope_id != 0) + sa6_embedscope(&vxlsa->in6, V_ip6_use_defzone); +#endif /* INET6 */ VXLAN_WLOCK(sc); if (vxlan_can_change_config(sc)) { @@ -2197,9 +2241,11 @@ vxlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct vxlan_softc *sc; + struct ifvxlancmd vxlancmd; + struct sockaddr *src, *dst; struct ifreq *ifr; struct ifdrv *ifd; - int error; + int error, salen, safamily; sc = ifp->if_softc; ifr = (struct ifreq *) data; @@ -2211,6 +2257,30 @@ error = 0; break; + case SIOCSIFPHYADDR: + src = (struct sockaddr *) + &(((struct in_aliasreq *)data)->ifra_addr); + dst = (struct sockaddr *) + &(((struct in_aliasreq *)data)->ifra_dstaddr); + safamily = AF_INET; + salen = sizeof(struct sockaddr_in); + break; + case SIOCSIFPHYADDR_IN6: + src = (struct sockaddr *) + &(((struct in6_aliasreq *)data)->ifra_addr); + dst = (struct sockaddr *) + &(((struct in6_aliasreq *)data)->ifra_dstaddr); + safamily = AF_INET6; + salen = sizeof(struct sockaddr_in6); + break; + + case SIOCDIFPHYADDR: + /* VXLAN_VNI_MAX means no address configured. */ + bzero(&vxlancmd, sizeof(vxlancmd)); + vxlancmd.vxlcmd_vni = VXLAN_VNI_MAX; + error = vxlan_ctrl_set_vni(sc, &vxlancmd); + break; + case SIOCGDRVSPEC: case SIOCSDRVSPEC: error = vxlan_ioctl_drvspec(sc, ifd, cmd == SIOCGDRVSPEC); @@ -2224,6 +2294,21 @@ break; } + switch (cmd) { + case SIOCSIFPHYADDR: + case SIOCSIFPHYADDR_IN6: + bzero(&vxlancmd, sizeof(vxlancmd)); + bcopy(src, &vxlancmd.vxlcmd_sa.sa, salen); + vxlancmd.vxlcmd_sa.sa.sa_family = safamily; + if ((error = vxlan_ctrl_set_local_addr(sc, &vxlancmd)) != 0) + break; + bcopy(dst, &vxlancmd.vxlcmd_sa.sa, salen); + vxlancmd.vxlcmd_sa.sa.sa_family = safamily; + if ((error = vxlan_ctrl_set_remote_addr(sc, &vxlancmd)) != 0) + break; + break; + } + return (error); } @@ -2548,7 +2633,7 @@ sc->vxl_vni = VXLAN_VNI_MAX; sc->vxl_ttl = IPDEFTTL; - if (!vxlan_tunable_int(sc, "legacy_port", vxlan_legacy_port)) { + if (V_vxlan_legacy_port == 0) { sc->vxl_src_addr.in4.sin_port = htons(VXLAN_PORT); sc->vxl_dst_addr.in4.sin_port = htons(VXLAN_PORT); } else { @@ -2587,27 +2672,55 @@ if (vxlp->vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR4) { sc->vxl_src_addr.in4.sin_len = sizeof(struct sockaddr_in); sc->vxl_src_addr.in4.sin_family = AF_INET; - sc->vxl_src_addr.in4.sin_addr = vxlp->vxlp_local_in4; + sc->vxl_src_addr.in4.sin_addr = vxlp->vxlp_local.in4.sin_addr; } else if (vxlp->vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR6) { sc->vxl_src_addr.in6.sin6_len = sizeof(struct sockaddr_in6); sc->vxl_src_addr.in6.sin6_family = AF_INET6; - sc->vxl_src_addr.in6.sin6_addr = vxlp->vxlp_local_in6; + sc->vxl_src_addr.in6.sin6_addr = vxlp->vxlp_local.in6.sin6_addr; + sc->vxl_src_addr.in6.sin6_scope_id = + vxlp->vxlp_local.in6.sin6_scope_id; + sa6_embedscope(&sc->vxl_src_addr.in6, V_ip6_use_defzone); } if (vxlp->vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4) { sc->vxl_dst_addr.in4.sin_len = sizeof(struct sockaddr_in); sc->vxl_dst_addr.in4.sin_family = AF_INET; - sc->vxl_dst_addr.in4.sin_addr = vxlp->vxlp_remote_in4; + sc->vxl_dst_addr.in4.sin_addr = vxlp->vxlp_remote.in4.sin_addr; } else if (vxlp->vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) { sc->vxl_dst_addr.in6.sin6_len = sizeof(struct sockaddr_in6); sc->vxl_dst_addr.in6.sin6_family = AF_INET6; - sc->vxl_dst_addr.in6.sin6_addr = vxlp->vxlp_remote_in6; + sc->vxl_dst_addr.in6.sin6_addr = + vxlp->vxlp_remote.in6.sin6_addr; + sc->vxl_dst_addr.in6.sin6_scope_id = + vxlp->vxlp_remote.in6.sin6_scope_id; + sa6_embedscope(&sc->vxl_dst_addr.in6, V_ip6_use_defzone); } if (vxlp->vxlp_with & VXLAN_PARAM_WITH_LOCAL_PORT) - sc->vxl_src_addr.in4.sin_port = htons(vxlp->vxlp_local_port); - if (vxlp->vxlp_with & VXLAN_PARAM_WITH_REMOTE_PORT) - sc->vxl_dst_addr.in4.sin_port = htons(vxlp->vxlp_remote_port); + /* Use vxlp_local.in4.sin_port for AF_INET and AF_INET6. */ + switch (sc->vxl_src_addr.sa.sa_family) { + case AF_INET: + sc->vxl_src_addr.in4.sin_port = + htons(vxlp->vxlp_local.in4.sin_port); + break; + case AF_INET6: + sc->vxl_src_addr.in6.sin6_port = + htons(vxlp->vxlp_local.in4.sin_port); + break; + } + if (vxlp->vxlp_with & VXLAN_PARAM_WITH_REMOTE_PORT) { + /* Use vxlp_local.in4.sin_port for AF_INET and AF_INET6. */ + switch (sc->vxl_dst_addr.sa.sa_family) { + case AF_INET: + sc->vxl_dst_addr.in4.sin_port = + htons(vxlp->vxlp_remote.in4.sin_port); + break; + case AF_INET6: + sc->vxl_dst_addr.in6.sin6_port = + htons(vxlp->vxlp_remote.in4.sin_port); + break; + } + } if (vxlp->vxlp_with & VXLAN_PARAM_WITH_PORT_RANGE) { if (vxlp->vxlp_min_port <= vxlp->vxlp_max_port) { @@ -2676,8 +2789,6 @@ sc->vxl_port_hash_key = arc4random(); vxlan_ftable_init(sc); - vxlan_sysctl_setup(sc); - ifp->if_softc = sc; if_initname(ifp, vxlan_name, unit); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; @@ -2715,7 +2826,6 @@ vxlan_ftable_fini(sc); - vxlan_sysctl_destroy(sc); rm_destroy(&sc->vxl_lock); free(sc, M_VXLAN); } @@ -2918,7 +3028,7 @@ vxlan_check_vni(uint32_t vni) { - return (vni >= VXLAN_VNI_MAX); + return (vni > VXLAN_VNI_MAX); } static int @@ -2943,70 +3053,6 @@ } static void -vxlan_sysctl_setup(struct vxlan_softc *sc) -{ - struct sysctl_ctx_list *ctx; - struct sysctl_oid *node; - struct vxlan_statistics *stats; - char namebuf[8]; - - ctx = &sc->vxl_sysctl_ctx; - stats = &sc->vxl_stats; - snprintf(namebuf, sizeof(namebuf), "%d", sc->vxl_unit); - - sysctl_ctx_init(ctx); - sc->vxl_sysctl_node = SYSCTL_ADD_NODE(ctx, - SYSCTL_STATIC_CHILDREN(_net_link_vxlan), OID_AUTO, namebuf, - CTLFLAG_RD, NULL, ""); - - node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sc->vxl_sysctl_node), - OID_AUTO, "ftable", CTLFLAG_RD, NULL, ""); - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "count", - CTLFLAG_RD, &sc->vxl_ftable_cnt, 0, - "Number of entries in fowarding table"); - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "max", - CTLFLAG_RD, &sc->vxl_ftable_max, 0, - "Maximum number of entries allowed in fowarding table"); - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "timeout", - CTLFLAG_RD, &sc->vxl_ftable_timeout, 0, - "Number of seconds between prunes of the forwarding table"); - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "dump", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE | CTLFLAG_SKIP, - sc, 0, vxlan_ftable_sysctl_dump, "A", - "Dump the forwarding table entries"); - - node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sc->vxl_sysctl_node), - OID_AUTO, "stats", CTLFLAG_RD, NULL, ""); - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(node), OID_AUTO, - "ftable_nospace", CTLFLAG_RD, &stats->ftable_nospace, 0, - "Fowarding table reached maximum entries"); - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(node), OID_AUTO, - "ftable_lock_upgrade_failed", CTLFLAG_RD, - &stats->ftable_lock_upgrade_failed, 0, - "Forwarding table update required lock upgrade"); -} - -static void -vxlan_sysctl_destroy(struct vxlan_softc *sc) -{ - - sysctl_ctx_free(&sc->vxl_sysctl_ctx); - sc->vxl_sysctl_node = NULL; -} - -static int -vxlan_tunable_int(struct vxlan_softc *sc, const char *knob, int def) -{ - char path[64]; - - snprintf(path, sizeof(path), "net.link.vxlan.%d.%s", - sc->vxl_unit, knob); - TUNABLE_INT_FETCH(path, &def); - - return (def); -} - -static void vxlan_ifdetach_event(void *arg __unused, struct ifnet *ifp) { struct vxlan_softc_head list; @@ -3020,10 +3066,10 @@ if ((ifp->if_flags & IFF_MULTICAST) == 0) return; - mtx_lock(&vxlan_list_mtx); - LIST_FOREACH(vso, &vxlan_socket_list, vxlso_entry) + VXLAN_LIST_LOCK(); + LIST_FOREACH(vso, &V_vxlan_socket_list, vxlso_entry) vxlan_socket_ifdetach(vso, ifp, &list); - mtx_unlock(&vxlan_list_mtx); + VXLAN_LIST_UNLOCK(); LIST_FOREACH_SAFE(sc, &list, vxl_ifdetach_list, tsc) { LIST_REMOVE(sc, vxl_ifdetach_list); @@ -3036,27 +3082,32 @@ } static void -vxlan_load(void) +vnet_vxlan_init(const void *unused __unused) { - mtx_init(&vxlan_list_mtx, "vxlan list", NULL, MTX_DEF); - LIST_INIT(&vxlan_socket_list); - vxlan_ifdetach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, + VXLAN_LIST_LOCK_INIT(); + LIST_INIT(&V_vxlan_socket_list); + V_vxlan_ifdetach_event_tag = + EVENTHANDLER_REGISTER(ifnet_departure_event, vxlan_ifdetach_event, NULL, EVENTHANDLER_PRI_ANY); - vxlan_cloner = if_clone_simple(vxlan_name, vxlan_clone_create, + V_vxlan_cloner = if_clone_simple(vxlan_name, vxlan_clone_create, vxlan_clone_destroy, 0); } +VNET_SYSINIT(vnet_vxlan_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, + vnet_vxlan_init, NULL); static void -vxlan_unload(void) +vnet_vxlan_uninit(const void *unused __unused) { EVENTHANDLER_DEREGISTER(ifnet_departure_event, - vxlan_ifdetach_event_tag); - if_clone_detach(vxlan_cloner); - mtx_destroy(&vxlan_list_mtx); - MPASS(LIST_EMPTY(&vxlan_socket_list)); + V_vxlan_ifdetach_event_tag); + if_clone_detach(V_vxlan_cloner); + VXLAN_LIST_LOCK_DESTROY(); + MPASS(LIST_EMPTY(&V_vxlan_socket_list)); } +VNET_SYSUNINIT(vnet_vxlan_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, + vnet_vxlan_uninit, NULL); static int vxlan_modevent(module_t mod, int type, void *unused) @@ -3067,10 +3118,7 @@ switch (type) { case MOD_LOAD: - vxlan_load(); - break; case MOD_UNLOAD: - vxlan_unload(); break; default: error = ENOTSUP;