[bhyve] virtio-net: Do not allow receiving packets until features have been negotiated.
Enforce the requirement that the RX callback cannot be called after a reset until the features have been negotiated. This fixes a race condition where the receive callback is called during a device reset. Reviewed by: vmaffione, grehan Approved by: vmaffione (mentor) Sponsored by: vstack.com Differential Revision: https://reviews.freebsd.org/D27381
This commit is contained in:
parent
10720ae4db
commit
ea57b2d7a8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=368720
@ -111,6 +111,8 @@ struct pci_vtnet_softc {
|
|||||||
|
|
||||||
net_backend_t *vsc_be;
|
net_backend_t *vsc_be;
|
||||||
|
|
||||||
|
bool features_negotiated; /* protected by rx_mtx */
|
||||||
|
|
||||||
int resetting; /* protected by tx_mtx */
|
int resetting; /* protected by tx_mtx */
|
||||||
|
|
||||||
uint64_t vsc_features; /* negotiated features */
|
uint64_t vsc_features; /* negotiated features */
|
||||||
@ -176,6 +178,7 @@ pci_vtnet_reset(void *vsc)
|
|||||||
* Receive operation will be enabled again once the guest adds
|
* Receive operation will be enabled again once the guest adds
|
||||||
* the first receive buffers and kicks us.
|
* the first receive buffers and kicks us.
|
||||||
*/
|
*/
|
||||||
|
sc->features_negotiated = false;
|
||||||
netbe_rx_disable(sc->vsc_be);
|
netbe_rx_disable(sc->vsc_be);
|
||||||
|
|
||||||
/* Set sc->resetting and give a chance to the TX thread to stop. */
|
/* Set sc->resetting and give a chance to the TX thread to stop. */
|
||||||
@ -246,6 +249,12 @@ pci_vtnet_rx(struct pci_vtnet_softc *sc)
|
|||||||
struct vqueue_info *vq;
|
struct vqueue_info *vq;
|
||||||
|
|
||||||
vq = &sc->vsc_queues[VTNET_RXQ];
|
vq = &sc->vsc_queues[VTNET_RXQ];
|
||||||
|
|
||||||
|
/* Features must be negotiated */
|
||||||
|
if (!sc->features_negotiated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct virtio_net_rxhdr *hdr;
|
struct virtio_net_rxhdr *hdr;
|
||||||
uint32_t riov_bytes;
|
uint32_t riov_bytes;
|
||||||
@ -406,8 +415,14 @@ pci_vtnet_ping_rxq(void *vsc, struct vqueue_info *vq)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* A qnotify means that the rx process can now begin.
|
* A qnotify means that the rx process can now begin.
|
||||||
|
* Enable RX only if features are negotiated.
|
||||||
*/
|
*/
|
||||||
pthread_mutex_lock(&sc->rx_mtx);
|
pthread_mutex_lock(&sc->rx_mtx);
|
||||||
|
if (!sc->features_negotiated) {
|
||||||
|
pthread_mutex_unlock(&sc->rx_mtx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
vq_kick_disable(vq);
|
vq_kick_disable(vq);
|
||||||
netbe_rx_enable(sc->vsc_be);
|
netbe_rx_enable(sc->vsc_be);
|
||||||
pthread_mutex_unlock(&sc->rx_mtx);
|
pthread_mutex_unlock(&sc->rx_mtx);
|
||||||
@ -750,6 +765,10 @@ pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features)
|
|||||||
netbe_set_cap(sc->vsc_be, negotiated_features, sc->vhdrlen);
|
netbe_set_cap(sc->vsc_be, negotiated_features, sc->vhdrlen);
|
||||||
sc->be_vhdrlen = netbe_get_vnet_hdr_len(sc->vsc_be);
|
sc->be_vhdrlen = netbe_get_vnet_hdr_len(sc->vsc_be);
|
||||||
assert(sc->be_vhdrlen == 0 || sc->be_vhdrlen == sc->vhdrlen);
|
assert(sc->be_vhdrlen == 0 || sc->be_vhdrlen == sc->vhdrlen);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&sc->rx_mtx);
|
||||||
|
sc->features_negotiated = true;
|
||||||
|
pthread_mutex_unlock(&sc->rx_mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BHYVE_SNAPSHOT
|
#ifdef BHYVE_SNAPSHOT
|
||||||
|
Loading…
Reference in New Issue
Block a user