Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 May 2014 14:52:57 +0000 (UTC)
From:      Bryan Venteicher <bryanv@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r266469 - in projects/vxlan: sbin/ifconfig sys/net
Message-ID:  <201405201452.s4KEqvxw094457@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <net/if_var.h>
 #include <net/if_vxlan.h>
 #include <net/route.h>
+#include <netinet/in.h>
 
 #include <ctype.h>
 #include <stdio.h>
@@ -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) &params;
 	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 <netinet/in_var.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/ip_var.h>
+#include <netinet6/ip6_var.h>
 #include <netinet/udp.h>
 #include <netinet/udp_var.h>
 
@@ -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 ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405201452.s4KEqvxw094457>