Page MenuHomeFreeBSD

D11618.id30901.diff
No OneTemporary

D11618.id30901.diff

Index: sys/dev/hyperv/netvsc/if_hn.c
===================================================================
--- sys/dev/hyperv/netvsc/if_hn.c
+++ sys/dev/hyperv/netvsc/if_hn.c
@@ -69,6 +69,8 @@
#include <sys/module.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>
@@ -119,6 +121,8 @@
#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
@@ -255,6 +259,11 @@
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 *,
@@ -303,6 +312,9 @@
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 *);
@@ -502,9 +514,21 @@
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;
+
#ifndef RSS
static const uint8_t
hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
@@ -971,7 +995,7 @@
{
struct hn_update_vf *uv = arg;
- uv->rxr->hn_vf = uv->vf;
+ uv->rxr->hn_rxvf_ifp = uv->vf;
}
static void
@@ -994,37 +1018,50 @@
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;
-
- HN_LOCK(sc);
-
- if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
- goto out;
+ const struct ifnet *hn_ifp;
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)
@@ -1037,7 +1074,7 @@
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);
@@ -1052,7 +1089,7 @@
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);
}
@@ -1082,6 +1119,85 @@
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,
@@ -1322,6 +1438,9 @@
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.
@@ -1412,10 +1531,14 @@
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)
@@ -1428,12 +1551,25 @@
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)) {
/*
@@ -2326,7 +2462,7 @@
int hash_type;
/* 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) {
/*
@@ -3301,12 +3437,28 @@
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_vf_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_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_vf;
+ 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);
@@ -3314,6 +3466,94 @@
}
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;
@@ -5829,11 +6069,19 @@
}
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)
@@ -5869,11 +6117,10 @@
"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) {
@@ -5883,6 +6130,9 @@
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);
Index: sys/dev/hyperv/netvsc/if_hnvar.h
===================================================================
--- sys/dev/hyperv/netvsc/if_hnvar.h
+++ sys/dev/hyperv/netvsc/if_hnvar.h
@@ -59,7 +59,7 @@
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;
@@ -174,6 +174,7 @@
*/
struct hn_softc {
struct ifnet *hn_ifp;
+ struct ifnet *hn_vf_ifp; /* SR-IOV VF */
struct ifmedia hn_media;
device_t hn_dev;
int hn_if_flags;
@@ -238,6 +239,8 @@
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

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 22, 4:43 AM (21 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15550651
Default Alt Text
D11618.id30901.diff (12 KB)

Event Timeline