From owner-svn-src-all@freebsd.org Fri Oct 21 08:02:07 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 05E8AC1803D; Fri, 21 Oct 2016 08:02:07 +0000 (UTC) (envelope-from sephe@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D6CAA35B; Fri, 21 Oct 2016 08:02:06 +0000 (UTC) (envelope-from sephe@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u9L826KO048395; Fri, 21 Oct 2016 08:02:06 GMT (envelope-from sephe@FreeBSD.org) Received: (from sephe@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u9L825L1048389; Fri, 21 Oct 2016 08:02:05 GMT (envelope-from sephe@FreeBSD.org) Message-Id: <201610210802.u9L825L1048389@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: sephe set sender to sephe@FreeBSD.org using -f From: Sepherosa Ziehau Date: Fri, 21 Oct 2016 08:02:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r307712 - in head/sys: dev/hyperv/netvsc net X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Oct 2016 08:02:07 -0000 Author: sephe Date: Fri Oct 21 08:02:05 2016 New Revision: 307712 URL: https://svnweb.freebsd.org/changeset/base/307712 Log: hyperv/hn: Add network change support. Currently the network change is simulated by link status changes. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8295 Modified: head/sys/dev/hyperv/netvsc/hv_net_vsc.h head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c head/sys/dev/hyperv/netvsc/hv_rndis_filter.c head/sys/dev/hyperv/netvsc/if_hnvar.h head/sys/dev/hyperv/netvsc/ndis.h head/sys/net/rndis.h Modified: head/sys/dev/hyperv/netvsc/hv_net_vsc.h ============================================================================== --- head/sys/dev/hyperv/netvsc/hv_net_vsc.h Fri Oct 21 07:46:35 2016 (r307711) +++ head/sys/dev/hyperv/netvsc/hv_net_vsc.h Fri Oct 21 08:02:05 2016 (r307712) @@ -207,7 +207,6 @@ struct hn_softc { struct ifnet *hn_ifp; struct ifmedia hn_media; device_t hn_dev; - int hn_carrier; int hn_if_flags; struct sx hn_lock; struct vmbus_channel *hn_prichan; @@ -236,6 +235,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_ */ @@ -271,6 +273,9 @@ struct hn_softc { #define HN_CAP_TSO6 0x0100 #define HN_CAP_HASHVAL 0x0200 +#define HN_LINK_FLAG_LINKUP 0x0001 +#define HN_LINK_FLAG_NETCHG 0x0002 + /* * Externs */ Modified: head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c ============================================================================== --- head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Fri Oct 21 07:46:35 2016 (r307711) +++ head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Fri Oct 21 08:02:05 2016 (r307712) @@ -335,6 +335,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); @@ -360,6 +362,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); @@ -482,7 +485,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; } @@ -563,6 +566,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 @@ -808,10 +814,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; @@ -822,11 +826,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 @@ -837,6 +881,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) @@ -3719,6 +3771,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); } @@ -3796,10 +3850,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: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c ============================================================================== --- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c Fri Oct 21 07:46:35 2016 (r307711) +++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c Fri Oct 21 08:02:05 2016 (r307712) @@ -158,6 +158,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"); @@ -176,8 +177,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: Modified: head/sys/dev/hyperv/netvsc/if_hnvar.h ============================================================================== --- head/sys/dev/hyperv/netvsc/if_hnvar.h Fri Oct 21 07:46:35 2016 (r307711) +++ head/sys/dev/hyperv/netvsc/if_hnvar.h Fri Oct 21 08:02:05 2016 (r307712) @@ -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: head/sys/dev/hyperv/netvsc/ndis.h ============================================================================== --- head/sys/dev/hyperv/netvsc/ndis.h Fri Oct 21 07:46:35 2016 (r307711) +++ head/sys/dev/hyperv/netvsc/ndis.h Fri Oct 21 08:02:05 2016 (r307712) @@ -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: head/sys/net/rndis.h ============================================================================== --- head/sys/net/rndis.h Fri Oct 21 07:46:35 2016 (r307711) +++ head/sys/net/rndis.h Fri Oct 21 08:02:05 2016 (r307712) @@ -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