Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/net_backends.c
Show First 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | int (*init)(struct net_backend *be, const char *devname, | ||||
net_be_rxeof_t cb, void *param); | net_be_rxeof_t cb, void *param); | ||||
void (*cleanup)(struct net_backend *be); | void (*cleanup)(struct net_backend *be); | ||||
/* | /* | ||||
* Called to serve a guest transmit request. The scatter-gather | * Called to serve a guest transmit request. The scatter-gather | ||||
* vector provided by the caller has 'iovcnt' elements and contains | * vector provided by the caller has 'iovcnt' elements and contains | ||||
* the packet to send. | * the packet to send. | ||||
*/ | */ | ||||
ssize_t (*send)(struct net_backend *be, struct iovec *iov, int iovcnt); | ssize_t (*send)(struct net_backend *be, const struct iovec *iov, | ||||
int iovcnt); | |||||
/* | /* | ||||
* Called to receive a packet from the backend. When the function | * Called to receive a packet from the backend. When the function | ||||
* returns a positive value 'len', the scatter-gather vector | * returns a positive value 'len', the scatter-gather vector | ||||
* provided by the caller contains a packet with such length. | * provided by the caller contains a packet with such length. | ||||
* The function returns 0 if the backend doesn't have a new packet to | * The function returns 0 if the backend doesn't have a new packet to | ||||
* receive. | * receive. | ||||
*/ | */ | ||||
ssize_t (*recv)(struct net_backend *be, struct iovec *iov, int iovcnt); | ssize_t (*recv)(struct net_backend *be, const struct iovec *iov, | ||||
int iovcnt); | |||||
/* | /* | ||||
* Ask the backend to enable or disable receive operation in the | * Ask the backend to enable or disable receive operation in the | ||||
* backend. On return from a disable operation, it is guaranteed | * backend. On return from a disable operation, it is guaranteed | ||||
* that the receive callback won't be called until receive is | * that the receive callback won't be called until receive is | ||||
* enabled again. Note however that it is up to the caller to make | * enabled again. Note however that it is up to the caller to make | ||||
* sure that netbe_recv() is not currently being executed by another | * sure that netbe_recv() is not currently being executed by another | ||||
* thread. | * thread. | ||||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | error: | ||||
tap_cleanup(be); | tap_cleanup(be); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/* | /* | ||||
* Called to send a buffer chain out to the tap device | * Called to send a buffer chain out to the tap device | ||||
*/ | */ | ||||
static ssize_t | static ssize_t | ||||
tap_send(struct net_backend *be, struct iovec *iov, int iovcnt) | tap_send(struct net_backend *be, const struct iovec *iov, int iovcnt) | ||||
{ | { | ||||
return (writev(be->fd, iov, iovcnt)); | return (writev(be->fd, iov, iovcnt)); | ||||
} | } | ||||
static ssize_t | static ssize_t | ||||
tap_recv(struct net_backend *be, struct iovec *iov, int iovcnt) | tap_recv(struct net_backend *be, const struct iovec *iov, int iovcnt) | ||||
{ | { | ||||
ssize_t ret; | ssize_t ret; | ||||
/* Should never be called without a valid tap fd */ | /* Should never be called without a valid tap fd */ | ||||
assert(be->fd != -1); | assert(be->fd != -1); | ||||
ret = readv(be->fd, iov, iovcnt); | ret = readv(be->fd, iov, iovcnt); | ||||
▲ Show 20 Lines • Show All 197 Lines • ▼ Show 20 Lines | netmap_cleanup(struct net_backend *be) | ||||
} | } | ||||
if (priv->nmd) { | if (priv->nmd) { | ||||
nm_close(priv->nmd); | nm_close(priv->nmd); | ||||
} | } | ||||
be->fd = -1; | be->fd = -1; | ||||
} | } | ||||
static ssize_t | static ssize_t | ||||
netmap_send(struct net_backend *be, struct iovec *iov, | netmap_send(struct net_backend *be, const struct iovec *iov, | ||||
int iovcnt) | int iovcnt) | ||||
{ | { | ||||
struct netmap_priv *priv = (struct netmap_priv *)be->opaque; | struct netmap_priv *priv = (struct netmap_priv *)be->opaque; | ||||
struct netmap_ring *ring; | struct netmap_ring *ring; | ||||
ssize_t totlen = 0; | ssize_t totlen = 0; | ||||
int nm_buf_size; | int nm_buf_size; | ||||
int nm_buf_len; | int nm_buf_len; | ||||
uint32_t head; | uint32_t head; | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | netmap_send(struct net_backend *be, const struct iovec *iov, | ||||
ring->head = ring->cur = head; | ring->head = ring->cur = head; | ||||
txsync: | txsync: | ||||
ioctl(be->fd, NIOCTXSYNC, NULL); | ioctl(be->fd, NIOCTXSYNC, NULL); | ||||
return (totlen); | return (totlen); | ||||
} | } | ||||
static ssize_t | static ssize_t | ||||
netmap_recv(struct net_backend *be, struct iovec *iov, int iovcnt) | netmap_recv(struct net_backend *be, const struct iovec *iov, int iovcnt) | ||||
{ | { | ||||
struct netmap_priv *priv = (struct netmap_priv *)be->opaque; | struct netmap_priv *priv = (struct netmap_priv *)be->opaque; | ||||
struct netmap_slot *slot = NULL; | struct netmap_slot *slot = NULL; | ||||
struct netmap_ring *ring; | struct netmap_ring *ring; | ||||
void *iov_frag_buf; | void *iov_frag_buf; | ||||
int iov_frag_size; | int iov_frag_size; | ||||
ssize_t totlen = 0; | ssize_t totlen = 0; | ||||
uint32_t head; | uint32_t head; | ||||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | netbe_set_cap(struct net_backend *be, uint64_t features, | ||||
ret = be->set_cap(be, features, vnet_hdr_len); | ret = be->set_cap(be, features, vnet_hdr_len); | ||||
assert(be->be_vnet_hdr_len == 0 || | assert(be->be_vnet_hdr_len == 0 || | ||||
be->be_vnet_hdr_len == be->fe_vnet_hdr_len); | be->be_vnet_hdr_len == be->fe_vnet_hdr_len); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static __inline struct iovec * | |||||
iov_trim(struct iovec *iov, int *iovcnt, unsigned int tlen) | |||||
{ | |||||
struct iovec *riov; | |||||
/* XXX short-cut: assume first segment is >= tlen */ | |||||
assert(iov[0].iov_len >= tlen); | |||||
iov[0].iov_len -= tlen; | |||||
if (iov[0].iov_len == 0) { | |||||
assert(*iovcnt > 1); | |||||
*iovcnt -= 1; | |||||
riov = &iov[1]; | |||||
} else { | |||||
iov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base + tlen); | |||||
riov = &iov[0]; | |||||
} | |||||
return (riov); | |||||
} | |||||
ssize_t | ssize_t | ||||
netbe_send(struct net_backend *be, struct iovec *iov, int iovcnt) | netbe_send(struct net_backend *be, const struct iovec *iov, int iovcnt) | ||||
{ | { | ||||
assert(be != NULL); | |||||
if (be->be_vnet_hdr_len != be->fe_vnet_hdr_len) { | |||||
/* | |||||
* The frontend uses a virtio-net header, but the backend | |||||
* does not. We ignore it (as it must be all zeroes) and | |||||
* strip it. | |||||
*/ | |||||
assert(be->be_vnet_hdr_len == 0); | |||||
iov = iov_trim(iov, &iovcnt, be->fe_vnet_hdr_len); | |||||
} | |||||
return (be->send(be, iov, iovcnt)); | return (be->send(be, iov, iovcnt)); | ||||
} | } | ||||
/* | /* | ||||
* Try to read a packet from the backend, without blocking. | * Try to read a packet from the backend, without blocking. | ||||
* If no packets are available, return 0. In case of success, return | * If no packets are available, return 0. In case of success, return | ||||
* the length of the packet just read. Return -1 in case of errors. | * the length of the packet just read. Return -1 in case of errors. | ||||
*/ | */ | ||||
ssize_t | ssize_t | ||||
netbe_recv(struct net_backend *be, struct iovec *iov, int iovcnt) | netbe_recv(struct net_backend *be, const struct iovec *iov, int iovcnt) | ||||
{ | { | ||||
/* Length of prepended virtio-net header. */ | |||||
unsigned int hlen = be->fe_vnet_hdr_len; | |||||
int ret; | |||||
assert(be != NULL); | return (be->recv(be, iov, iovcnt)); | ||||
if (hlen && hlen != be->be_vnet_hdr_len) { | |||||
/* | |||||
* The frontend uses a virtio-net header, but the backend | |||||
* does not. We need to prepend a zeroed header. | |||||
*/ | |||||
struct virtio_net_rxhdr *vh; | |||||
assert(be->be_vnet_hdr_len == 0); | |||||
/* | |||||
* Get a pointer to the rx header, and use the | |||||
* data immediately following it for the packet buffer. | |||||
*/ | |||||
vh = iov[0].iov_base; | |||||
iov = iov_trim(iov, &iovcnt, hlen); | |||||
/* | |||||
* The only valid field in the rx packet header is the | |||||
* number of buffers if merged rx bufs were negotiated. | |||||
*/ | |||||
memset(vh, 0, hlen); | |||||
if (hlen == VNET_HDR_LEN) { | |||||
vh->vrh_bufs = 1; | |||||
} | } | ||||
} | |||||
ret = be->recv(be, iov, iovcnt); | |||||
if (ret > 0) { | |||||
ret += hlen; | |||||
} | |||||
return (ret); | |||||
} | |||||
/* | /* | ||||
* Read a packet from the backend and discard it. | * Read a packet from the backend and discard it. | ||||
* Returns the size of the discarded packet or zero if no packet was available. | * Returns the size of the discarded packet or zero if no packet was available. | ||||
* A negative error code is returned in case of read error. | * A negative error code is returned in case of read error. | ||||
*/ | */ | ||||
ssize_t | ssize_t | ||||
netbe_rx_discard(struct net_backend *be) | netbe_rx_discard(struct net_backend *be) | ||||
{ | { | ||||
Show All 18 Lines | netbe_rx_disable(struct net_backend *be) | ||||
return be->recv_disable(be); | return be->recv_disable(be); | ||||
} | } | ||||
void | void | ||||
netbe_rx_enable(struct net_backend *be) | netbe_rx_enable(struct net_backend *be) | ||||
{ | { | ||||
return be->recv_enable(be); | return be->recv_enable(be); | ||||
} | |||||
size_t | |||||
netbe_get_vnet_hdr_len(struct net_backend *be) | |||||
{ | |||||
return (be->be_vnet_hdr_len); | |||||
} | } |