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 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
|
||||
*/
|
||||
|
@ -335,6 +335,8 @@ static void hn_destroy_tx_data(struct hn_softc *);
|
||||
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_channel *);
|
||||
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 ifmediareq *ifmr)
|
||||
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 __unused)
|
||||
}
|
||||
|
||||
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 *sc)
|
||||
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
|
||||
|
@ -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_softc *sc, const void *data, int dlen)
|
||||
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:
|
||||
|
@ -139,6 +139,7 @@ int hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
|
||||
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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user