diff --git a/src/apps/vhost/vhost_user.c b/src/apps/vhost/vhost_user.c index 2a12ac20ee..f581c201f7 100644 --- a/src/apps/vhost/vhost_user.c +++ b/src/apps/vhost/vhost_user.c @@ -136,13 +136,13 @@ int vhost_user_receive(int sock, struct vhost_user_msg *msg, int *fds, return ret; } -void* vhost_user_map_guest_memory(int fd, int size) +void* vhost_user_map_guest_memory(int fd, uint64_t size) { void *ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); return ptr == MAP_FAILED ? 0 : ptr; } -int vhost_user_unmap_guest_memory(void *ptr, int size) +int vhost_user_unmap_guest_memory(void *ptr, uint64_t size) { return munmap(ptr, size); } diff --git a/src/apps/vhost/vhost_user.h b/src/apps/vhost/vhost_user.h index c3f9851dce..19b8c5a5cc 100644 --- a/src/apps/vhost/vhost_user.h +++ b/src/apps/vhost/vhost_user.h @@ -58,6 +58,6 @@ int vhost_user_connect(const char *path); int vhost_user_send(int sock, struct vhost_user_msg *msg); int vhost_user_receive(int sock, struct vhost_user_msg *msg, int *fds, int *nfds); -void* vhost_user_map_guest_memory(int fd, int size); -int vhost_user_unmap_guest_memory(void *ptr, int size); +void* vhost_user_map_guest_memory(int fd, uint64_t size); +int vhost_user_unmap_guest_memory(void *ptr, uint64_t size); int vhost_user_sync_shm(void *ptr, size_t size); diff --git a/src/lib/virtio/net_device.lua b/src/lib/virtio/net_device.lua index 027f75fc07..918f360a2b 100644 --- a/src/lib/virtio/net_device.lua +++ b/src/lib/virtio/net_device.lua @@ -176,18 +176,53 @@ end -- Prepared argument for writing a 1 to an eventfd. local eventfd_one = ffi.new("uint64_t[1]", {1}) +function VirtioNetDevice:more_vm_buffers () + return freelist.nfree(self.vring_transmit_buffers) > 2 +end + +-- return the buffer from a iovec, ensuring it originates from the vm +function VirtioNetDevice:vm_buffer (iovec) + local should_continue = true + local b = iovec.buffer + -- check if this is a zero-copy packet + if b.origin.type ~= C.BUFFER_ORIGIN_VIRTIO then + -- get buffer from the once supplied by the VM + local old_b = b + b = freelist.remove(self.vring_transmit_buffers) + --assert(iovec.offset + iovec.length <= b.size) + + -- copy the whole buffer data, including offset + ffi.copy(b.pointer, old_b.pointer, iovec.offset + iovec.length) + buffer.free(old_b) + iovec.buffer = b + + if not self:more_vm_buffers() then + -- no more buffers, stop the loop + should_continue = false + end + end + return should_continue, b +end + -- Transmit packets from the app input queue to the VM. function VirtioNetDevice:transmit_packets_to_vm () local l = self.owner.input.rx if not l then return end - while not link.empty(l) do + local should_continue = not self.not_enough_vm_bufers + + while (not link.empty(l)) and should_continue do local p = link.receive(l) - local iovec = p.iovecs[0] - local b = iovec.buffer - local virtio_hdr = b.origin.info.virtio.header_pointer - --assert(b.origin.type == C.BUFFER_ORIGIN_VIRTIO) + -- ensure all data is in a single buffer + if p.niovecs > 1 then + packet.coalesce(p) + end + + local iovec = p.iovecs[0] + should_continue, b = self:vm_buffer(iovec) + -- fill in the virtio header + local virtio_hdr = b.origin.info.virtio.header_pointer ffi.copy(virtio_hdr, p.info, packet_info_size) local used = self.txring.used.ring[self.txused%self.tx_vring_num] @@ -200,6 +235,11 @@ function VirtioNetDevice:transmit_packets_to_vm () packet.deref(p) end + if not should_continue then + -- not enough buffers detected, verify once again + self.not_enough_vm_bufers = not self:more_vm_buffers() + end + if self.txring.used.idx ~= self.txused then self.txring.used.idx = self.txused C.write(self.callfd[0], eventfd_one, 8)