*------------------------------------------------------------------
*/
+#include <stddef.h>
#include <fcntl.h> /* for open */
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <vnet/devices/devices.h>
#include <vnet/feature/feature.h>
+#include <vnet/devices/virtio/virtio.h>
#include <vnet/devices/virtio/vhost_user.h>
#include <vnet/devices/virtio/vhost_user_inline.h>
+#include <vnet/gso/gso.h>
/*
* On the transmit side, we keep processing the buffers from vlib in the while
* loop and prepare the copy order to be executed later. However, the static
* entries. In order to not corrupt memory, we have to do the copy when the
* static array reaches the copy threshold. We subtract 40 in case the code
* goes into the inner loop for a maximum of 64k frames which may require
- * more array entries.
+ * more array entries. We subtract 200 because our default buffer size is
+ * 2048 and the default desc len is likely 1536. While it takes less than 40
+ * vlib buffers for the jumbo frame, it may take twice as much descriptors
+ * for the same jumbo frame. Use 200 for the extra head room.
*/
-#define VHOST_USER_TX_COPY_THRESHOLD (VHOST_USER_COPY_ARRAY_N - 40)
+#define VHOST_USER_TX_COPY_THRESHOLD (VHOST_USER_COPY_ARRAY_N - 200)
-vnet_device_class_t vhost_user_device_class;
+extern vnet_device_class_t vhost_user_device_class;
#define foreach_vhost_user_tx_func_error \
_(NONE, "no error") \
return 0;
}
+static_always_inline void
+vhost_user_handle_tx_offload (vhost_user_intf_t * vui, vlib_buffer_t * b,
+ virtio_net_hdr_t * hdr)
+{
+ gso_header_offset_t gho =
+ vnet_gso_header_offset_parser (b, b->flags & VNET_BUFFER_F_IS_IP6);
+ if (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM)
+ {
+ ip4_header_t *ip4;
+
+ ip4 =
+ (ip4_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
+ ip4->checksum = ip4_header_checksum (ip4);
+ }
+
+ /* checksum offload */
+ if (b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)
+ {
+ hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+ hdr->csum_start = gho.l4_hdr_offset;
+ hdr->csum_offset = offsetof (udp_header_t, checksum);
+ }
+ else if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
+ {
+ hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+ hdr->csum_start = gho.l4_hdr_offset;
+ hdr->csum_offset = offsetof (tcp_header_t, checksum);
+ }
+
+ /* GSO offload */
+ if (b->flags & VNET_BUFFER_F_GSO)
+ {
+ if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
+ {
+ if ((b->flags & VNET_BUFFER_F_IS_IP4) &&
+ (vui->features & (1ULL << FEAT_VIRTIO_NET_F_GUEST_TSO4)))
+ {
+ hdr->gso_size = vnet_buffer2 (b)->gso_size;
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ }
+ else if ((b->flags & VNET_BUFFER_F_IS_IP6) &&
+ (vui->features & (1ULL << FEAT_VIRTIO_NET_F_GUEST_TSO6)))
+ {
+ hdr->gso_size = vnet_buffer2 (b)->gso_size;
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ }
+ }
+ else if ((vui->features & (1ULL << FEAT_VIRTIO_NET_F_GUEST_UFO)) &&
+ (b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
+ {
+ hdr->gso_size = vnet_buffer2 (b)->gso_size;
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
+ }
+ }
+}
+
VNET_DEVICE_CLASS_TX_FN (vhost_user_device_class) (vlib_main_t * vm,
vlib_node_runtime_t *
node, vlib_frame_t * frame)
u8 retry = 8;
u16 copy_len;
u16 tx_headers_len;
+ u32 or_flags;
if (PREDICT_FALSE (!vui->admin_up))
{
virtio_net_hdr_mrg_rxbuf_t *hdr = &cpu->tx_headers[tx_headers_len];
tx_headers_len++;
hdr->hdr.flags = 0;
- hdr->hdr.gso_type = 0;
+ hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE;
hdr->num_buffers = 1; //This is local, no need to check
+ or_flags = (b0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM) ||
+ (b0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM) ||
+ (b0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM);
+
+ /* Guest supports csum offload and buffer requires checksum offload? */
+ if (or_flags
+ && (vui->features & (1ULL << FEAT_VIRTIO_NET_F_GUEST_CSUM)))
+ vhost_user_handle_tx_offload (vui, b0, &hdr->hdr);
+
// Prepare a copy order executed later for the header
+ ASSERT (copy_len < VHOST_USER_COPY_ARRAY_N);
vhost_copy_t *cpy = &cpu->copy[copy_len];
copy_len++;
cpy->len = vui->virtio_net_hdr_sz;
}
{
+ ASSERT (copy_len < VHOST_USER_COPY_ARRAY_N);
vhost_copy_t *cpy = &cpu->copy[copy_len];
copy_len++;
cpy->len = bytes_left;
* retry.
* The idea is that it is better to waste some time on packets
* that have been processed already than dropping them and get
- * more fresh packets with a good likelyhood that they will be dropped too.
+ * more fresh packets with a good likelihood that they will be dropped too.
* This technique also gives more time to VM driver to pick-up packets.
* In case the traffic flows from physical to virtual interfaces, this
* technique will end-up leveraging the physical NIC buffer in order to