Author: sephe
Date: Fri Nov 11 03:22:22 2016
New Revision: 308497
URL: https://svnweb.freebsd.org/changeset/base/308497

Log:
  MFC 307843
  
      hyperv/hn: Fix RX filter settings.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8313

Modified:
  stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
  stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  stable/10/sys/net/rndis.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h        Fri Nov 11 03:15:52 
2016        (r308496)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h        Fri Nov 11 03:22:22 
2016        (r308497)
@@ -233,6 +233,7 @@ struct hn_softc {
        struct sysctl_oid *hn_rx_sysctl_tree;
        struct vmbus_xact_ctx *hn_xact;
        uint32_t        hn_nvs_ver;
+       uint32_t        hn_rx_filter;
 
        struct taskqueue        *hn_mgmt_taskq;
        struct taskqueue        *hn_mgmt_taskq0;

Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c     Fri Nov 11 
03:15:52 2016        (r308496)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c     Fri Nov 11 
03:22:22 2016        (r308497)
@@ -328,6 +328,7 @@ static int hn_tx_conf_int_sysctl(SYSCTL_
 static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
+static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_check_iplen(const struct mbuf *, int);
@@ -369,6 +370,7 @@ static int netvsc_detach(device_t dev);
 static void hn_link_status(struct hn_softc *);
 static int hn_sendpkt_rndis_sglist(struct hn_tx_ring *, struct hn_txdesc *);
 static int hn_sendpkt_rndis_chim(struct hn_tx_ring *, struct hn_txdesc *);
+static int hn_set_rxfilter(struct hn_softc *);
 
 static void hn_nvs_handle_notify(struct hn_softc *sc,
                const struct vmbus_chanpkt_hdr *pkt);
@@ -457,6 +459,43 @@ hn_sendpkt_rndis_chim(struct hn_tx_ring 
 }
 
 static int
+hn_set_rxfilter(struct hn_softc *sc)
+{
+       struct ifnet *ifp = sc->hn_ifp;
+       uint32_t filter;
+       int error = 0;
+
+       HN_LOCK_ASSERT(sc);
+
+       if (ifp->if_flags & IFF_PROMISC) {
+               filter = NDIS_PACKET_TYPE_PROMISCUOUS;
+       } else {
+               filter = NDIS_PACKET_TYPE_DIRECTED;
+               if (ifp->if_flags & IFF_BROADCAST)
+                       filter |= NDIS_PACKET_TYPE_BROADCAST;
+#ifdef notyet
+               /*
+                * See the comment in SIOCADDMULTI/SIOCDELMULTI.
+                */
+               /* TODO: support multicast list */
+               if ((ifp->if_flags & IFF_ALLMULTI) ||
+                   !TAILQ_EMPTY(&ifp->if_multiaddrs))
+                       filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
+#else
+               /* Always enable ALLMULTI */
+               filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
+#endif
+       }
+
+       if (sc->hn_rx_filter != filter) {
+               error = hn_rndis_set_rxfilter(sc, filter);
+               if (!error)
+                       sc->hn_rx_filter = filter;
+       }
+       return (error);
+}
+
+static int
 hn_get_txswq_depth(const struct hn_tx_ring *txr)
 {
 
@@ -744,6 +783,9 @@ netvsc_attach(device_t dev)
        SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
            CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
            hn_hwassist_sysctl, "A", "hwassist");
+       SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
+           CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
+           hn_rxfilter_sysctl, "A", "rxfilter");
        SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
            CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
            hn_rss_key_sysctl, "IU", "RSS key");
@@ -1860,31 +1902,13 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
                }
 
                if (ifp->if_flags & IFF_UP) {
-                       /*
-                        * If only the state of the PROMISC flag changed,
-                        * then just use the 'set promisc mode' command
-                        * instead of reinitializing the entire NIC. Doing
-                        * a full re-init means reloading the firmware and
-                        * waiting for it to start up, which may take a
-                        * second or two.
-                        */
-#ifdef notyet
-                       /* Fixme:  Promiscuous mode? */
-                       if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
-                           ifp->if_flags & IFF_PROMISC &&
-                           !(sc->hn_if_flags & IFF_PROMISC)) {
-                               /* do something here for Hyper-V */
-                       } else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
-                           !(ifp->if_flags & IFF_PROMISC) &&
-                           sc->hn_if_flags & IFF_PROMISC) {
-                               /* do something here for Hyper-V */
-                       } else
-#endif
+                       if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+                               hn_set_rxfilter(sc);
+                       else
                                hn_init_locked(sc);
                } else {
-                       if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+                       if (ifp->if_drv_flags & IFF_DRV_RUNNING)
                                hn_stop(sc);
-                       }
                }
                sc->hn_if_flags = ifp->if_flags;
 
@@ -1942,12 +1966,27 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
 
        case SIOCADDMULTI:
        case SIOCDELMULTI:
-               /* Always all-multi */
+#ifdef notyet
                /*
-                * TODO:
-                * Enable/disable all-multi according to the emptiness of
-                * the mcast address list.
+                * XXX
+                * Multicast uses mutex, while RNDIS RX filter setting
+                * sleeps.  We workaround this by always enabling
+                * ALLMULTI.  ALLMULTI would actually always be on, even
+                * if we supported the SIOCADDMULTI/SIOCDELMULTI, since
+                * we don't support multicast address list configuration
+                * for this driver.
                 */
+               HN_LOCK(sc);
+
+               if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
+                       HN_UNLOCK(sc);
+                       break;
+               }
+               if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+                       hn_set_rxfilter(sc);
+
+               HN_UNLOCK(sc);
+#endif
                break;
 
        case SIOCSIFMEDIA:
@@ -2055,8 +2094,8 @@ hn_init_locked(struct hn_softc *sc)
        if (ifp->if_drv_flags & IFF_DRV_RUNNING)
                return;
 
-       /* TODO: add hn_rx_filter */
-       hn_rndis_set_rxfilter(sc, NDIS_PACKET_TYPE_PROMISCUOUS);
+       /* Configure RX filter */
+       hn_set_rxfilter(sc);
 
        /* Clear OACTIVE bit. */
        atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
@@ -2383,6 +2422,21 @@ hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
 }
 
 static int
+hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
+{
+       struct hn_softc *sc = arg1;
+       char filter_str[128];
+       uint32_t filter;
+
+       HN_LOCK(sc);
+       filter = sc->hn_rx_filter;
+       HN_UNLOCK(sc);
+       snprintf(filter_str, sizeof(filter_str), "%b", filter,
+           NDIS_PACKET_TYPES);
+       return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
+}
+
+static int
 hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
 {
        struct hn_softc *sc = arg1;
@@ -3803,6 +3857,7 @@ hn_suspend_data(struct hn_softc *sc)
         * Disable RX by clearing RX filter.
         */
        hn_rndis_set_rxfilter(sc, 0);
+       sc->hn_rx_filter = 0;
 
        /*
         * Give RNDIS enough time to flush all pending data packets.
@@ -3890,9 +3945,8 @@ hn_resume_data(struct hn_softc *sc)
 
        /*
         * Re-enable RX.
-        * TODO: add hn_rx_filter.
         */
-       hn_rndis_set_rxfilter(sc, NDIS_PACKET_TYPE_PROMISCUOUS);
+       hn_set_rxfilter(sc);
 
        /*
         * Make sure to clear suspend status on "all" TX rings,

Modified: stable/10/sys/net/rndis.h
==============================================================================
--- stable/10/sys/net/rndis.h   Fri Nov 11 03:15:52 2016        (r308496)
+++ stable/10/sys/net/rndis.h   Fri Nov 11 03:22:22 2016        (r308497)
@@ -351,7 +351,7 @@ struct rndis_keepalive_comp {
        uint32_t rm_status;
 };
 
-/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
+/* Packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
 #define        NDIS_PACKET_TYPE_DIRECTED               0x00000001
 #define        NDIS_PACKET_TYPE_MULTICAST              0x00000002
 #define        NDIS_PACKET_TYPE_ALL_MULTICAST          0x00000004
@@ -365,6 +365,14 @@ struct rndis_keepalive_comp {
 #define        NDIS_PACKET_TYPE_FUNCTIONAL             0x00004000
 #define        NDIS_PACKET_TYPE_MAC_FRAME              0x00008000
 
+/*
+ * Packet filter description for use with printf(9) %b identifier.
+ */
+#define        NDIS_PACKET_TYPES                               \
+       "\20\1DIRECT\2MULTICAST\3ALLMULTI\4BROADCAST"   \
+       "\5SRCROUTE\6PROMISC\7SMT\10ALLLOCAL"           \
+       "\11GROUP\12ALLFUNC\13FUNC\14MACFRAME"
+
 /* RNDIS offsets */
 #define        RNDIS_HEADER_OFFSET     ((uint32_t)sizeof(struct rndis_msghdr))
 #define        RNDIS_DATA_OFFSET       \
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to