Author: sephe
Date: Mon Jul 24 03:52:32 2017
New Revision: 321407
URL: https://svnweb.freebsd.org/changeset/base/321407

Log:
  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

Modified:
  head/sys/dev/hyperv/netvsc/if_hn.c
  head/sys/dev/hyperv/netvsc/if_hnvar.h

Modified: head/sys/dev/hyperv/netvsc/if_hn.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hn.c  Mon Jul 24 03:32:10 2017        
(r321406)
+++ head/sys/dev/hyperv/netvsc/if_hn.c  Mon Jul 24 03:52:32 2017        
(r321407)
@@ -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_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 *);
@@ -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,37 +1018,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)
@@ -1037,7 +1074,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);
@@ -1052,7 +1089,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);
        }
@@ -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,13 +1551,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
@@ -2326,7 +2462,7 @@ hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int
        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,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);
@@ -3314,6 +3450,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;
@@ -5829,11 +6069,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)
@@ -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);

Modified: head/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hnvar.h       Mon Jul 24 03:32:10 2017        
(r321406)
+++ head/sys/dev/hyperv/netvsc/if_hnvar.h       Mon Jul 24 03:52:32 2017        
(r321407)
@@ -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
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to