23086193 implicitly created OVS bridge VNIC shows incorrect statistic
authorMark Haywood <Mark.Haywood@Oracle.COM>
Wed, 18 May 2016 09:07:00 -0700
changeset 6018 b5072b523988
parent 6017 beff85b67068
child 6019 bd2dbcf829c2
23086193 implicitly created OVS bridge VNIC shows incorrect statistic 23102701 cannot create new OVS bridges after system reboot 23236806 ovs.vswitchd failed to start with -- too many open files -- error 23257330 failed to add uplink port to an OVS bridge in solaris-kz in certain cases
components/openvswitch/files/lib/dpif-solaris.c
components/openvswitch/files/lib/netdev-solaris.c
components/openvswitch/files/lib/util-solaris.c
components/openvswitch/files/lib/util-solaris.h
components/openvswitch/files/ovs-svc
components/openvswitch/patches/07-ovsthread_key_destruct-fix.patch
--- a/components/openvswitch/files/lib/dpif-solaris.c	Wed May 18 07:43:43 2016 -0700
+++ b/components/openvswitch/files/lib/dpif-solaris.c	Wed May 18 09:07:00 2016 -0700
@@ -120,6 +120,7 @@
 	/* Hash table index by unmasked flow. */
 	struct hmap_node node;	/* Node in dpif_solaris's 'flows'. */
 	struct flow flow;	/* The flow that created this entry. */
+	struct flow mask;	/* The flow that created this entry. */
 	char *physname;
 	char flowname[MAXUSERFLOWNAMELEN];
 };
@@ -245,7 +246,7 @@
 
 		ovs_refcount_init(&dpif->ref_cnt);
 		shash_add(&dp_all_solaris, name, dpif);
-		if (dp_exists) {
+		if (!create) {
 			ovs_refcount_ref(&dpif->ref_cnt);
 			goto again;
 		}
@@ -720,7 +721,7 @@
 		VLOG_DBG("set portno %d on %s", (uint32_t)(*port_nop),
 		    linkname);
 		if ((error = solaris_set_dlprop_ulong(linkname, "ofport",
-		    &u64)) != 0) {
+		    &u64, B_TRUE)) != 0) {
 			VLOG_ERR("set portno %d on %s failed: %s",
 			    (uint32_t)(*port_nop), linkname,
 			    ovs_strerror(error));
@@ -784,7 +785,8 @@
 	if (vtype == OVS_VPORT_TYPE_NETDEV || vtype == OVS_VPORT_TYPE_VXLAN ||
 	    vtype == OVS_VPORT_TYPE_INTERNAL) {
 		VLOG_DBG("reset portno on %s", linkname);
-		(void) solaris_set_dlprop_ulong(linkname, "ofport", NULL);
+		(void) solaris_set_dlprop_ulong(linkname, "ofport", NULL,
+		    B_TRUE);
 	}
 	ovs_rwlock_unlock(&dpif->port_rwlock);
 	ovs_rwlock_unlock(&dpif->upcall_lock);
@@ -879,7 +881,7 @@
 	    OVS_VPORT_TYPE_VXLAN || port->vtype == OVS_VPORT_TYPE_INTERNAL) {
 			VLOG_DBG("1.reset portno on %s", port->linkname);
 			(void) solaris_set_dlprop_ulong(port->linkname,
-			    "ofport", NULL);
+			    "ofport", NULL, B_TRUE);
 		if (port->is_uplink) {
 			VLOG_DBG("dpif_solaris_port_del__ primary port "
 			    "%s", port->name);
@@ -1193,8 +1195,23 @@
 }
 
 static struct dpif_solaris_flow *
+dpif_solaris_find_flow_by_name(const struct dpif_solaris *dpif,
+    const char *flowname)
+{
+	struct dpif_solaris_flow *solaris_flow;
+
+	HMAP_FOR_EACH(solaris_flow, node, &dpif->flows) {
+		if (strcmp(solaris_flow->flowname, flowname) == 0) {
+			return (solaris_flow);
+		}
+	}
+
+	return (NULL);
+}
+
+static struct dpif_solaris_flow *
 dpif_solaris_flow_add(struct dpif_solaris *dpif, const char *physname,
-    struct flow *flow, const struct flow_wildcards *wc)
+    struct flow *flow, struct flow *mask, const struct flow_wildcards *wc)
     OVS_REQ_WRLOCK(dpif->flow_rwlock)
 {
 	struct dpif_solaris_flow *solaris_flow;
@@ -1206,6 +1223,7 @@
 	(void) snprintf(solaris_flow->flowname, MAXUSERFLOWNAMELEN,
 	    "%p.sys.of", (void *)solaris_flow);
 	solaris_flow->flow = *flow;
+	solaris_flow->mask = *mask;
 	match_init(&match, flow, wc);
 	fat_rwlock_wrlock(&dpif->cls.rwlock);
 	cls_rule_init(&solaris_flow->cr, &match, 0x8001);
@@ -1425,7 +1443,7 @@
 				    physname);
 
 				solaris_flow = dpif_solaris_flow_add(dpif,
-				    physname, &f, &wc);
+				    physname, &f, &wc.masks, &wc);
 				(void) strlcpy(flowname,
 				    solaris_flow->flowname,
 				    MAXUSERFLOWNAMELEN);
@@ -1628,6 +1646,7 @@
 };
 
 struct dpif_solaris_flow_iter {
+	struct dpif_solaris *dpif;
 	struct hmap flows;
 	uint32_t bucket;
 	uint32_t offset;
@@ -1657,7 +1676,9 @@
     uint64_t lastused)
 {
 	struct dpif_solaris_flow_iter *iter = arg;
+	struct dpif_solaris *dpif = iter->dpif;
 	struct dpif_solaris_flow_ent *flow;
+	struct dpif_solaris_flow *dsflow;
 
 	VLOG_DBG("dpif_solaris_flow_dump_start walk flow %s", name);
 	ovs_assert(!is_default);
@@ -1665,6 +1686,19 @@
 	strlcpy(flow->flowname, name, sizeof (flow->flowname));
 	bcopy(f, &flow->f, sizeof (*f));
 	bcopy(m, &flow->m, sizeof (*m));
+	fat_rwlock_rdlock(&dpif->cls.rwlock);
+	if ((dsflow = dpif_solaris_find_flow_by_name(dpif, name)) != NULL) {
+		bcopy(&dsflow->flow, &flow->f, sizeof (struct flow));
+		bcopy(&dsflow->mask, &flow->m, sizeof (struct flow));
+		VLOG_DBG("dpif_solaris_flow_dump_start walk flow %s found "
+		    "tunnel 0x%lx src 0x%x dst 0x%x\n", name,
+		    flow->f.tunnel.tun_id, flow->f.tunnel.ip_src,
+		    flow->f.tunnel.ip_dst);
+	} else {
+		VLOG_DBG("dpif_solaris_flow_dump_start walk flow %s not found"
+		    "\n", name);
+	}
+	fat_rwlock_unlock(&dpif->cls.rwlock);
 	flow->stats.n_packets = npackets;
 	flow->stats.n_bytes = nbytes;
 	flow->stats.used = lastused / 1000000;
@@ -1680,12 +1714,14 @@
 }
 
 static int
-dpif_solaris_flow_dump_start(const struct dpif *dpif OVS_UNUSED, void **iterp)
+dpif_solaris_flow_dump_start(const struct dpif *dpif_, void **iterp)
 {
+	struct dpif_solaris *dpif = dpif_solaris_cast(dpif_);
 	struct dpif_solaris_flow_iter *iter;
 	struct ofpbuf action;
 
 	*iterp = iter = xmalloc(sizeof (*iter));
+	iter->dpif = dpif;
 	iter->bucket = 0;
 	iter->offset = 0;
 	iter->status = 0;
@@ -1809,7 +1845,7 @@
 
 static int
 dpif_solaris_port_output(struct dpif_solaris *dpif, odp_port_t port_no,
-    struct ofpbuf *packet, bool may_steal)
+    struct ofpbuf *packet, struct flow_tnl *tnl, bool may_steal)
 {
 	struct msghdr			msghdr;
 	struct iovec 			iov;
@@ -1820,9 +1856,10 @@
 	ssize_t		nbytes = 0;
 	const char	*buf = ofpbuf_data(packet);
 	size_t		buflen = ofpbuf_size(packet);
-	int error, fd = -1;
+	int		error, fd = -1;
 
-	VLOG_DBG("dpif_solaris_port_output %d", port_no);
+	VLOG_DBG("dpif_solaris_port_output %d tunnel %ld", port_no,
+	    tnl == NULL ? 0 : tnl->tun_id);
 
 	error = dpif_solaris_get_uplink_port_info(dpif, port_no, NULL, &fd);
 	if (error != 0 || fd == -1) {
@@ -1848,6 +1885,15 @@
 
 	memcpy(&auxdata, CMSG_DATA(cmsg), sizeof (auxdata));
 	auxdata.tp_of_port = port_no;
+#ifdef MAC_OVS_AUX_DATA_VERSION
+	auxdata.tp_tun_id = 0;
+	IN6_IPADDR_TO_V4MAPPED(0, &auxdata.tp_tun_dstip);
+	if (tnl != NULL) {
+		auxdata.tp_tun_type = 0;
+		auxdata.tp_tun_id = htonll(tnl->tun_id);
+		IN6_IPADDR_TO_V4MAPPED(tnl->ip_dst, &auxdata.tp_tun_dstip);
+	}
+#endif
 	memcpy(CMSG_DATA(cmsg), &auxdata, sizeof (auxdata));
 	for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
 		nbytes = sendmsg(fd, &msghdr, 0);
@@ -2008,11 +2054,12 @@
 
 static void
 dp_solaris_execute_cb(void *aux_, struct ofpbuf *packet,
-    struct pkt_metadata *md OVS_UNUSED, const struct nlattr *a, bool may_steal)
+    struct pkt_metadata *md, const struct nlattr *a, bool may_steal)
 {
 	struct dpif_solaris *dpif = aux_;
 	int type = nl_attr_type(a);
 	odp_port_t pin, pout;
+	struct flow_tnl *tnl = NULL;
 	int err;
 
 	VLOG_DBG("dp_solaris_execute_cb type %d", type);
@@ -2067,7 +2114,9 @@
 				break;
 			}
 		}
-		(void) dpif_solaris_port_output(dpif, port_no, packet,
+		if (md->tunnel.ip_dst && (port_no == pout))
+			tnl = &md->tunnel;
+		(void) dpif_solaris_port_output(dpif, port_no, packet, tnl,
 		    may_steal);
 		break;
 	}
@@ -2095,9 +2144,12 @@
 				ofpbuf_delete(packet);
 			break;
 		}
+		if (md->tunnel.ip_dst)
+			tnl = &md->tunnel;
 		VLOG_DBG("dp_solaris_execute_cb OVS_ACTION_ATTR_USERSPACE "
 		    "%d", pin);
-		(void) dpif_solaris_port_output(dpif, pin, packet, may_steal);
+		(void) dpif_solaris_port_output(dpif, pin, packet, tnl,
+		    may_steal);
 		break;
 	}
 	case OVS_ACTION_ATTR_HASH:		/* for bonding */
@@ -2406,7 +2458,8 @@
 	buf_size += ofpbuf_size(packet);
 	ofpbuf_init(buf, buf_size);
 
-	VLOG_DBG("PARSE flow in_port %d", flow.in_port.odp_port);
+	VLOG_DBG("PARSE flow in_port %d tunnel dst %u", flow.in_port.odp_port,
+	    flow.tunnel.ip_dst);
 	odp_flow_key_from_flow(buf, &flow, NULL, flow.in_port.odp_port);
 	upcall->key = ofpbuf_data(buf);
 	upcall->key_len = ofpbuf_size(buf);
@@ -2465,15 +2518,14 @@
 		pktlen = recvmsg(port->upcall_fd, &msg, MSG_TRUNC);
 		if (pktlen > 0) {
 			struct pkt_metadata	md;
-			mactun_info_t		*tuninfop;
+			mactun_info_t		*tuninfop = NULL;
 			struct flow_tnl		*tun;
 			struct ofpbuf		pkt;
+			struct tpacket_auxdata	aux;
 
 			action_type = FLOW_ACTION_OF_MAX;
 			for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
 			    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
-				struct tpacket_auxdata	aux;
-
 				if (cmsg->cmsg_len <
 				    CMSG_LEN(sizeof (struct tpacket_auxdata)) ||
 				    cmsg->cmsg_level != SOL_PACKET ||
@@ -2500,6 +2552,7 @@
 			    action_type == FLOW_ACTION_MISSED_PKT ?
 			    "miss_pkt" : "fwd_controller", port_no);
 
+			ovs_assert(tuninfop != NULL);
 			md = PKT_METADATA_INITIALIZER(port_no);
 			if (tuninfop->mti_dst._S6_un._S6_u32[3] != 0) {
 				tun = &md.tunnel;
--- a/components/openvswitch/files/lib/netdev-solaris.c	Wed May 18 07:43:43 2016 -0700
+++ b/components/openvswitch/files/lib/netdev-solaris.c	Wed May 18 09:07:00 2016 -0700
@@ -941,12 +941,10 @@
 	if (error != 0) {
 		VLOG_ERR("netdev_create_impl_etherstub: failed to create %s: "
 		    "%s", NETDEV_IMPL_ETHERSTUB, ovs_strerror(error));
-
 	} else {
 		boolean_t bval = B_TRUE;
-
 		error = solaris_set_dlprop_boolean(NETDEV_IMPL_ETHERSTUB,
-		    "openvswitch", &bval);
+		    "openvswitch", &bval, B_FALSE);
 		if (error != 0) {
 			(void) solaris_delete_etherstub(NETDEV_IMPL_ETHERSTUB);
 			VLOG_ERR("netdev_create_impl_etherstub: failed to "
@@ -964,7 +962,7 @@
 	int		error;
 
 	error = solaris_set_dlprop_boolean(NETDEV_IMPL_ETHERSTUB,
-	    "openvswitch", &bval);
+	    "openvswitch", &bval, B_FALSE);
 	if (error != 0) {
 		VLOG_ERR("netdev_create_impl_etherstub: failed to "
 		    "set 'openvswitch' property on %s: %s: ",
@@ -982,7 +980,24 @@
 boolean_t
 netdev_impl_etherstub_exists(void)
 {
-	return (solaris_etherstub_exists(NETDEV_IMPL_ETHERSTUB));
+	char	prop[DLADM_PROP_VAL_MAX];
+	int	error;
+
+	error = solaris_get_dlprop(NETDEV_IMPL_ETHERSTUB, "openvswitch",
+	    "current", prop, sizeof (prop));
+	if (error == ENODEV)
+		return (B_FALSE);
+
+	/*
+	 * If the implicit etherstub exists, but the openvswitch
+	 * property is not set, then something has gone wrong.
+	 */
+	if (strcmp(prop, "1") != 0) {
+		VLOG_FATAL("%s does not have openvswitch property set",
+		    NETDEV_IMPL_ETHERSTUB);
+	}
+
+	return (B_TRUE);
 }
 
 /*
@@ -1111,7 +1126,8 @@
 	 */
 	(void) snprintf(buffer, sizeof (buffer), ETH_ADDR_FMT,
 	    ETH_ADDR_ARGS(mac));
-	error = solaris_set_dlprop_string(netdev_name, "mac-address", buffer);
+	error = solaris_set_dlprop_string(netdev_name, "mac-address", buffer,
+	    B_TRUE);
 	if (error != 0) {
 		VLOG_ERR("set etheraddr %s on %s device failed: %s",
 		    buffer, netdev_name, ovs_strerror(error));
@@ -1303,7 +1319,7 @@
 	/*
 	 * MTU is a datalink property.
 	 */
-	error = solaris_set_dlprop_ulong(netdev_name, "mtu", &ulval);
+	error = solaris_set_dlprop_ulong(netdev_name, "mtu", &ulval, B_TRUE);
 	if (error != 0) {
 		VLOG_ERR("set mtu on %s device failed: %s",
 		    netdev_name, ovs_strerror(error));
@@ -2379,13 +2395,6 @@
 }
 
 static int
-netdev_internal_get_stats(const struct netdev *netdev_ OVS_UNUSED,
-    struct netdev_stats *stats OVS_UNUSED)
-{
-	return (0);
-}
-
-static int
 netdev_internal_get_status(const struct netdev *netdev OVS_UNUSED,
     struct smap *smap)
 {
@@ -2467,7 +2476,7 @@
     NETDEV_SOLARIS_CLASS(
 	"internal",
 	netdev_solaris_construct,
-	netdev_internal_get_stats,
+	netdev_solaris_get_stats,
 	NULL,				/* set_stats */
 	NULL,				/* get_features */
 	netdev_internal_get_status);
--- a/components/openvswitch/files/lib/util-solaris.c	Wed May 18 07:43:43 2016 -0700
+++ b/components/openvswitch/files/lib/util-solaris.c	Wed May 18 09:07:00 2016 -0700
@@ -826,6 +826,13 @@
 		memcpy(prop_value, buf, prop_len);
 		break;
 	case DDLVT_BOOLEAN:
+		if (dlval->ddlv_bval == NULL) {
+			error = EINVAL;
+			goto out;
+		}
+		(void) snprintf(buf, sizeof (buf), "%d", *dlval->ddlv_bval);
+		memcpy(prop_value, buf, prop_len);
+		break;
 	case DDLVT_BOOLEANS:
 	case DDLVT_LONG:
 	case DDLVT_LONGS:
@@ -846,7 +853,7 @@
 
 static int
 solaris_set_dlprop(const char *netdev_name, const char *propname, void *arg,
-    dlmgr_DLValueType_t vtype)
+    dlmgr_DLValueType_t vtype, boolean_t temp)
 {
 	dlmgr__rad_dict_string_DLValue_t *sprop_dict = NULL;
 	dlmgr_DLValue_t			*old_val = NULL;
@@ -914,18 +921,19 @@
 		break;
 	}
 
-	/* we need to add temporary flag */
-	bzero(&new_val, sizeof (new_val));
-	old_val = NULL;
-	new_val.ddlv_type = DDLVT_BOOLEAN;
-	new_val.ddlv_bval = &b_true;
-	status = dlmgr__rad_dict_string_DLValue_put(
-	    sprop_dict, "temporary", &new_val, &old_val);
-	if (status != RCE_OK) {
-		error = EINVAL;
-		goto out;
+	if (temp) {
+		bzero(&new_val, sizeof (new_val));
+		old_val = NULL;
+		new_val.ddlv_type = DDLVT_BOOLEAN;
+		new_val.ddlv_bval = &b_true;
+		status = dlmgr__rad_dict_string_DLValue_put(
+		    sprop_dict, "temporary", &new_val, &old_val);
+		if (status != RCE_OK) {
+			error = EINVAL;
+			goto out;
+		}
+		dlmgr_DLValue_free(old_val);
 	}
-	dlmgr_DLValue_free(old_val);
 
 	status = dlmgr_Datalink_setProperties(link, sprop_dict, &derrp);
 	if (status != RCE_OK) {
@@ -945,35 +953,35 @@
 
 int
 solaris_set_dlprop_boolean(const char *netdev_name, const char *propname,
-    void *arg)
+    void *arg, boolean_t temp)
 {
-	return (solaris_set_dlprop(netdev_name, propname, arg, DDLVT_BOOLEAN));
+	return (solaris_set_dlprop(netdev_name, propname, arg, DDLVT_BOOLEAN,
+	    temp));
 }
 
 int
 solaris_set_dlprop_ulong(const char *netdev_name, const char *propname,
-    void *arg)
+    void *arg, boolean_t temp)
 {
-	return (solaris_set_dlprop(netdev_name, propname, arg, DDLVT_ULONG));
+	return (solaris_set_dlprop(netdev_name, propname, arg, DDLVT_ULONG,
+	    temp));
 }
 
 int
 solaris_set_dlprop_string(const char *netdev_name, const char *propname,
-    void *arg)
+    void *arg, boolean_t temp)
 {
-	return (solaris_set_dlprop(netdev_name, propname, arg, DDLVT_STRING));
+	return (solaris_set_dlprop(netdev_name, propname, arg, DDLVT_STRING,
+	    temp));
 }
 
 int
 solaris_create_vnic(const char *linkname, const char *vnicname)
 {
 	dlmgr__rad_dict_string_DLValue_t *prop = NULL;
-	dlmgr__rad_dict_string_DLValue_t *macaddr_info = NULL;
 	dlmgr_DatalinkError_t		*derrp = NULL;
 	dlmgr_DLValue_t			*old_val = NULL;
 	dlmgr_DLValue_t			name_val;
-	dlmgr_DLValue_t			type_val;
-	dlmgr_DLValue_t			macaddr_info_val;
 	rc_instance_t			*linkmgr = NULL;
 	rc_instance_t			*vnic = NULL;
 	rc_err_t			status;
@@ -998,29 +1006,6 @@
 	dlmgr_DLValue_free(old_val);
 	old_val = NULL;
 
-	macaddr_info = dlmgr__rad_dict_string_DLValue_create(linkmgr);
-	if (macaddr_info == NULL)
-		goto out;
-
-	bzero(&type_val, sizeof (type_val));
-	type_val.ddlv_type = DDLVT_STRING;
-	type_val.ddlv_sval = strdupa("auto");
-	status = dlmgr__rad_dict_string_DLValue_put(macaddr_info,
-	    "mac-address-type", &type_val, &old_val);
-	if (status != RCE_OK)
-		goto out;
-	dlmgr_DLValue_free(old_val);
-	old_val = NULL;
-
-	bzero(&macaddr_info_val, sizeof (macaddr_info_val));
-	macaddr_info_val.ddlv_type = DDLVT_DICTIONARY;
-	macaddr_info_val.ddlv_dval = macaddr_info;
-	status = dlmgr__rad_dict_string_DLValue_put(prop, "mac-address-info",
-	    &macaddr_info_val, &old_val);
-	if (status != RCE_OK)
-		goto out;
-	dlmgr_DLValue_free(old_val);
-
 	status = dlmgr_DatalinkManager_createVNIC(linkmgr, vnicname, prop,
 	    &vnic, &derrp);
 	if (status == RCE_SERVER_OBJECT) {
@@ -1031,7 +1016,6 @@
 	rc_instance_rele(vnic);
 	dlmgr_DatalinkError_free(derrp);
 out:
-	dlmgr__rad_dict_string_DLValue_free(macaddr_info);
 	dlmgr__rad_dict_string_DLValue_free(prop);
 	rc_instance_rele(linkmgr);
 	return ((status != RCE_OK) ? ENOTSUP : 0);
@@ -1041,11 +1025,8 @@
 solaris_modify_vnic(const char *linkname, const char *vnicname)
 {
 	dlmgr__rad_dict_string_DLValue_t *sprop_dict = NULL;
-	dlmgr__rad_dict_string_DLValue_t *macaddr_info = NULL;
 	dlmgr_DLValue_t			*old_val = NULL;
 	dlmgr_DLValue_t			new_val;
-	dlmgr_DLValue_t			type_val;
-	dlmgr_DLValue_t			macaddr_info_val;
 	rc_instance_t			*link = NULL;
 	rc_err_t			status;
 	dlmgr_DatalinkError_t   	*derrp = NULL;
@@ -1075,43 +1056,6 @@
 	}
 	dlmgr_DLValue_free(old_val);
 
-	/* we need to add temporary flag */
-	bzero(&new_val, sizeof (new_val));
-	old_val = NULL;
-	new_val.ddlv_type = DDLVT_BOOLEAN;
-	new_val.ddlv_bval = &b_true;
-	status = dlmgr__rad_dict_string_DLValue_put(
-	    sprop_dict, "temporary", &new_val, &old_val);
-	if (status != RCE_OK) {
-		error = EINVAL;
-		goto out;
-	}
-	dlmgr_DLValue_free(old_val);
-
-	macaddr_info = dlmgr__rad_dict_string_DLValue_create(link);
-	if (macaddr_info == NULL)
-		goto out;
-
-	bzero(&type_val, sizeof (type_val));
-	old_val = NULL;
-	type_val.ddlv_type = DDLVT_STRING;
-	type_val.ddlv_sval = strdupa("auto");
-	status = dlmgr__rad_dict_string_DLValue_put(macaddr_info,
-	    "mac-address-type", &type_val, &old_val);
-	if (status != RCE_OK)
-		goto out;
-	dlmgr_DLValue_free(old_val);
-
-	bzero(&macaddr_info_val, sizeof (macaddr_info_val));
-	old_val = NULL;
-	macaddr_info_val.ddlv_type = DDLVT_DICTIONARY;
-	macaddr_info_val.ddlv_dval = macaddr_info;
-	status = dlmgr__rad_dict_string_DLValue_put(sprop_dict,
-	    "mac-address-info", &macaddr_info_val, &old_val);
-	if (status != RCE_OK)
-		goto out;
-	dlmgr_DLValue_free(old_val);
-
 	status = dlmgr_Datalink_setProperties(link, sprop_dict, &derrp);
 	if (status != RCE_OK) {
 		if (status == RCE_SERVER_OBJECT) {
@@ -1123,7 +1067,6 @@
 	}
 out:
 	dlmgr_DatalinkError_free(derrp);
-	dlmgr__rad_dict_string_DLValue_free(macaddr_info);
 	dlmgr__rad_dict_string_DLValue_free(sprop_dict);
 	rc_instance_rele(link);
 	return (error);
@@ -1211,36 +1154,6 @@
 	return ((status != RCE_OK) ? ENOTSUP : 0);
 }
 
-boolean_t
-solaris_etherstub_exists(const char *name)
-{
-	rc_instance_t	*etherstub = NULL;
-	boolean_t	exists;
-	rc_err_t	status;
-
-	status = dlmgr_Etherstub__rad_lookup(rad_conn, B_TRUE, &etherstub, 1,
-	    "name", name);
-	if (status == RCE_OK) {
-		dlmgr__rad_dict_string_DLValue_t *linkinfo = NULL;
-		dlmgr_DatalinkError_t *derrp = NULL;
-
-		status = dlmgr_Etherstub_getInfo(etherstub, NULL, 0,
-		    &linkinfo, &derrp);
-		if (status == RCE_OK) {
-			exists = _B_TRUE;
-			dlmgr__rad_dict_string_DLValue_free(linkinfo);
-		} else {
-			exists = _B_FALSE;
-			dlmgr_DatalinkError_free(derrp);
-		}
-	} else {
-		exists = _B_FALSE;
-	}
-
-	rc_instance_rele(etherstub);
-	return (exists);
-}
-
 static int
 flow_str2mac(const char *str, uchar_t *f, size_t maclen)
 {
@@ -1717,7 +1630,7 @@
 	const char *max_rate = NULL;
 	uint64_t maxbw;
 	char *endp = NULL;
-	int err;
+	int err = EINVAL;
 
 	smap_init(&details);
 	if (queueid == UINT32_MAX || nofports != 1)
@@ -2907,6 +2820,7 @@
 	 * The property value is in the format of "src:xxx" "dst:xxx"
 	 * "tun_id:0x%x" "tos:0x%x" "hoplimit:xxx"
 	 */
+	bzero(&tnl, sizeof (struct flow_tnl));
 	tnl.ip_tos = 0xff;
 	for (i = 0; i < nval; i++) {
 		(void) strlcpy(pval, propvals[i], sizeof (pval));
@@ -3693,3 +3607,72 @@
 
 	return (_B_TRUE);
 }
+
+/*
+ * Sets *n_cores to the total number of cores on this system, or 0 if the
+ * number cannot be determined.
+ */
+void
+solaris_parse_cpuinfo(long int *n_cores)
+{
+	kstat2_handle_t	handle;
+	kstat2_status_t	stat;
+	kstat2_map_t	map;
+	kstat2_nv_t	val;
+	char		kuri[1024];
+	int		coreid;
+	int		lcoreid = -1;
+	int		i;
+
+	*n_cores = 0;
+
+	stat = kstat2_open(&handle, NULL);
+	if (stat != KSTAT2_S_OK) {
+		dpif_log(1, "solaris_parse_cpuinfo kstat2_open failed (%s). "
+		    "Core count may be inaccurate.",
+		    kstat2_status_string(stat));
+		return;
+	}
+
+	for (i = 0; ; i++) {
+		(void) snprintf(kuri, sizeof (kuri),
+		    "kstat:/system/cpu/%d/info", i);
+		stat = kstat2_lookup_map(handle, kuri, &map);
+		if (stat == KSTAT2_S_OK) {
+			stat = kstat2_map_get(map, "core_id", &val);
+			if (stat != KSTAT2_S_OK) {
+				dpif_log(1, "solaris_parse_cpuinfo"
+				    "kstat2_map_get failed (%s). "
+				    "Core count may be inaccurate.",
+				    kstat2_status_string(stat));
+				*n_cores = 0;
+				break;
+			}
+
+			if (val->type != KSTAT2_NVVT_INT) {
+				dpif_log(1, "solaris_parse_cpuinfo "
+				    "kstat2 value error. "
+				    "Core count may be inaccurate.");
+				*n_cores = 0;
+				break;
+			}
+
+			coreid = val->kstat2_integer;
+			if (coreid != lcoreid) {
+				(*n_cores)++;
+				lcoreid = coreid;
+			}
+		} else if (stat == KSTAT2_S_NOT_FOUND) {
+			/* no more cores */
+			break;
+		} else {
+			dpif_log(1, "solaris_parse_cpuinfo kstat2_lookup_map "
+			    "failed (%s). Core count may be inaccurate.",
+			    kstat2_status_string(stat));
+			*n_cores = 0;
+			break;
+		}
+	}
+
+	kstat2_close(&handle);
+}
--- a/components/openvswitch/files/lib/util-solaris.h	Wed May 18 07:43:43 2016 -0700
+++ b/components/openvswitch/files/lib/util-solaris.h	Wed May 18 09:07:00 2016 -0700
@@ -130,9 +130,9 @@
 int solaris_get_dllower(const char *, char *, size_t);
 int solaris_get_dlprop(const char *, const char *, const char *, char *,
     size_t);
-int solaris_set_dlprop_ulong(const char *, const char *, void *);
-int solaris_set_dlprop_boolean(const char *, const char *, void *);
-int solaris_set_dlprop_string(const char *, const char *, void *);
+int solaris_set_dlprop_ulong(const char *, const char *, void *, boolean_t);
+int solaris_set_dlprop_boolean(const char *, const char *, void *, boolean_t);
+int solaris_set_dlprop_string(const char *, const char *, void *, boolean_t);
 int solaris_plumb_if(int, const char *, sa_family_t);
 int solaris_unplumb_if(int, const char *, sa_family_t);
 boolean_t dlparse_drvppa(const char *, char *, uint_t, uint_t *);
@@ -168,6 +168,7 @@
 boolean_t solaris_is_uplink_class(const char *);
 boolean_t solaris_dlparse_zonelinkname(const char *, char *, zoneid_t *);
 
+void solaris_parse_cpuinfo(long int *);
 
 #define	SOLARIS_MAX_BUFSIZE	1024
 #endif	/* UTIL_SOLARIS_H */
--- a/components/openvswitch/files/ovs-svc	Wed May 18 07:43:43 2016 -0700
+++ b/components/openvswitch/files/ovs-svc	Wed May 18 09:07:00 2016 -0700
@@ -92,7 +92,7 @@
 	typeset -r OVSDB_PIDFILE=${OVS_TMP_DIR}/ovsdb-server.pid
 
 	${OVSDB_SERVER_PATH} ${OVSDB_DATABASE} \
-	    -vconsole:emer -vsyslog:off -vfile:info \
+	    -vconsole:emer -vsyslog:off -vfile:warn \
 	    --remote=punix:${OVSDB_REMOTE} \
 	    --remote=db:Open_vSwitch,Open_vSwitch,manager_options \
 	    --private-key=db:Open_vSwitch,SSL,private_key \
@@ -156,7 +156,7 @@
 	create_ovs_tempdir
 
 	 ${PFEXEC} ${OVS_VSWITCHD_PATH} unix:${OVSDB_REMOTE} \
-	    -vconsole:emer -vsyslog:off -vfile:info --mlockall --no-chdir \
+	    -vconsole:emer -vsyslog:off -vfile:warn --mlockall --no-chdir \
 	    --log-file=${VSWITCHD_LOGFILE} \
 	    --pidfile=${VSWITCHD_PIDFILE} \
 	    --detach
--- a/components/openvswitch/patches/07-ovsthread_key_destruct-fix.patch	Wed May 18 07:43:43 2016 -0700
+++ b/components/openvswitch/patches/07-ovsthread_key_destruct-fix.patch	Wed May 18 09:07:00 2016 -0700
@@ -3,10 +3,43 @@
 This patch has not been proposed upstream but will be proposed for 2.5.
 
 diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c
-index 529756f..8b76eb9 100644
+index 529756f..86a3fa4 100644
 --- a/lib/ovs-thread.c
 +++ b/lib/ovs-thread.c
-@@ -641,8 +641,10 @@ ovsthread_key_destruct__(void *slots_)
+@@ -28,6 +28,10 @@
+ #include "socket-util.h"
+ #include "util.h"
+ 
++#ifdef __sun
++#include <util-solaris.h>
++#endif
++
+ #ifdef __CHECKER__
+ /* Omit the definitions in this file because they are somewhat difficult to
+  * write without prompting "sparse" complaints, without ugliness or
+@@ -476,6 +480,13 @@ ovs_thread_stats_next_bucket(const struct ovsthread_stats *stats, size_t i)
+     return i;
+ }
+ 
++#ifdef __sun
++static void
++parse_cpuinfo(long int *n_cores)
++{
++    solaris_parse_cpuinfo(n_cores);
++}
++#else
+ 
+ /* Parses /proc/cpuinfo for the total number of physical cores on this system
+  * across all CPU packages, not counting hyper-threads.
+@@ -531,6 +542,7 @@ parse_cpuinfo(long int *n_cores)
+ 
+     *n_cores = cores;
+ }
++#endif
+ 
+ /* Returns the total number of cores on this system, or 0 if the number cannot
+  * be determined.
+@@ -641,8 +653,10 @@ ovsthread_key_destruct__(void *slots_)
      n = n_keys;
      ovs_mutex_unlock(&key_mutex);