Index: usr.sbin/bhyve/pci_virtio_net.c =================================================================== --- usr.sbin/bhyve/pci_virtio_net.c +++ usr.sbin/bhyve/pci_virtio_net.c @@ -109,7 +109,6 @@ uint64_t vsc_features; /* negotiated features */ pthread_mutex_t rx_mtx; - unsigned int rx_vhdrlen; int rx_merge; /* merged rx bufs in use */ pthread_t tx_tid; @@ -149,6 +148,16 @@ /* Acquire the RX lock to block RX processing. */ pthread_mutex_lock(&sc->rx_mtx); + /* + * Make sure receive operation is disabled at least until we + * re-negotiate the features, since receive operation depends + * on the value of sc->rx_merge and the header length, which + * are both set in pci_vtnet_neg_features(). + * Receive operation will be enabled again once the guest adds + * the first receive buffers and kicks us. + */ + netbe_rx_disable(sc->vsc_be); + /* Set sc->resetting and give a chance to the TX thread to stop. */ pthread_mutex_lock(&sc->tx_mtx); sc->resetting = 1; @@ -158,9 +167,6 @@ pthread_mutex_lock(&sc->tx_mtx); } - sc->rx_merge = 1; - sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); - /* * Now reset rings, MSI-X vectors, and negotiated capabilities. * Do that with the TX lock held, since we need to reset @@ -512,8 +518,7 @@ sc->resetting = 0; - sc->rx_merge = 1; - sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); + sc->rx_merge = 0; pthread_mutex_init(&sc->rx_mtx, NULL); /* @@ -568,18 +573,24 @@ pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features) { struct pci_vtnet_softc *sc = vsc; + unsigned int rx_vhdrlen; sc->vsc_features = negotiated_features; - if (!(negotiated_features & VIRTIO_NET_F_MRG_RXBUF)) { + if (negotiated_features & VIRTIO_NET_F_MRG_RXBUF) { + rx_vhdrlen = sizeof(struct virtio_net_rxhdr); + sc->rx_merge = 1; + } else { + /* + * Without mergeable rx buffers, virtio-net header is 2 + * bytes shorter than sizeof(struct virtio_net_rxhdr). + */ + rx_vhdrlen = sizeof(struct virtio_net_rxhdr) - 2; sc->rx_merge = 0; - /* Without mergeable rx buffers, virtio-net header is 2 - * bytes shorter than sizeof(struct virtio_net_rxhdr). */ - sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr) - 2; } /* Tell the backend to enable some capabilities it has advertised. */ - netbe_set_cap(sc->vsc_be, negotiated_features, sc->rx_vhdrlen); + netbe_set_cap(sc->vsc_be, negotiated_features, rx_vhdrlen); } static struct pci_devemu pci_de_vnet = {