hyperv/hn: Export VF list and VF-HN mapping

The VF-HN map will be used later on to implement "transparent VF".

MFC after:	3 days
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D11618
This commit is contained in:
Sepherosa Ziehau 2017-07-24 03:52:32 +00:00
parent 8819ad852f
commit 499c3e1739
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=321407
2 changed files with 283 additions and 30 deletions

View File

@ -69,6 +69,8 @@ __FBSDID("$FreeBSD$");
#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 @@ __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
@ -255,6 +259,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 *,
@ -303,6 +312,9 @@ static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
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 @@ 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;
#ifndef RSS
static const uint8_t
hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
@ -971,7 +995,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
@ -994,11 +1018,35 @@ 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 __inline bool
hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
{
const struct ifnet *hn_ifp;
hn_ifp = sc->hn_ifp;
if (ifp == hn_ifp)
return (false);
if (ifp->if_alloctype != IFT_ETHER)
return (false);
/* Ignore lagg/vlan interfaces */
if (strcmp(ifp->if_dname, "lagg") == 0 ||
strcmp(ifp->if_dname, "vlan") == 0)
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)
{
@ -1009,22 +1057,11 @@ hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf)
if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
goto out;
if (!hn_ismyvf(sc, ifp))
goto out;
hn_ifp = sc->hn_ifp;
if (ifp == hn_ifp)
goto out;
if (ifp->if_alloctype != IFT_ETHER)
goto out;
/* Ignore lagg/vlan interfaces */
if (strcmp(ifp->if_dname, "lagg") == 0 ||
strcmp(ifp->if_dname, "vlan") == 0)
goto out;
if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
goto out;
/* Now we're sure 'ifp' is a real VF device. */
if (vf) {
if (sc->hn_flags & HN_FLAG_VF)
@ -1037,7 +1074,7 @@ hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf)
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_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf)
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_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,
@ -1322,6 +1438,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.
@ -1412,10 +1531,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)
@ -1428,12 +1551,25 @@ 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)) {
/*
@ -2326,7 +2462,7 @@ hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
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,18 +3437,122 @@ 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);
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_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)
{
@ -5829,10 +6069,18 @@ hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
}
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.
*/
@ -5869,11 +6117,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) {
@ -5883,6 +6130,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);

View File

@ -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;
@ -174,6 +174,7 @@ struct hn_tx_ring {
*/
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 @@ 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