svn commit: r321759 - stable/10/sys/dev/hyperv/netvsc
Sepherosa Ziehau
sephe at FreeBSD.org
Mon Jul 31 06:27:44 UTC 2017
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
More information about the svn-src-all
mailing list