Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_virtio_net.c
Show First 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
pci_vtnet_rx(struct pci_vtnet_softc *sc) | pci_vtnet_rx(struct pci_vtnet_softc *sc) | ||||
{ | { | ||||
int prepend_hdr_len = sc->vhdrlen - sc->be_vhdrlen; | int prepend_hdr_len = sc->vhdrlen - sc->be_vhdrlen; | ||||
struct virtio_mrg_rxbuf_info info[VTNET_MAXSEGS]; | struct virtio_mrg_rxbuf_info info[VTNET_MAXSEGS]; | ||||
struct iovec iov[VTNET_MAXSEGS + 1]; | struct iovec iov[VTNET_MAXSEGS + 1]; | ||||
struct vqueue_info *vq; | struct vqueue_info *vq; | ||||
vq = &sc->vsc_queues[VTNET_RXQ]; | |||||
for (;;) { | |||||
struct virtio_net_rxhdr *hdr; | |||||
uint32_t riov_bytes; | uint32_t riov_bytes; | ||||
struct iovec *riov; | struct iovec *riov; | ||||
int riov_len; | |||||
uint32_t ulen; | uint32_t ulen; | ||||
int riov_len; | |||||
int n_chains; | int n_chains; | ||||
int len; | ssize_t rlen; | ||||
ssize_t plen; | |||||
vq = &sc->vsc_queues[VTNET_RXQ]; | plen = netbe_peek_recvlen(sc->vsc_be); | ||||
for (;;) { | if (plen <= 0) { | ||||
struct virtio_net_rxhdr *hdr; | /* | ||||
* No more packets (plen == 0), or backend errored | |||||
* (plen < 0). Interrupt if needed and stop. | |||||
*/ | |||||
vq_endchains(vq, /*used_all_avail=*/0); | |||||
return; | |||||
} | |||||
/* | /* | ||||
* Get a descriptor chain to store the next ingress | * Get a descriptor chain to store the next ingress | ||||
* packet. In case of mergeable rx buffers, get as | * packet. In case of mergeable rx buffers, get as | ||||
* many chains as necessary in order to make room | * many chains as necessary in order to make room | ||||
* for a maximum sized LRO packet. | * for plen bytes. | ||||
*/ | */ | ||||
riov_bytes = 0; | riov_bytes = 0; | ||||
riov_len = 0; | riov_len = 0; | ||||
riov = iov; | riov = iov; | ||||
n_chains = 0; | n_chains = 0; | ||||
do { | do { | ||||
int n = vq_getchain(vq, &info[n_chains].idx, riov, | int n = vq_getchain(vq, &info[n_chains].idx, riov, | ||||
VTNET_MAXSEGS - riov_len, NULL); | VTNET_MAXSEGS - riov_len, NULL); | ||||
Show All 27 Lines | do { | ||||
if (!sc->rx_merge) { | if (!sc->rx_merge) { | ||||
n_chains = 1; | n_chains = 1; | ||||
break; | break; | ||||
} | } | ||||
info[n_chains].len = (uint32_t)count_iov(riov, n); | info[n_chains].len = (uint32_t)count_iov(riov, n); | ||||
riov_bytes += info[n_chains].len; | riov_bytes += info[n_chains].len; | ||||
riov += n; | riov += n; | ||||
n_chains++; | n_chains++; | ||||
} while (riov_bytes < VTNET_MAX_PKT_LEN && | } while (riov_bytes < plen && riov_len < VTNET_MAXSEGS); | ||||
riov_len < VTNET_MAXSEGS); | |||||
riov = iov; | riov = iov; | ||||
hdr = riov[0].iov_base; | hdr = riov[0].iov_base; | ||||
if (prepend_hdr_len > 0) { | if (prepend_hdr_len > 0) { | ||||
/* | /* | ||||
* The frontend uses a virtio-net header, but the | * The frontend uses a virtio-net header, but the | ||||
* backend does not. We need to prepend a zeroed | * backend does not. We need to prepend a zeroed | ||||
* header. | * header. | ||||
*/ | */ | ||||
riov = iov_trim_hdr(riov, &riov_len, prepend_hdr_len); | riov = iov_trim_hdr(riov, &riov_len, prepend_hdr_len); | ||||
if (riov == NULL) { | if (riov == NULL) { | ||||
/* | /* | ||||
* The first collected chain is nonsensical, | * The first collected chain is nonsensical, | ||||
* as it is not even enough to store the | * as it is not even enough to store the | ||||
* virtio-net header. Just drop it. | * virtio-net header. Just drop it. | ||||
*/ | */ | ||||
vq_relchain(vq, info[0].idx, 0); | vq_relchain(vq, info[0].idx, 0); | ||||
vq_retchains(vq, n_chains - 1); | vq_retchains(vq, n_chains - 1); | ||||
continue; | continue; | ||||
} | } | ||||
memset(hdr, 0, prepend_hdr_len); | memset(hdr, 0, prepend_hdr_len); | ||||
} | } | ||||
len = netbe_recv(sc->vsc_be, riov, riov_len); | rlen = netbe_recv(sc->vsc_be, riov, riov_len); | ||||
if (rlen != plen) { | |||||
if (len <= 0) { | |||||
/* | /* | ||||
* No more packets (len == 0), or backend errored | * If this happens it means there is something | ||||
* (err < 0). Return unused available buffers | * wrong with the backend (e.g., some other | ||||
* and stop. | * process is stealing our packets). | ||||
*/ | */ | ||||
WPRINTF(("netbe_recv: expected %zd bytes, " | |||||
"got %zd", plen, rlen)); | |||||
vq_retchains(vq, n_chains); | vq_retchains(vq, n_chains); | ||||
/* Interrupt if needed/appropriate and stop. */ | continue; | ||||
vq_endchains(vq, /*used_all_avail=*/0); | |||||
return; | |||||
} | } | ||||
ulen = (uint32_t)(len + prepend_hdr_len); | ulen = (uint32_t)(plen + prepend_hdr_len); | ||||
/* | /* | ||||
* Publish the used buffers to the guest, reporting the | * Publish the used buffers to the guest, reporting the | ||||
* number of bytes that we wrote. | * number of bytes that we wrote. | ||||
*/ | */ | ||||
if (!sc->rx_merge) { | if (!sc->rx_merge) { | ||||
vq_relchain(vq, info[0].idx, ulen); | vq_relchain(vq, info[0].idx, ulen); | ||||
} else { | } else { | ||||
uint32_t iolen; | uint32_t iolen; | ||||
int i = 0; | int i = 0; | ||||
do { | do { | ||||
iolen = info[i].len; | iolen = info[i].len; | ||||
if (iolen > ulen) { | if (iolen > ulen) { | ||||
iolen = ulen; | iolen = ulen; | ||||
} | } | ||||
vq_relchain_prepare(vq, info[i].idx, iolen); | vq_relchain_prepare(vq, info[i].idx, iolen); | ||||
ulen -= iolen; | ulen -= iolen; | ||||
i++; | i++; | ||||
assert(i <= n_chains); | |||||
} while (ulen > 0); | } while (ulen > 0); | ||||
hdr->vrh_bufs = i; | hdr->vrh_bufs = i; | ||||
vq_relchain_publish(vq); | vq_relchain_publish(vq); | ||||
vq_retchains(vq, n_chains - i); | assert(i == n_chains); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Called when there is read activity on the backend file descriptor. | * Called when there is read activity on the backend file descriptor. | ||||
* Each buffer posted by the guest is assumed to be able to contain | * Each buffer posted by the guest is assumed to be able to contain | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | if (opts != NULL) { | ||||
err = netbe_init(&sc->vsc_be, devname, pci_vtnet_rx_callback, | err = netbe_init(&sc->vsc_be, devname, pci_vtnet_rx_callback, | ||||
sc); | sc); | ||||
free(devname); | free(devname); | ||||
if (err) { | if (err) { | ||||
free(sc); | free(sc); | ||||
return (err); | return (err); | ||||
} | } | ||||
sc->vsc_consts.vc_hv_caps |= netbe_get_cap(sc->vsc_be); | sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MRG_RXBUF | | ||||
netbe_get_cap(sc->vsc_be); | |||||
} | } | ||||
if (!mac_provided) { | if (!mac_provided) { | ||||
net_genmac(pi, sc->vsc_config.mac); | net_genmac(pi, sc->vsc_config.mac); | ||||
} | } | ||||
/* initialize config space */ | /* initialize config space */ | ||||
pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); | pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); | ||||
▲ Show 20 Lines • Show All 106 Lines • Show Last 20 Lines |