svn commit: r308494 - in stable/10/sys: dev/hyperv/netvsc net
Sepherosa Ziehau
sephe at FreeBSD.org
Fri Nov 11 03:03:56 UTC 2016
Author: sephe
Date: Fri Nov 11 03:03:54 2016
New Revision: 308494
URL: https://svnweb.freebsd.org/changeset/base/308494
Log:
MFC 307710-307712,307714
307710
hyperv/hn: Always query RSS capabilities.
- This avoid distributing NDIS version check.
- Only NDIS 6.20 required (earlier NDIS uses different indirect table
format).
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8291
307711
hyperv/hn: Check NVS version for HASHVAL pktinfo on sending path.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8293
307712
hyperv/hn: Add network change support.
Currently the network change is simulated by link status changes.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8295
307714
hyperv/hn: Function renaming; consistent w/ hardware capabilities query.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8296
Modified:
stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
stable/10/sys/dev/hyperv/netvsc/if_hnreg.h
stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
stable/10/sys/dev/hyperv/netvsc/ndis.h
stable/10/sys/net/rndis.h
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c Fri Nov 11 02:42:53 2016 (r308493)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c Fri Nov 11 03:03:54 2016 (r308494)
@@ -543,8 +543,9 @@ hn_nvs_init(struct hn_softc *sc)
if (error) {
if_printf(sc->hn_ifp, "reinit NVS version 0x%x "
"failed: %d\n", sc->hn_nvs_ver, error);
+ return (error);
}
- return (error);
+ goto done;
}
/*
@@ -566,11 +567,16 @@ hn_nvs_init(struct hn_softc *sc)
HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
}
- return (0);
+ goto done;
}
}
if_printf(sc->hn_ifp, "no NVS available\n");
return (ENXIO);
+
+done:
+ if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
+ sc->hn_caps |= HN_CAP_HASHVAL;
+ return (0);
}
int
Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h Fri Nov 11 02:42:53 2016 (r308493)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h Fri Nov 11 03:03:54 2016 (r308494)
@@ -208,7 +208,6 @@ struct hn_softc {
struct arpcom arpcom;
struct ifmedia hn_media;
device_t hn_dev;
- int hn_carrier;
int hn_if_flags;
struct sx hn_lock;
struct vmbus_channel *hn_prichan;
@@ -237,6 +236,9 @@ struct hn_softc {
struct taskqueue *hn_mgmt_taskq;
struct taskqueue *hn_mgmt_taskq0;
struct task hn_link_task;
+ struct task hn_netchg_init;
+ struct timeout_task hn_netchg_status;
+ uint32_t hn_link_flags; /* HN_LINK_FLAG_ */
uint32_t hn_caps; /* HN_CAP_ */
uint32_t hn_flags; /* HN_FLAG_ */
@@ -270,6 +272,10 @@ struct hn_softc {
#define HN_CAP_UDP6CS 0x0040
#define HN_CAP_TSO4 0x0080
#define HN_CAP_TSO6 0x0100
+#define HN_CAP_HASHVAL 0x0200
+
+#define HN_LINK_FLAG_LINKUP 0x0001
+#define HN_LINK_FLAG_NETCHG 0x0002
/*
* Externs
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 02:42:53 2016 (r308493)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Fri Nov 11 03:03:54 2016 (r308494)
@@ -337,6 +337,8 @@ static void hn_destroy_tx_data(struct hn
static void hn_start_taskfunc(void *, int);
static void hn_start_txeof_taskfunc(void *, int);
static void hn_link_taskfunc(void *, int);
+static void hn_netchg_init_taskfunc(void *, int);
+static void hn_netchg_status_taskfunc(void *, int);
static void hn_suspend_mgmt_taskfunc(void *, int);
static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
static int hn_create_rx_data(struct hn_softc *sc, int);
@@ -362,6 +364,7 @@ static void hn_rx_drain(struct vmbus_cha
static void hn_tx_resume(struct hn_softc *, int);
static void hn_tx_ring_qflush(struct hn_tx_ring *);
static int netvsc_detach(device_t dev);
+static void hn_link_status(struct hn_softc *);
static void hn_nvs_handle_notify(struct hn_softc *sc,
const struct vmbus_chanpkt_hdr *pkt);
@@ -484,7 +487,7 @@ hn_ifmedia_sts(struct ifnet *ifp, struct
ifmr->ifm_status = IFM_AVALID;
ifmr->ifm_active = IFM_ETHER;
- if (!sc->hn_carrier) {
+ if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
ifmr->ifm_active |= IFM_NONE;
return;
}
@@ -579,6 +582,9 @@ netvsc_attach(device_t dev)
taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
device_get_nameunit(dev));
TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
+ TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
+ TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
+ hn_netchg_status_taskfunc, sc);
/*
* Allocate ifnet and setup its name earlier, so that if_printf
@@ -824,10 +830,8 @@ netvsc_shutdown(device_t dev)
}
static void
-hn_link_taskfunc(void *xsc, int pending __unused)
+hn_link_status(struct hn_softc *sc)
{
- struct hn_softc *sc = xsc;
- struct ifnet *ifp = sc->hn_ifp;
uint32_t link_status;
int error;
@@ -838,11 +842,51 @@ hn_link_taskfunc(void *xsc, int pending
}
if (link_status == NDIS_MEDIA_STATE_CONNECTED)
- sc->hn_carrier = 1;
+ sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
else
- sc->hn_carrier = 0;
- if_link_state_change(ifp,
- sc->hn_carrier ? LINK_STATE_UP : LINK_STATE_DOWN);
+ sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
+ if_link_state_change(sc->hn_ifp,
+ (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
+ LINK_STATE_UP : LINK_STATE_DOWN);
+}
+
+static void
+hn_link_taskfunc(void *xsc, int pending __unused)
+{
+ struct hn_softc *sc = xsc;
+
+ if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
+ return;
+ hn_link_status(sc);
+}
+
+static void
+hn_netchg_init_taskfunc(void *xsc, int pending __unused)
+{
+ struct hn_softc *sc = xsc;
+
+ /* Prevent any link status checks from running. */
+ sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
+
+ /*
+ * Fake up a [link down --> link up] state change; 5 seconds
+ * delay is used, which closely simulates miibus reaction
+ * upon link down event.
+ */
+ sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
+ if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
+ taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
+ &sc->hn_netchg_status, 5 * hz);
+}
+
+static void
+hn_netchg_status_taskfunc(void *xsc, int pending __unused)
+{
+ struct hn_softc *sc = xsc;
+
+ /* Re-allow link status checks. */
+ sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
+ hn_link_status(sc);
}
void
@@ -853,6 +897,14 @@ hn_link_status_update(struct hn_softc *s
taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
}
+void
+hn_network_change(struct hn_softc *sc)
+{
+
+ if (sc->hn_mgmt_taskq != NULL)
+ taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
+}
+
static __inline int
hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
@@ -2253,7 +2305,8 @@ hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
"\006UDP4CS"
"\007UDP6CS"
"\010TSO4"
- "\011TSO6");
+ "\011TSO6"
+ "\012HASHVAL");
return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
}
@@ -3028,12 +3081,15 @@ hn_fixup_tx_data(struct hn_softc *sc)
if (sc->hn_caps & HN_CAP_UDP6CS)
csum_assist |= CSUM_IP6_UDP;
#endif
-
for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
- if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) {
- /* Support HASHVAL pktinfo on TX path. */
+ if (sc->hn_caps & HN_CAP_HASHVAL) {
+ /*
+ * Support HASHVAL pktinfo on TX path.
+ */
+ if (bootverbose)
+ if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
}
@@ -3428,20 +3484,19 @@ hn_synth_alloc_subchans(struct hn_softc
int nchan, rxr_cnt, error;
nchan = *nsubch + 1;
- if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30 || nchan == 1) {
+ if (nchan == 1) {
/*
- * Either RSS is not supported, or multiple RX/TX rings
- * are not requested.
+ * Multiple RX/TX rings are not requested.
*/
*nsubch = 0;
return (0);
}
/*
- * Get RSS capabilities, e.g. # of RX rings, and # of indirect
+ * Query RSS capabilities, e.g. # of RX rings, and # of indirect
* table entries.
*/
- error = hn_rndis_get_rsscaps(sc, &rxr_cnt);
+ error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
if (error) {
/* No RSS; this is benign. */
*nsubch = 0;
@@ -3736,6 +3791,8 @@ hn_suspend_mgmt(struct hn_softc *sc)
/*
* Make sure that all pending management tasks are completed.
*/
+ taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
+ taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
taskqueue_drain_all(sc->hn_mgmt_taskq0);
}
@@ -3813,10 +3870,11 @@ hn_resume_mgmt(struct hn_softc *sc)
{
/*
- * Kick off link status check.
+ * Kick off network change detection, which will
+ * do link status check too.
*/
sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
- hn_link_status_update(sc);
+ hn_network_change(sc);
}
static void
Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c Fri Nov 11 02:42:53 2016 (r308493)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c Fri Nov 11 03:03:54 2016 (r308494)
@@ -159,6 +159,7 @@ static void
hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
{
const struct rndis_status_msg *msg;
+ int ofs;
if (dlen < sizeof(*msg)) {
if_printf(sc->hn_ifp, "invalid RNDIS status\n");
@@ -177,8 +178,19 @@ hv_rf_receive_indicate_status(struct hn_
break;
case RNDIS_STATUS_NETWORK_CHANGE:
- /* TODO */
- if_printf(sc->hn_ifp, "network changed\n");
+ ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
+ if (dlen < ofs + msg->rm_stbuflen ||
+ msg->rm_stbuflen < sizeof(uint32_t)) {
+ if_printf(sc->hn_ifp, "network changed\n");
+ } else {
+ uint32_t change;
+
+ memcpy(&change, ((const uint8_t *)msg) + ofs,
+ sizeof(change));
+ if_printf(sc->hn_ifp, "network changed, change %u\n",
+ change);
+ }
+ hn_network_change(sc);
break;
default:
@@ -737,7 +749,7 @@ done:
}
int
-hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
+hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt)
{
struct ndis_rss_caps in, caps;
size_t caps_len;
@@ -745,15 +757,13 @@ hn_rndis_get_rsscaps(struct hn_softc *sc
*rxr_cnt = 0;
+ if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_20)
+ return (EOPNOTSUPP);
+
memset(&in, 0, sizeof(in));
in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
- if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30) {
- in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_1;
- in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE_6_0;
- } else {
- in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
- in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
- }
+ in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
+ in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
caps_len = NDIS_RSS_CAPS_SIZE;
error = hn_rndis_query2(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
@@ -1028,10 +1038,12 @@ hn_rndis_conf_rss(struct hn_softc *sc, u
int error;
/*
- * Only NDIS 6.30+ is supported.
+ * Only NDIS 6.20+ is supported:
+ * We only support 4bytes element in indirect table, which has been
+ * adopted since NDIS 6.20.
*/
- KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
- ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
+ KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_20,
+ ("NDIS 6.20+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
/*
* NOTE:
Modified: stable/10/sys/dev/hyperv/netvsc/if_hnreg.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/if_hnreg.h Fri Nov 11 02:42:53 2016 (r308493)
+++ stable/10/sys/dev/hyperv/netvsc/if_hnreg.h Fri Nov 11 03:03:54 2016 (r308494)
@@ -36,6 +36,7 @@
* NDIS protocol version numbers
*/
#define HN_NDIS_VERSION_6_1 0x00060001
+#define HN_NDIS_VERSION_6_20 0x00060014
#define HN_NDIS_VERSION_6_30 0x0006001e
#define HN_NDIS_VERSION_MAJOR(ver) (((ver) & 0xffff0000) >> 16)
#define HN_NDIS_VERSION_MINOR(ver) ((ver) & 0xffff)
Modified: stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/if_hnvar.h Fri Nov 11 02:42:53 2016 (r308493)
+++ stable/10/sys/dev/hyperv/netvsc/if_hnvar.h Fri Nov 11 03:03:54 2016 (r308494)
@@ -122,7 +122,7 @@ void hn_rndis_detach(struct hn_softc *s
int hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags);
void *hn_rndis_pktinfo_append(struct rndis_packet_msg *,
size_t pktsize, size_t pi_dlen, uint32_t pi_type);
-int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
+int hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt);
int hn_rndis_get_eaddr(struct hn_softc *sc, uint8_t *eaddr);
int hn_rndis_get_linkstatus(struct hn_softc *sc,
uint32_t *link_status);
@@ -139,6 +139,7 @@ int hn_rxpkt(struct hn_rx_ring *rxr, co
const struct hn_recvinfo *info);
void hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr);
void hn_link_status_update(struct hn_softc *sc);
+void hn_network_change(struct hn_softc *sc);
extern struct hn_send_ctx hn_send_ctx_none;
Modified: stable/10/sys/dev/hyperv/netvsc/ndis.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/ndis.h Fri Nov 11 02:42:53 2016 (r308493)
+++ stable/10/sys/dev/hyperv/netvsc/ndis.h Fri Nov 11 03:03:54 2016 (r308494)
@@ -32,6 +32,10 @@
#define NDIS_MEDIA_STATE_CONNECTED 0
#define NDIS_MEDIA_STATE_DISCONNECTED 1
+#define NDIS_NETCHANGE_TYPE_POSSIBLE 1
+#define NDIS_NETCHANGE_TYPE_DEFINITE 2
+#define NDIS_NETCHANGE_TYPE_FROMMEDIA 3
+
#define NDIS_OFFLOAD_SET_NOCHG 0
#define NDIS_OFFLOAD_SET_ON 1
#define NDIS_OFFLOAD_SET_OFF 2
Modified: stable/10/sys/net/rndis.h
==============================================================================
--- stable/10/sys/net/rndis.h Fri Nov 11 02:42:53 2016 (r308493)
+++ stable/10/sys/net/rndis.h Fri Nov 11 03:03:54 2016 (r308494)
@@ -320,6 +320,10 @@ struct rndis_status_msg {
/* rndis_diag_info */
};
+/* stbuf offset from the beginning of rndis_status_msg. */
+#define RNDIS_STBUFOFFSET_ABS(ofs) \
+ ((ofs) + __offsetof(struct rndis_status_msg, rm_status))
+
/*
* Immediately after rndis_status_msg.rm_stbufoffset, if a control
* message is malformatted, or a packet message contains inappropriate
More information about the svn-src-stable
mailing list