mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-15 10:17:20 +00:00
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
This commit is contained in:
parent
31f05efd89
commit
970ead008d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=307712
@ -207,7 +207,6 @@ struct hn_softc {
|
|||||||
struct ifnet *hn_ifp;
|
struct ifnet *hn_ifp;
|
||||||
struct ifmedia hn_media;
|
struct ifmedia hn_media;
|
||||||
device_t hn_dev;
|
device_t hn_dev;
|
||||||
int hn_carrier;
|
|
||||||
int hn_if_flags;
|
int hn_if_flags;
|
||||||
struct sx hn_lock;
|
struct sx hn_lock;
|
||||||
struct vmbus_channel *hn_prichan;
|
struct vmbus_channel *hn_prichan;
|
||||||
@ -236,6 +235,9 @@ struct hn_softc {
|
|||||||
struct taskqueue *hn_mgmt_taskq;
|
struct taskqueue *hn_mgmt_taskq;
|
||||||
struct taskqueue *hn_mgmt_taskq0;
|
struct taskqueue *hn_mgmt_taskq0;
|
||||||
struct task hn_link_task;
|
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_caps; /* HN_CAP_ */
|
||||||
uint32_t hn_flags; /* HN_FLAG_ */
|
uint32_t hn_flags; /* HN_FLAG_ */
|
||||||
@ -271,6 +273,9 @@ struct hn_softc {
|
|||||||
#define HN_CAP_TSO6 0x0100
|
#define HN_CAP_TSO6 0x0100
|
||||||
#define HN_CAP_HASHVAL 0x0200
|
#define HN_CAP_HASHVAL 0x0200
|
||||||
|
|
||||||
|
#define HN_LINK_FLAG_LINKUP 0x0001
|
||||||
|
#define HN_LINK_FLAG_NETCHG 0x0002
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Externs
|
* Externs
|
||||||
*/
|
*/
|
||||||
|
@ -335,6 +335,8 @@ static void hn_destroy_tx_data(struct hn_softc *);
|
|||||||
static void hn_start_taskfunc(void *, int);
|
static void hn_start_taskfunc(void *, int);
|
||||||
static void hn_start_txeof_taskfunc(void *, int);
|
static void hn_start_txeof_taskfunc(void *, int);
|
||||||
static void hn_link_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 void hn_suspend_mgmt_taskfunc(void *, int);
|
||||||
static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
|
static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
|
||||||
static int hn_create_rx_data(struct hn_softc *sc, int);
|
static int hn_create_rx_data(struct hn_softc *sc, int);
|
||||||
@ -360,6 +362,7 @@ static void hn_rx_drain(struct vmbus_channel *);
|
|||||||
static void hn_tx_resume(struct hn_softc *, int);
|
static void hn_tx_resume(struct hn_softc *, int);
|
||||||
static void hn_tx_ring_qflush(struct hn_tx_ring *);
|
static void hn_tx_ring_qflush(struct hn_tx_ring *);
|
||||||
static int netvsc_detach(device_t dev);
|
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,
|
static void hn_nvs_handle_notify(struct hn_softc *sc,
|
||||||
const struct vmbus_chanpkt_hdr *pkt);
|
const struct vmbus_chanpkt_hdr *pkt);
|
||||||
@ -482,7 +485,7 @@ hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
|
|||||||
ifmr->ifm_status = IFM_AVALID;
|
ifmr->ifm_status = IFM_AVALID;
|
||||||
ifmr->ifm_active = IFM_ETHER;
|
ifmr->ifm_active = IFM_ETHER;
|
||||||
|
|
||||||
if (!sc->hn_carrier) {
|
if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
|
||||||
ifmr->ifm_active |= IFM_NONE;
|
ifmr->ifm_active |= IFM_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -563,6 +566,9 @@ netvsc_attach(device_t dev)
|
|||||||
taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
|
taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
|
||||||
device_get_nameunit(dev));
|
device_get_nameunit(dev));
|
||||||
TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
|
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
|
* Allocate ifnet and setup its name earlier, so that if_printf
|
||||||
@ -808,10 +814,8 @@ netvsc_shutdown(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
uint32_t link_status;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -822,11 +826,51 @@ hn_link_taskfunc(void *xsc, int pending __unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (link_status == NDIS_MEDIA_STATE_CONNECTED)
|
if (link_status == NDIS_MEDIA_STATE_CONNECTED)
|
||||||
sc->hn_carrier = 1;
|
sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
|
||||||
else
|
else
|
||||||
sc->hn_carrier = 0;
|
sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
|
||||||
if_link_state_change(ifp,
|
if_link_state_change(sc->hn_ifp,
|
||||||
sc->hn_carrier ? LINK_STATE_UP : LINK_STATE_DOWN);
|
(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
|
void
|
||||||
@ -837,6 +881,14 @@ hn_link_status_update(struct hn_softc *sc)
|
|||||||
taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
|
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
|
static __inline int
|
||||||
hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
|
hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
|
||||||
struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
|
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.
|
* 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);
|
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;
|
sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
|
||||||
hn_link_status_update(sc);
|
hn_network_change(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -158,6 +158,7 @@ static void
|
|||||||
hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
|
hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
|
||||||
{
|
{
|
||||||
const struct rndis_status_msg *msg;
|
const struct rndis_status_msg *msg;
|
||||||
|
int ofs;
|
||||||
|
|
||||||
if (dlen < sizeof(*msg)) {
|
if (dlen < sizeof(*msg)) {
|
||||||
if_printf(sc->hn_ifp, "invalid RNDIS status\n");
|
if_printf(sc->hn_ifp, "invalid RNDIS status\n");
|
||||||
@ -176,8 +177,19 @@ hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RNDIS_STATUS_NETWORK_CHANGE:
|
case RNDIS_STATUS_NETWORK_CHANGE:
|
||||||
/* TODO */
|
ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
|
||||||
if_printf(sc->hn_ifp, "network changed\n");
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -139,6 +139,7 @@ int hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
|
|||||||
const struct hn_recvinfo *info);
|
const struct hn_recvinfo *info);
|
||||||
void hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr);
|
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_link_status_update(struct hn_softc *sc);
|
||||||
|
void hn_network_change(struct hn_softc *sc);
|
||||||
|
|
||||||
extern struct hn_send_ctx hn_send_ctx_none;
|
extern struct hn_send_ctx hn_send_ctx_none;
|
||||||
|
|
||||||
|
@ -32,6 +32,10 @@
|
|||||||
#define NDIS_MEDIA_STATE_CONNECTED 0
|
#define NDIS_MEDIA_STATE_CONNECTED 0
|
||||||
#define NDIS_MEDIA_STATE_DISCONNECTED 1
|
#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_NOCHG 0
|
||||||
#define NDIS_OFFLOAD_SET_ON 1
|
#define NDIS_OFFLOAD_SET_ON 1
|
||||||
#define NDIS_OFFLOAD_SET_OFF 2
|
#define NDIS_OFFLOAD_SET_OFF 2
|
||||||
|
@ -320,6 +320,10 @@ struct rndis_status_msg {
|
|||||||
/* rndis_diag_info */
|
/* 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
|
* Immediately after rndis_status_msg.rm_stbufoffset, if a control
|
||||||
* message is malformatted, or a packet message contains inappropriate
|
* message is malformatted, or a packet message contains inappropriate
|
||||||
|
Loading…
Reference in New Issue
Block a user