#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
-#include <linux/virtio_net.h>
-#include <linux/vhost.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
typedef enum
{
-#define _(f,s) TAP_TX_ERROR_##f,
+#define _(f,s) VIRTIO_TX_ERROR_##f,
foreach_virtio_tx_func_error
#undef _
- TAP_TX_N_ERROR,
+ VIRTIO_TX_N_ERROR,
} virtio_tx_func_error_t;
static char *virtio_tx_func_error_strings[] = {
#undef _
};
+#ifndef CLIB_MARCH_VARIANT
u8 *
format_virtio_device_name (u8 * s, va_list * args)
{
virtio_if_t *vif = pool_elt_at_index (mm->interfaces, dev_instance);
if (vif->type == VIRTIO_IF_TYPE_TAP)
- {
- s = format (s, "tap%u", vif->id);
- }
+ s = format (s, "tap%u", vif->id);
+ else if (vif->type == VIRTIO_IF_TYPE_PCI)
+ s = format (s, "virtio-%x/%x/%x/%x", vif->pci_addr.domain,
+ vif->pci_addr.bus, vif->pci_addr.slot,
+ vif->pci_addr.function);
else
- s = format (s, "virtio%lu", vif->dev_instance);
+ s = format (s, "virtio-%lu", vif->dev_instance);
return s;
}
+#endif /* CLIB_MARCH_VARIANT */
static u8 *
format_virtio_device (u8 * s, va_list * args)
return s;
}
+#ifndef CLIB_MARCH_VARIANT
inline void
virtio_free_used_desc (vlib_main_t * vm, virtio_vring_t * vring)
{
{
struct vring_used_elem *e = &vring->used->ring[last & mask];
u16 slot = e->id;
- struct vring_desc *d = &vring->desc[slot];
-
- if (PREDICT_FALSE (d->flags & VRING_DESC_F_INDIRECT))
- {
- d = uword_to_pointer (d->addr, struct vring_desc *);
- vec_free (d);
- }
vlib_buffer_free (vm, &vring->buffers[slot], 1);
used--;
vring->desc_in_use = used;
vring->last_used_idx = last;
}
+#endif /* CLIB_MARCH_VARIANT */
static_always_inline u16
-add_buffer_to_slot (vlib_main_t * vm, virtio_vring_t * vring, u32 bi,
- u16 avail, u16 next, u16 mask)
+add_buffer_to_slot (vlib_main_t * vm, virtio_if_t * vif,
+ virtio_vring_t * vring, u32 bi, u16 avail, u16 next,
+ u16 mask, int do_gso)
{
u16 n_added = 0;
- const int hdr_sz = sizeof (struct virtio_net_hdr_v1);
+ int hdr_sz = vif->virtio_net_hdr_sz;
struct vring_desc *d;
d = &vring->desc[next];
vlib_buffer_t *b = vlib_get_buffer (vm, bi);
struct virtio_net_hdr_v1 *hdr = vlib_buffer_get_current (b) - hdr_sz;
- memset (hdr, 0, hdr_sz);
+ clib_memset (hdr, 0, hdr_sz);
+ if (do_gso && (b->flags & VNET_BUFFER_F_GSO))
+ {
+ if (b->flags & VNET_BUFFER_F_IS_IP4)
+ {
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ hdr->gso_size = vnet_buffer2 (b)->gso_size;
+ hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+ hdr->csum_start = vnet_buffer (b)->l4_hdr_offset; // 0x22;
+ hdr->csum_offset = 0x10;
+ }
+ else
+ {
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ hdr->gso_size = vnet_buffer2 (b)->gso_size;
+ hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+ hdr->csum_start = vnet_buffer (b)->l4_hdr_offset; // 0x36;
+ hdr->csum_offset = 0x10;
+ }
+ }
if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
{
- d->addr = pointer_to_uword (vlib_buffer_get_current (b)) - hdr_sz;
+ d->addr =
+ ((vif->type == VIRTIO_IF_TYPE_PCI) ? vlib_buffer_get_current_pa (vm,
+ b) :
+ pointer_to_uword (vlib_buffer_get_current (b))) - hdr_sz;
d->len = b->current_length + hdr_sz;
d->flags = 0;
}
else
{
- struct vring_desc *id, *descs = 0;
-
- /* first buffer in chain */
- vec_add2_aligned (descs, id, 1, CLIB_CACHE_LINE_BYTES);
- id->addr = pointer_to_uword (vlib_buffer_get_current (b)) - hdr_sz;
- id->len = b->current_length + hdr_sz;
-
- while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
+ /*
+ * We are using single vlib_buffer_t for indirect descriptor(s)
+ * chain. Single descriptor is 16 bytes and vlib_buffer_t
+ * has 2048 bytes space. So maximum long chain can have 128
+ * (=2048/16) indirect descriptors.
+ * It can easily support 65535 bytes of Jumbo frames with
+ * each data buffer size of 512 bytes minimum.
+ */
+ vlib_buffer_t *indirect_desc =
+ vlib_get_buffer (vm, vring->indirect_buffers[next]);
+ indirect_desc->current_data = 0;
+
+ struct vring_desc *id =
+ (struct vring_desc *) vlib_buffer_get_current (indirect_desc);
+ u32 count = 1;
+ if (vif->type == VIRTIO_IF_TYPE_PCI)
{
- id->flags = VRING_DESC_F_NEXT;
- id->next = vec_len (descs);
- vec_add2_aligned (descs, id, 1, CLIB_CACHE_LINE_BYTES);
- b = vlib_get_buffer (vm, b->next_buffer);
- id->addr = pointer_to_uword (vlib_buffer_get_current (b));
- id->len = b->current_length;
+ d->addr = vlib_physmem_get_pa (vm, id);
+ id->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
+
+ /*
+ * If VIRTIO_F_ANY_LAYOUT is not negotiated, then virtio_net_hdr
+ * should be presented in separate descriptor and data will start
+ * from next descriptor.
+ */
+ if (PREDICT_TRUE
+ (vif->features & VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)))
+ id->len = b->current_length + hdr_sz;
+ else
+ {
+ id->len = hdr_sz;
+ id->flags = VRING_DESC_F_NEXT;
+ id->next = count;
+ count++;
+ id++;
+ id->addr = vlib_buffer_get_current_pa (vm, b);
+ id->len = b->current_length;
+ }
+ while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
+ {
+ id->flags = VRING_DESC_F_NEXT;
+ id->next = count;
+ count++;
+ id++;
+ b = vlib_get_buffer (vm, b->next_buffer);
+ id->addr = vlib_buffer_get_current_pa (vm, b);
+ id->len = b->current_length;
+ }
}
-
- d->addr = pointer_to_uword (descs);
- d->len = vec_len (descs) * sizeof (struct vring_desc);
+ else /* VIRTIO_IF_TYPE_TAP */
+ {
+ d->addr = pointer_to_uword (id);
+ /* first buffer in chain */
+ id->addr = pointer_to_uword (vlib_buffer_get_current (b)) - hdr_sz;
+ id->len = b->current_length + hdr_sz;
+
+ while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
+ {
+ id->flags = VRING_DESC_F_NEXT;
+ id->next = count;
+ count++;
+ id++;
+ b = vlib_get_buffer (vm, b->next_buffer);
+ id->addr = pointer_to_uword (vlib_buffer_get_current (b));
+ id->len = b->current_length;
+ }
+ }
+ id->flags = 0;
+ id->next = 0;
+ d->len = count * sizeof (struct vring_desc);
d->flags = VRING_DESC_F_INDIRECT;
}
vring->buffers[next] = bi;
return n_added;
}
-
static_always_inline uword
virtio_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame, virtio_if_t * vif)
+ vlib_frame_t * frame, virtio_if_t * vif,
+ int do_gso)
{
- u8 qid = 0;
u16 n_left = frame->n_vectors;
- virtio_vring_t *vring = vec_elt_at_index (vif->vrings, (qid << 1) + 1);
+ virtio_vring_t *vring;
+ u16 qid = vm->thread_index % vif->num_txqs;
+ vring = vec_elt_at_index (vif->txq_vrings, qid);
u16 used, next, avail;
u16 sz = vring->size;
u16 mask = sz - 1;
- u32 *buffers = vlib_frame_args (frame);
+ u32 *buffers = vlib_frame_vector_args (frame);
+
+ clib_spinlock_lock_if_init (&vring->lockp);
+
+ if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0 &&
+ (vring->last_kick_avail_idx != vring->avail->idx))
+ virtio_kick (vm, vring, vif);
/* free consumed buffers */
virtio_free_used_desc (vm, vring);
while (n_left && used < sz)
{
- u16 n_added;
- n_added = add_buffer_to_slot (vm, vring, buffers[0], avail, next, mask);
+ u16 n_added = 0;
+ n_added =
+ add_buffer_to_slot (vm, vif, vring, buffers[0], avail, next, mask,
+ do_gso);
+ if (!n_added)
+ break;
avail += n_added;
next = (next + n_added) & mask;
used += n_added;
vring->desc_next = next;
vring->desc_in_use = used;
if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0)
- {
- u64 x = 1;
- CLIB_UNUSED (int r) = write (vring->kick_fd, &x, sizeof (x));
- }
+ virtio_kick (vm, vring, vif);
}
-
if (n_left)
{
- vlib_error_count (vm, node->node_index, TAP_TX_ERROR_NO_FREE_SLOTS,
+ vlib_error_count (vm, node->node_index, VIRTIO_TX_ERROR_NO_FREE_SLOTS,
n_left);
vlib_buffer_free (vm, buffers, n_left);
}
+ clib_spinlock_unlock_if_init (&vring->lockp);
+
return frame->n_vectors - n_left;
}
-static uword
-virtio_interface_tx (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VNET_DEVICE_CLASS_TX_FN (virtio_device_class) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
virtio_main_t *nm = &virtio_main;
vnet_interface_output_runtime_t *rund = (void *) node->runtime_data;
virtio_if_t *vif = pool_elt_at_index (nm->interfaces, rund->dev_instance);
+ vnet_main_t *vnm = vnet_get_main ();
- return virtio_interface_tx_inline (vm, node, frame, vif);
+ if (vnm->interface_main.gso_interface_count > 0)
+ return virtio_interface_tx_inline (vm, node, frame, vif, 1 /* do_gso */ );
+ else
+ return virtio_interface_tx_inline (vm, node, frame, vif,
+ 0 /* no do_gso */ );
}
static void
virtio_main_t *mm = &virtio_main;
vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
- virtio_vring_t *vring = vec_elt_at_index (vif->vrings, qid);
+ virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, qid);
+
+ if (vif->type == VIRTIO_IF_TYPE_PCI && !(vif->support_int_mode))
+ {
+ vring->avail->flags |= VIRTIO_RING_FLAG_MASK_INT;
+ return clib_error_return (0, "interrupt mode is not supported");
+ }
if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
vring->avail->flags |= VIRTIO_RING_FLAG_MASK_INT;
virtio_main_t *mm = &virtio_main;
vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
- static clib_error_t *error = 0;
if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
else
vif->flags &= ~VIRTIO_IF_FLAG_ADMIN_UP;
- return error;
return 0;
}
/* *INDENT-OFF* */
VNET_DEVICE_CLASS (virtio_device_class) = {
.name = "virtio",
- .tx_function = virtio_interface_tx,
.format_device_name = format_virtio_device_name,
.format_device = format_virtio_device,
.format_tx_trace = format_virtio_tx_trace,
- .tx_function_n_errors = TAP_TX_N_ERROR,
+ .tx_function_n_errors = VIRTIO_TX_N_ERROR,
.tx_function_error_strings = virtio_tx_func_error_strings,
.rx_redirect_to_node = virtio_set_interface_next_node,
.clear_counters = virtio_clear_hw_interface_counters,
.subif_add_del_function = virtio_subif_add_del_function,
.rx_mode_change_function = virtio_interface_rx_mode_change,
};
-
-VLIB_DEVICE_TX_FUNCTION_MULTIARCH(virtio_device_class,
- virtio_interface_tx)
/* *INDENT-ON* */
/*