hyperv/hn: Fix RX filter settings.

MFC after:	1 week
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D8313
This commit is contained in:
sephe 2016-10-24 05:10:35 +00:00
parent 951eda704f
commit 5dd046f63c
3 changed files with 94 additions and 31 deletions

View File

@ -232,6 +232,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;

View File

@ -326,6 +326,7 @@ static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
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);
@ -367,6 +368,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);
@ -454,6 +456,43 @@ hn_sendpkt_rndis_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
&rndis, sizeof(rndis), &txd->send_ctx));
}
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)
{
@ -728,6 +767,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");
@ -1840,32 +1882,14 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
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;
HN_UNLOCK(sc);
@ -1922,12 +1946,27 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
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:
@ -2035,8 +2074,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);
@ -2362,6 +2401,21 @@ hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
}
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)
{
@ -3783,6 +3837,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.
@ -3870,9 +3925,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,

View File

@ -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 \