21 #include <sys/ioctl.h> 22 #include <sys/socket.h> 25 #include <sys/types.h> 27 #include <netinet/in.h> 30 #include <linux/if_arp.h> 31 #include <linux/if_tun.h> 54 #define VHOST_USER_TX_COPY_THRESHOLD (VHOST_USER_COPY_ARRAY_N - 40) 58 #define foreach_vhost_user_tx_func_error \ 60 _(NOT_READY, "vhost vring not ready") \ 61 _(DOWN, "vhost interface is down") \ 62 _(PKT_DROP_NOBUF, "tx packet drops (no available descriptors)") \ 63 _(PKT_DROP_NOMRG, "tx packet drops (cannot merge descriptors)") \ 64 _(MMAP_FAIL, "mmap failure") \ 65 _(INDIRECT_OVERFLOW, "indirect descriptor table overflow") 69 #define _(f,s) VHOST_USER_TX_FUNC_ERROR_##f, 81 static __clib_unused
u8 *
85 u32 show_dev_instance = ~0;
91 if (show_dev_instance != ~0)
92 i = show_dev_instance;
94 s =
format (s,
"VirtualEthernet0/0/%d", i);
98 static __clib_unused
int 109 DBG_SOCK (
"renumbered vhost-user interface dev_instance %d to %d",
122 return __sync_lock_test_and_set (vui->
vring_locks[qid], 1);
152 vring_desc_t *hdr_desc = 0;
155 memset (t, 0,
sizeof (*t));
159 hdr_desc = &rxvq->
desc[desc_current];
170 if (!(rxvq->
desc[desc_current].flags & VIRTQ_DESC_F_NEXT) &&
171 !(rxvq->
desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT))
181 u16 copy_len,
u32 * map_hint)
183 void *dst0, *dst1, *dst2, *dst3;
205 clib_memcpy (dst0, (
void *) cpy[0].src, cpy[0].len);
206 clib_memcpy (dst1, (
void *) cpy[1].src, cpy[1].len);
233 u32 n_left = frame->n_vectors;
249 error = VHOST_USER_TX_FUNC_ERROR_DOWN;
255 error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
261 (vui->per_cpu_tx_qid, thread_index));
262 rxvq = &vui->vrings[qid];
267 error = VHOST_USER_TX_FUNC_ERROR_NONE;
273 u16 desc_head, desc_index, desc_len;
274 vring_desc_t *desc_table;
275 uword buffer_map_addr;
290 vui, qid / 2, b0, rxvq);
295 error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
299 desc_table = rxvq->
desc;
300 desc_head = desc_index =
308 (rxvq->
desc[desc_head].len < sizeof (vring_desc_t)))
310 error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
318 error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
324 desc_len = vui->virtio_net_hdr_sz;
325 buffer_map_addr = desc_table[desc_index].addr;
326 buffer_len = desc_table[desc_index].len;
330 virtio_net_hdr_mrg_rxbuf_t *hdr =
334 hdr->hdr.gso_type = 0;
335 hdr->num_buffers = 1;
340 cpy->
len = vui->virtio_net_hdr_sz;
341 cpy->
dst = buffer_map_addr;
345 buffer_map_addr += vui->virtio_net_hdr_sz;
346 buffer_len -= vui->virtio_net_hdr_sz;
356 desc_index = desc_table[desc_index].next;
357 buffer_map_addr = desc_table[desc_index].addr;
358 buffer_len = desc_table[desc_index].len;
360 else if (vui->virtio_net_hdr_sz == 12)
362 virtio_net_hdr_mrg_rxbuf_t *hdr =
385 error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
389 desc_table = rxvq->
desc;
390 desc_head = desc_index =
393 (rxvq->
desc[desc_head].flags & VIRTQ_DESC_F_INDIRECT))
398 (rxvq->
desc[desc_head].len < sizeof (vring_desc_t)))
400 error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
406 rxvq->
desc[desc_index].addr,
409 error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
414 buffer_map_addr = desc_table[desc_index].addr;
415 buffer_len = desc_table[desc_index].len;
419 error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOMRG;
427 cpy->
len = bytes_left;
428 cpy->
len = (cpy->
len > buffer_len) ? buffer_len : cpy->
len;
429 cpy->
dst = buffer_map_addr;
433 bytes_left -= cpy->
len;
434 buffer_len -= cpy->
len;
435 buffer_map_addr += cpy->
len;
436 desc_len += cpy->
len;
445 (current_b0->
flags & VLIB_BUFFER_NEXT_PRESENT))
482 copy_len, &map_hint)))
485 VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
501 copy_len, &map_hint)))
504 VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
523 if (n_left && (error == VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF) && retry)
542 if (
PREDICT_FALSE (n_left && error != VHOST_USER_TX_FUNC_ERROR_NONE))
548 thread_index, vui->sw_if_index, n_left);
552 return frame->n_vectors;
607 txvq->
used->flags = 0;
610 clib_warning (
"BUG: unhandled mode %d changed for if %d queue %d", mode,
635 #ifndef CLIB_MARCH_VARIANT 638 .name =
"vhost-user",
652 static void __clib_constructor
static __clib_unused u8 * format_vhost_user_interface_name(u8 *s, va_list *args)
static __clib_unused int vhost_user_name_renumber(vnet_hw_interface_t *hi, u32 new_dev_instance)
static __clib_unused clib_error_t * vhost_user_interface_admin_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
static_always_inline int vhost_user_vring_try_lock(vhost_user_intf_t *vui, u32 qid)
Try once to lock the vring.
u32 virtio_ring_flags
The device index.
virtio_net_hdr_mrg_rxbuf_t hdr
Length of the first data descriptor.
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
vhost_cpu_t * cpus
Per-CPU data for vhost-user.
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
vhost_user_tx_func_error_t
#define foreach_vhost_user_tx_func_error
vnet_interface_main_t interface_main
static __clib_unused char * vhost_user_tx_func_error_strings[]
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
#define VHOST_USER_TX_COPY_THRESHOLD
vhost_copy_t copy[VHOST_USER_COPY_ARRAY_N]
uword CLIB_MULTIARCH_FN() vhost_user_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
#define VHOST_USER_EVENT_START_TIMER
#define VRING_AVAIL_F_NO_INTERRUPT
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 thread_index, u32 index, u64 increment)
Increment a simple counter.
#define VNET_HW_INTERFACE_FLAG_LINK_UP
static_always_inline void vhost_user_vring_lock(vhost_user_intf_t *vui, u32 qid)
Spin until the vring is successfully locked.
struct _vnet_device_class vnet_device_class_t
vhost_trace_t * current_trace
vnet_hw_interface_rx_mode
#define static_always_inline
#define vlib_prefetch_buffer_with_index(vm, bi, type)
Prefetch buffer metadata by buffer index The first 64 bytes of buffer contains most header informatio...
static_always_inline u32 vhost_user_tx_copy(vhost_user_intf_t *vui, vhost_copy_t *cpy, u16 copy_len, u32 *map_hint)
vlib_node_function_t __clib_weak vhost_user_tx_avx2
static_always_inline void * map_guest_mem(vhost_user_intf_t *vui, uword addr, u32 *hint)
#define VHOST_VRING_IDX_TX(qid)
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define VRING_USED_F_NO_NOTIFY
#define clib_error_return(e, args...)
static_always_inline u8 * format_vhost_trace(u8 *s, va_list *va)
VNET_DEVICE_CLASS(vhost_user_device_class)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
u16 current_length
Nbytes between current data and the end of this buffer.
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
#define VIRTQ_DESC_F_INDIRECT
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
vhost_user_main_t vhost_user_main
vlib_simple_counter_main_t * sw_if_counters
static_always_inline void vhost_user_vring_unlock(vhost_user_intf_t *vui, u32 qid)
Unlock the vring lock.
uword( vlib_node_function_t)(struct vlib_main_t *vm, struct vlib_node_runtime_t *node, struct vlib_frame_t *frame)
static void __clib_constructor vhost_user_tx_multiarch_select(void)
#define VHOST_VRING_IDX_RX(qid)
vnet_device_class_t vhost_user_device_class
u32 * show_dev_instance_by_real_dev_instance
u16 device_index
The interface queue index (Not the virtio vring idx)
vhost_user_intf_t * vhost_user_interfaces
#define DBG_SOCK(args...)
#define CLIB_PREFETCH(addr, size, type)
static __clib_unused clib_error_t * vhost_user_interface_rx_mode_change(vnet_main_t *vnm, u32 hw_if_index, u32 qid, vnet_hw_interface_rx_mode mode)
#define VHOST_USER_EVENT_STOP_TIMER
#define clib_warning(format, args...)
#define clib_memcpy(a, b, c)
u16 first_desc_len
Runtime queue flags.
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
#define VIRTQ_DESC_F_NEXT
static_always_inline void vhost_user_send_call(vlib_main_t *vm, vhost_user_vring_t *vq)
u32 next_buffer
Next buffer for this linked-list of buffers.
volatile u32 * vring_locks[VHOST_VRING_MAX_N]
static void * vlib_frame_args(vlib_frame_t *f)
Get pointer to frame scalar data.
vlib_node_registration_t vhost_user_send_interrupt_node
(constructor) VLIB_REGISTER_NODE (vhost_user_send_interrupt_node)
static_always_inline void vhost_user_tx_trace(vhost_trace_t *t, vhost_user_intf_t *vui, u16 qid, vlib_buffer_t *b, vhost_user_vring_t *rxvq)
vlib_node_function_t __clib_weak vhost_user_tx_avx512
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
vhost_user_vring_t vrings[VHOST_VRING_MAX_N]
static_always_inline void vhost_user_log_dirty_pages_2(vhost_user_intf_t *vui, u64 addr, u64 len, u8 is_host_address)
#define vhost_user_log_dirty_ring(vui, vq, member)
#define CLIB_MEMORY_BARRIER()
virtio_net_hdr_mrg_rxbuf_t tx_headers[VLIB_FRAME_SIZE]
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
#define CLIB_CACHE_LINE_BYTES
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
#define CLIB_MULTIARCH_FN(fn)