Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 31 Jul 2017 06:27:43 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r321759 - stable/10/sys/dev/hyperv/netvsc
Message-ID:  <201707310627.v6V6RhHh074860@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Mon Jul 31 06:27:43 2017
New Revision: 321759
URL: https://svnweb.freebsd.org/changeset/base/321759

Log:
  MFC 321407
  
      hyperv/hn: Export VF list and VF-HN mapping
  
      The VF-HN map will be used later on to implement "transparent VF".
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D11618

Modified:
  stable/10/sys/dev/hyperv/netvsc/if_hn.c
  stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/netvsc/if_hn.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/if_hn.c	Mon Jul 31 05:23:32 2017	(r321758)
+++ stable/10/sys/dev/hyperv/netvsc/if_hn.c	Mon Jul 31 06:27:43 2017	(r321759)
@@ -69,6 +69,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/proc.h>
 #include <sys/queue.h>
 #include <sys/lock.h>
+#include <sys/rmlock.h>
+#include <sys/sbuf.h>
 #include <sys/smp.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
@@ -118,6 +120,8 @@ __FBSDID("$FreeBSD$");
 
 #define HN_RING_CNT_DEF_MAX		8
 
+#define HN_VFMAP_SIZE_DEF		8
+
 /* YYY should get it from the underlying channel */
 #define HN_TX_DESC_CNT			512
 
@@ -250,6 +254,11 @@ static int			hn_ifmedia_upd(struct ifnet *);
 static void			hn_ifmedia_sts(struct ifnet *,
 				    struct ifmediareq *);
 
+static void			hn_ifnet_event(void *, struct ifnet *, int);
+static void			hn_ifaddr_event(void *, struct ifnet *);
+static void			hn_ifnet_attevent(void *, struct ifnet *);
+static void			hn_ifnet_detevent(void *, struct ifnet *);
+
 static int			hn_rndis_rxinfo(const void *, int,
 				    struct hn_rxinfo *);
 static void			hn_rndis_rx_data(struct hn_rx_ring *,
@@ -296,6 +305,9 @@ static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARG
 static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
 static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
 static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
+static int			hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS);
+static int			hn_vflist_sysctl(SYSCTL_HANDLER_ARGS);
+static int			hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS);
 
 static void			hn_stop(struct hn_softc *, bool);
 static void			hn_init_locked(struct hn_softc *);
@@ -493,9 +505,21 @@ static int			hn_tx_agg_pkts = -1;
 SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
 
+/* VF list */
+SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING,
+    0, 0, hn_vflist_sysctl, "A", "VF list");
+
+/* VF mapping */
+SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING,
+    0, 0, hn_vfmap_sysctl, "A", "VF mapping");
+
 static u_int			hn_cpu_index;	/* next CPU for channel */
 static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
 
+static struct rmlock		hn_vfmap_lock;
+static int			hn_vfmap_size;
+static struct ifnet		**hn_vfmap;
+
 static const uint8_t
 hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
@@ -958,7 +982,7 @@ hn_update_vf_task(void *arg, int pending __unused)
 {
 	struct hn_update_vf *uv = arg;
 
-	uv->rxr->hn_vf = uv->vf;
+	uv->rxr->hn_rxvf_ifp = uv->vf;
 }
 
 static void
@@ -981,37 +1005,50 @@ hn_update_vf(struct hn_softc *sc, struct ifnet *vf)
 			uv.vf = vf;
 			vmbus_chan_run_task(rxr->hn_chan, &task);
 		} else {
-			rxr->hn_vf = vf;
+			rxr->hn_rxvf_ifp = vf;
 		}
 	}
 }
 
-static void
-hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf)
+static __inline bool
+hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
 {
-	struct ifnet *hn_ifp;
+	const struct ifnet *hn_ifp;
 
-	HN_LOCK(sc);
-
-	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
-		goto out;
-
 	hn_ifp = sc->hn_ifp;
 
 	if (ifp == hn_ifp)
-		goto out;
+		return (false);
 
 	if (ifp->if_alloctype != IFT_ETHER)
-		goto out;
+		return (false);
 
 	/* Ignore lagg/vlan interfaces */
 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
 	    strcmp(ifp->if_dname, "vlan") == 0)
-		goto out;
+		return (false);
 
 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
+		return (false);
+
+	return (true);
+}
+
+static void
+hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf)
+{
+	struct ifnet *hn_ifp;
+
+	HN_LOCK(sc);
+
+	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
 		goto out;
 
+	if (!hn_ismyvf(sc, ifp))
+		goto out;
+
+	hn_ifp = sc->hn_ifp;
+
 	/* Now we're sure 'ifp' is a real VF device. */
 	if (vf) {
 		if (sc->hn_flags & HN_FLAG_VF)
@@ -1024,7 +1061,7 @@ hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool
 			goto out;
 
 		sc->hn_flags &= ~HN_FLAG_VF;
-		if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
+		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
 			hn_rxfilter_config(sc);
 		else
 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
@@ -1039,7 +1076,7 @@ hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool
 		hn_suspend_mgmt(sc);
 		sc->hn_link_flags &=
 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
-		if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
+		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
 	} else {
 		hn_resume_mgmt(sc);
 	}
@@ -1069,6 +1106,85 @@ hn_ifaddr_event(void *arg, struct ifnet *ifp)
 	hn_set_vf(arg, ifp, ifp->if_flags & IFF_UP);
 }
 
+static void
+hn_ifnet_attevent(void *xsc, struct ifnet *ifp)
+{
+	struct hn_softc *sc = xsc;
+
+	HN_LOCK(sc);
+
+	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
+		goto done;
+
+	if (!hn_ismyvf(sc, ifp))
+		goto done;
+
+	if (sc->hn_vf_ifp != NULL) {
+		if_printf(sc->hn_ifp, "%s was attached as VF\n",
+		    sc->hn_vf_ifp->if_xname);
+		goto done;
+	}
+
+	rm_wlock(&hn_vfmap_lock);
+
+	if (ifp->if_index >= hn_vfmap_size) {
+		struct ifnet **newmap;
+		int newsize;
+
+		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
+		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
+		    M_WAITOK | M_ZERO);
+
+		memcpy(newmap, hn_vfmap,
+		    sizeof(struct ifnet *) * hn_vfmap_size);
+		free(hn_vfmap, M_DEVBUF);
+		hn_vfmap = newmap;
+		hn_vfmap_size = newsize;
+	}
+	KASSERT(hn_vfmap[ifp->if_index] == NULL,
+	    ("%s: ifindex %d was mapped to %s",
+	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
+	hn_vfmap[ifp->if_index] = sc->hn_ifp;
+
+	rm_wunlock(&hn_vfmap_lock);
+
+	sc->hn_vf_ifp = ifp;
+done:
+	HN_UNLOCK(sc);
+}
+
+static void
+hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
+{
+	struct hn_softc *sc = xsc;
+
+	HN_LOCK(sc);
+
+	if (sc->hn_vf_ifp == NULL)
+		goto done;
+
+	if (!hn_ismyvf(sc, ifp))
+		goto done;
+
+	sc->hn_vf_ifp = NULL;
+
+	rm_wlock(&hn_vfmap_lock);
+
+	KASSERT(ifp->if_index < hn_vfmap_size,
+	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
+	if (hn_vfmap[ifp->if_index] != NULL) {
+		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
+		    ("%s: ifindex %d was mapped to %s",
+		     ifp->if_xname, ifp->if_index,
+		     hn_vfmap[ifp->if_index]->if_xname));
+		hn_vfmap[ifp->if_index] = NULL;
+	}
+
+	rm_wunlock(&hn_vfmap_lock);
+done:
+	HN_UNLOCK(sc);
+}
+
 /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
 static const struct hyperv_guid g_net_vsc_device_type = {
 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
@@ -1300,6 +1416,9 @@ hn_attach(device_t dev)
 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
 	    hn_vf_sysctl, "A", "Virtual Function's name");
+	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
+	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
+	    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
 
 	/*
 	 * Setup the ifmedia, which has been initialized earlier.
@@ -1395,10 +1514,14 @@ hn_attach(device_t dev)
 
 	sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
 	    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
-
 	sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
 	    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
 
+	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
+	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
+	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
+	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
+
 	return (0);
 failed:
 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
@@ -1411,13 +1534,26 @@ static int
 hn_detach(device_t dev)
 {
 	struct hn_softc *sc = device_get_softc(dev);
-	struct ifnet *ifp = sc->hn_ifp;
+	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
 
 	if (sc->hn_ifaddr_evthand != NULL)
 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
 	if (sc->hn_ifnet_evthand != NULL)
 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
+	if (sc->hn_ifnet_atthand != NULL) {
+		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
+		    sc->hn_ifnet_atthand);
+	}
+	if (sc->hn_ifnet_dethand != NULL) {
+		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
+		    sc->hn_ifnet_dethand);
+	}
 
+	vf_ifp = sc->hn_vf_ifp;
+	__compiler_membar();
+	if (vf_ifp != NULL)
+		hn_ifnet_detevent(sc, vf_ifp);
+
 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
 		/*
 		 * In case that the vmbus missed the orphan handler
@@ -2315,7 +2451,7 @@ hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int
 	int hash_type = M_HASHTYPE_OPAQUE;
 
 	/* If the VF is active, inject the packet through the VF */
-	ifp = rxr->hn_vf ? rxr->hn_vf : rxr->hn_ifp;
+	ifp = rxr->hn_rxvf_ifp ? rxr->hn_rxvf_ifp : rxr->hn_ifp;
 
 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
 		/*
@@ -3284,12 +3420,12 @@ static int
 hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
 {
 	struct hn_softc *sc = arg1;
-	char vf_name[128];
+	char vf_name[IFNAMSIZ + 1];
 	struct ifnet *vf;
 
 	HN_LOCK(sc);
 	vf_name[0] = '\0';
-	vf = sc->hn_rx_ring[0].hn_vf;
+	vf = sc->hn_vf_ifp;
 	if (vf != NULL)
 		snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf));
 	HN_UNLOCK(sc);
@@ -3297,6 +3433,110 @@ hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
 }
 
 static int
+hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct hn_softc *sc = arg1;
+	char vf_name[IFNAMSIZ + 1];
+	struct ifnet *vf;
+
+	HN_LOCK(sc);
+	vf_name[0] = '\0';
+	vf = sc->hn_rx_ring[0].hn_rxvf_ifp;
+	if (vf != NULL)
+		snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf));
+	HN_UNLOCK(sc);
+	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
+}
+
+static int
+hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct rm_priotracker pt;
+	struct sbuf *sb;
+	int error, i;
+	bool first;
+
+	error = sysctl_wire_old_buffer(req, 0);
+	if (error != 0)
+		return (error);
+
+	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
+	if (sb == NULL)
+		return (ENOMEM);
+
+	rm_rlock(&hn_vfmap_lock, &pt);
+
+	first = true;
+	for (i = 0; i < hn_vfmap_size; ++i) {
+		struct ifnet *ifp;
+
+		if (hn_vfmap[i] == NULL)
+			continue;
+
+		ifp = ifnet_byindex(i);
+		if (ifp != NULL) {
+			if (first)
+				sbuf_printf(sb, "%s", ifp->if_xname);
+			else
+				sbuf_printf(sb, " %s", ifp->if_xname);
+			first = false;
+		}
+	}
+
+	rm_runlock(&hn_vfmap_lock, &pt);
+
+	error = sbuf_finish(sb);
+	sbuf_delete(sb);
+	return (error);
+}
+
+static int
+hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct rm_priotracker pt;
+	struct sbuf *sb;
+	int error, i;
+	bool first;
+
+	error = sysctl_wire_old_buffer(req, 0);
+	if (error != 0)
+		return (error);
+
+	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
+	if (sb == NULL)
+		return (ENOMEM);
+
+	rm_rlock(&hn_vfmap_lock, &pt);
+
+	first = true;
+	for (i = 0; i < hn_vfmap_size; ++i) {
+		struct ifnet *ifp, *hn_ifp;
+
+		hn_ifp = hn_vfmap[i];
+		if (hn_ifp == NULL)
+			continue;
+
+		ifp = ifnet_byindex(i);
+		if (ifp != NULL) {
+			if (first) {
+				sbuf_printf(sb, "%s:%s", ifp->if_xname,
+				    hn_ifp->if_xname);
+			} else {
+				sbuf_printf(sb, " %s:%s", ifp->if_xname,
+				    hn_ifp->if_xname);
+			}
+			first = false;
+		}
+	}
+
+	rm_runlock(&hn_vfmap_lock, &pt);
+
+	error = sbuf_finish(sb);
+	sbuf_delete(sb);
+	return (error);
+}
+
+static int
 hn_check_iplen(const struct mbuf *m, int hoff)
 {
 	const struct ip *ip;
@@ -5781,11 +6021,19 @@ hn_chan_callback(struct vmbus_channel *chan, void *xrx
 }
 
 static void
-hn_tx_taskq_create(void *arg __unused)
+hn_sysinit(void *arg __unused)
 {
 	int i;
 
 	/*
+	 * Initialize VF map.
+	 */
+	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
+	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
+	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
+	    M_WAITOK | M_ZERO);
+
+	/*
 	 * Fix the # of TX taskqueues.
 	 */
 	if (hn_tx_taskq_cnt <= 0)
@@ -5821,11 +6069,10 @@ hn_tx_taskq_create(void *arg __unused)
 		    "hn tx%d", i);
 	}
 }
-SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
-    hn_tx_taskq_create, NULL);
+SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
 
 static void
-hn_tx_taskq_destroy(void *arg __unused)
+hn_sysuninit(void *arg __unused)
 {
 
 	if (hn_tx_taskque != NULL) {
@@ -5835,6 +6082,9 @@ hn_tx_taskq_destroy(void *arg __unused)
 			taskqueue_free(hn_tx_taskque[i]);
 		free(hn_tx_taskque, M_DEVBUF);
 	}
+
+	if (hn_vfmap != NULL)
+		free(hn_vfmap, M_DEVBUF);
+	rm_destroy(&hn_vfmap_lock);
 }
-SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
-    hn_tx_taskq_destroy, NULL);
+SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);

Modified: stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/if_hnvar.h	Mon Jul 31 05:23:32 2017	(r321758)
+++ stable/10/sys/dev/hyperv/netvsc/if_hnvar.h	Mon Jul 31 06:27:43 2017	(r321759)
@@ -59,7 +59,7 @@ struct hn_tx_ring;
 
 struct hn_rx_ring {
 	struct ifnet	*hn_ifp;
-	struct ifnet	*hn_vf;		/* SR-IOV VF */
+	struct ifnet	*hn_rxvf_ifp;	/* SR-IOV VF for RX */
 	struct hn_tx_ring *hn_txr;
 	void		*hn_pktbuf;
 	int		hn_pktbuf_len;
@@ -175,6 +175,7 @@ struct hn_tx_ring {
 struct hn_softc {
 	struct ifnet    *hn_ifp;
 	struct arpcom   arpcom;
+	struct ifnet	*hn_vf_ifp;	/* SR-IOV VF */
 	struct ifmedia	hn_media;
 	device_t        hn_dev;
 	int             hn_if_flags;
@@ -239,6 +240,8 @@ struct hn_softc {
 
 	eventhandler_tag	hn_ifaddr_evthand;
 	eventhandler_tag	hn_ifnet_evthand;
+	eventhandler_tag	hn_ifnet_atthand;
+	eventhandler_tag	hn_ifnet_dethand;
 };
 
 #define HN_FLAG_RXBUF_CONNECTED		0x0001



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