25375056 Guest LDom packets may not flow w/o in-guest network activity (userland part)
authorCathy Zhou <Cathy.Zhou@Oracle.COM>
Thu, 19 Jan 2017 16:57:09 -0800
changeset 7590 5461fab14904
parent 7589 7eccd056eff6
child 7593 3f5b9ebe028b
25375056 Guest LDom packets may not flow w/o in-guest network activity (userland part) 25292405 Open vSwitch latency regression
components/openvswitch/files/lib/dpif-solaris.c
components/openvswitch/files/lib/dpif-solaris.h
components/openvswitch/files/lib/netdev-solaris.c
components/openvswitch/files/lib/util-solaris.c
components/openvswitch/files/lib/util-solaris.h
--- a/components/openvswitch/files/lib/dpif-solaris.c	Thu Jan 19 14:29:43 2017 -0800
+++ b/components/openvswitch/files/lib/dpif-solaris.c	Thu Jan 19 16:57:09 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -1914,8 +1914,8 @@
 
 		ofpbuf_use_stack(&buf, &state->maskbuf,
 		    sizeof (state->maskbuf));
-		odp_flow_key_from_mask(&buf, &flow->m, &flow->m,
-		    flow->f.in_port.odp_port, SIZE_MAX);
+		odp_flow_key_from_mask(&buf, &flow->m, &flow->f,
+		    UINT32_MAX, SIZE_MAX);
 
 		*mask = ofpbuf_data(&buf);
 		*mask_len = ofpbuf_size(&buf);
@@ -2998,6 +2998,52 @@
 	return (err);
 }
 
+void
+dpif_solaris_send_rarp(const char *name)
+{
+	struct dpif_solaris	*dpif;
+	int			fd = -1;
+	odp_port_t		port_no;
+	boolean_t		port_found = B_FALSE;
+	struct dpif_solaris_port	*port = NULL;
+	uint8_t			hwaddr[ETHERADDRL];
+
+	VLOG_DBG("dpif_get_uplink_fd: getting TX socket for %s\n", name);
+	dpif = get_dp_by_name("ovs-system");
+	if (dpif == NULL) {
+		VLOG_DBG("dpif_solaris_send_rarp: error getting datapath\n");
+		return;
+	}
+	ovs_rwlock_rdlock(&dpif->port_rwlock);
+	HMAP_FOR_EACH(port, node, &dpif->ports) {
+		if (strcmp(port->name, name) == 0) {
+			port_no = port->port_no;
+			port_found = B_TRUE;
+			break;
+		}
+	}
+	ovs_rwlock_unlock(&dpif->port_rwlock);
+	if (!port_found) {
+		VLOG_DBG("dpif_solaris_send_rarp: Error getting port for %s\n",
+		    name);
+		return;
+	}
+
+	if (netdev_get_etheraddr(port->netdev, hwaddr) != 0) {
+		VLOG_DBG("dpif_solaris_send_rarp: Error getting port %s's "
+		    "ethernet address\n", name);
+		return;
+	}
+
+	if (dpif_solaris_get_uplink_port_info(dpif, port_no,
+	    NULL, &fd, NULL) == 0) {
+		if (solaris_send_rarp(fd, hwaddr) == 0)
+			VLOG_DBG("dpif_get_uplink_fd: RARP success!");
+		else
+			VLOG_ERR("dpif_get_uplink_fd: RARP error!");
+	}
+}
+
 const struct dpif_class dpif_solaris_class = {
 	"system",
 	dpif_solaris_enumerate,
--- a/components/openvswitch/files/lib/dpif-solaris.h	Thu Jan 19 14:29:43 2017 -0800
+++ b/components/openvswitch/files/lib/dpif-solaris.h	Thu Jan 19 16:57:09 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -36,5 +36,6 @@
 void dpif_log(int, const char *, ...);
 void dpif_solaris_migrate_internal_port(const char *, const char *);
 struct netdev *dpif_solaris_obtain_netdev_to_migrate(char *, bool *);
+void dpif_solaris_send_rarp(const char *);
 
 #endif	/* DPIF_SOLARIS_H */
--- a/components/openvswitch/files/lib/netdev-solaris.c	Thu Jan 19 14:29:43 2017 -0800
+++ b/components/openvswitch/files/lib/netdev-solaris.c	Thu Jan 19 16:57:09 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -81,6 +81,8 @@
 	/* Protects all members below. */
 	struct ovs_mutex mutex;
 
+	boolean_t rarp_sent;
+
 	/*
 	 * Bit mask of cached properties. These can be cached because
 	 * nothing besides vswitchd is altering the properties.
@@ -147,6 +149,7 @@
 
 static int netdev_solaris_init(void);
 static struct netdev_solaris *netdev_solaris_cast(const struct netdev *);
+static void netdev_solaris_send_rarp(const struct netdev *);
 
 /* Maintaining a mapping of every netdev->name to its bridge name. */
 struct shash port_to_bridge_map = SHASH_INITIALIZER(&port_to_bridge_map);
@@ -702,6 +705,28 @@
 static void
 netdev_solaris_run(void)
 {
+	struct shash device_shash;
+	struct shash_node *node;
+
+	shash_init(&device_shash);
+	netdev_get_devices(&netdev_solaris_class, &device_shash);
+	SHASH_FOR_EACH(node, &device_shash) {
+		struct netdev *netdev = node->data;
+		struct netdev_solaris *dev = netdev_solaris_cast(netdev);
+
+		/*
+		 * No lock is needed to protect dev->rarp_sent. Because
+		 * netdev_solaris_run() is called single threaded in the
+		 * main() function.
+		 */
+		if (!dev->rarp_sent) {
+			netdev_solaris_send_rarp(netdev);
+			dev->rarp_sent = B_TRUE;
+		}
+		netdev_close(netdev);
+	}
+
+	shash_destroy(&device_shash);
 }
 
 static void
@@ -714,6 +739,7 @@
 {
 	struct netdev_solaris *netdev = xzalloc(sizeof (*netdev));
 
+	netdev->rarp_sent = B_FALSE;
 	return (&netdev->up);
 }
 
@@ -1198,6 +1224,24 @@
 	return (solaris_is_uplink_class(netdev->class));
 }
 
+/*
+ * Send an Reverse ARP for this link, if it is not an uplink.
+ */
+static void
+netdev_solaris_send_rarp(const struct netdev *netdev_)
+{
+	const char		*netdev_name = netdev_get_name(netdev_);
+
+	VLOG_DBG("netdev_solaris_send_rarp:send RARP device %s", netdev_name);
+
+	if (netdev_solaris_is_uplink(netdev_)) {
+		VLOG_DBG("netdev_solaris_send_rarp: uplink\n");
+		return;
+	}
+
+	dpif_solaris_send_rarp(netdev_name);
+}
+
 static int
 netdev_solaris_get_etheraddr(const struct netdev *netdev_,
     uint8_t mac[ETH_ADDR_LEN])
--- a/components/openvswitch/files/lib/util-solaris.c	Thu Jan 19 14:29:43 2017 -0800
+++ b/components/openvswitch/files/lib/util-solaris.c	Thu Jan 19 16:57:09 2017 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <config.h>
@@ -47,8 +47,10 @@
 #include <libdllink.h>
 #include <zone.h>
 #include <net/if_types.h>
+#include <net/if_arp.h>
 #include <inet/arp.h>
 #include <sys/socket.h>
+#include <sys/ethernet.h>
 #include <netdb.h>
 #include <rad/radclient.h>
 #include <rad/client/1/dlmgr.h>
@@ -81,6 +83,10 @@
 	uint32_t ofp_max;
 } ofport_range_t;
 
+static ether_addr_t	bcast_addr = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
 static int
 extract_uint(const char *valstr, uint_t *val)
 {
@@ -1591,6 +1597,7 @@
 	char		dstr[DLADM_STRSIZE];
 	int		err = 0;
 	boolean_t	is_arp = (ntohs(f->dl_type) == 0x806);
+	boolean_t	is_rarp = (ntohs(f->dl_type) == 0x8035);
 
 	dstr[0] = '\0';
 	if (f->dl_type != htons(FLOW_DL_TYPE_NONE)) {
@@ -1600,7 +1607,7 @@
 			goto out;
 	}
 
-	if (is_arp) {
+	if (is_arp || is_rarp) {
 		if (f->nw_proto != 0 || m->nw_proto != 0) {
 			err = dlmgr_DLValue_fm_putulong(ddvp, ddmp, "arp-op",
 			    f->nw_proto, m->nw_proto, dstr, sizeof (dstr));
@@ -1626,22 +1633,25 @@
 				goto out;
 		}
 
-		flow_addr2str(NULL, NULL, f->nw_src, m->nw_src, buf, rbuf,
-		    sizeof (buf), sizeof (rbuf));
-		if (strlen(buf) != 0) {
-			err = dlmgr_DLValue_fm_putstring(ddvp, ddmp, "arp-sip",
-			    buf, rbuf, dstr, sizeof (dstr));
-			if (err != 0)
-				goto out;
-		}
-
-		flow_addr2str(NULL, NULL, f->nw_dst, m->nw_dst, buf, rbuf,
-		    sizeof (buf), sizeof (rbuf));
-		if (strlen(buf) != 0) {
-			err = dlmgr_DLValue_fm_putstring(ddvp, ddmp, "arp-tip",
-			    buf, rbuf,  dstr, sizeof (dstr));
-			if (err != 0)
-				goto out;
+		/* sip and tip of REVARP_REQUEST is undefined */
+		if (f->nw_proto != REVARP_REQUEST) {
+			flow_addr2str(NULL, NULL, f->nw_src, m->nw_src, buf,
+			    rbuf, sizeof (buf), sizeof (rbuf));
+			if (strlen(buf) != 0) {
+				err = dlmgr_DLValue_fm_putstring(ddvp, ddmp,
+				    "arp-sip", buf, rbuf, dstr, sizeof (dstr));
+				if (err != 0)
+					goto out;
+			}
+
+			flow_addr2str(NULL, NULL, f->nw_dst, m->nw_dst, buf,
+			    rbuf, sizeof (buf), sizeof (rbuf));
+			if (strlen(buf) != 0) {
+				err = dlmgr_DLValue_fm_putstring(ddvp, ddmp,
+				    "arp-tip", buf, rbuf,  dstr, sizeof (dstr));
+				if (err != 0)
+					goto out;
+			}
 		}
 	} else {
 		if (f->nw_proto != 0 || m->nw_proto != 0) {
@@ -2568,6 +2578,9 @@
 
 	status = dlmgr__rad_dict_string_DLValue_map(mdict,
 	    solaris_flowinfo2flowmap, m);
+	/* IP fragmentation is not supported, always return 0xff for its mask */
+	if (is_ip_any(f))
+		m->nw_frag = 0xff;
 	dlmgr_DLValue_free(mlist);
 	if (status != RCE_OK)
 		return (EINVAL);
@@ -3968,3 +3981,62 @@
 
 	kstat2_close(&handle);
 }
+
+#define	ARH_FIXED_LEN	8
+/*
+ *  Send RARP packet on the given socket using the given MAC addresses.
+ *  Need to work with multiple MAC addresses
+ */
+int
+solaris_send_rarp(int sockfd, const uint8_t *hwaddr)
+{
+	int			count;
+	uint8_t			rarp_pkt[ETHERMIN];
+	struct ether_header	*ehp;
+	struct arphdr		*arh;
+	uint8_t			*cp;
+	uint8_t			*cp1;
+	uint8_t			plen = 4;
+	int			naddrs = 1;
+	int			err;
+
+	bzero(rarp_pkt, ETHERMIN);
+	ehp = (struct  ether_header *)rarp_pkt;
+	bcopy(&bcast_addr, &ehp->ether_dhost, ETHERADDRL);
+	ehp->ether_type = htons(ETHERTYPE_REVARP);
+	arh = (struct arphdr *)(rarp_pkt + sizeof (struct ether_header));
+	cp = (uint8_t *)arh;
+	arh->ar_hrd = htons(ARPHRD_ETHER);
+	arh->ar_pro = htons(ETHERTYPE_IP);
+	arh->ar_hln = ETHERADDRL;
+	arh->ar_pln = plen;
+	arh->ar_op = htons(REVARP_REQUEST);
+
+	cp += ARH_FIXED_LEN;
+	cp1 = cp;
+	/* For now, only one ethernet address is supported */
+	for (count = 0; count < naddrs; count++) {
+		cp = cp1;
+		bcopy(hwaddr, &ehp->ether_shost, ETHERADDRL);
+		bcopy(hwaddr, cp, ETHERADDRL);
+		cp += ETHERADDRL;
+		bzero(cp, plen);
+		cp += plen;
+
+		bcopy(hwaddr, cp, ETHERADDRL);
+		cp += ETHERADDRL;
+		bzero(cp, plen);
+
+		/*
+		 * Send the packet; Sending only one, we could send
+		 * multiple with an interval between them.
+		 */
+		errno = 0;
+		if (send(sockfd, (void *)rarp_pkt, ETHERMIN, 0) < 0) {
+			err = errno;
+			dpif_log(err, "RARP send() failed");
+			return (err);
+		}
+	}
+	return (0);
+}
--- a/components/openvswitch/files/lib/util-solaris.h	Thu Jan 19 14:29:43 2017 -0800
+++ b/components/openvswitch/files/lib/util-solaris.h	Thu Jan 19 16:57:09 2017 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	UTIL_SOLARIS_H
@@ -103,6 +103,7 @@
 boolean_t solaris_dlparse_zonelinkname(const char *, char *, zoneid_t *);
 
 void solaris_parse_cpuinfo(long int *);
+int solaris_send_rarp(int, const uint8_t *);
 
 #define	SOLARIS_MAX_BUFSIZE	1024
 #endif	/* UTIL_SOLARIS_H */