vhost: Added ARMV8 NEON version of function map_guest_mem()
[vpp.git] / src / vnet / devices / virtio / vhost-user.c
1 /*
2  *------------------------------------------------------------------
3  * vhost.c - vhost-user
4  *
5  * Copyright (c) 2014 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <fcntl.h>              /* for open */
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/uio.h>            /* for iovec */
27 #include <netinet/in.h>
28 #include <sys/vfs.h>
29
30 #include <linux/if_arp.h>
31 #include <linux/if_tun.h>
32
33 #include <vlib/vlib.h>
34 #include <vlib/unix/unix.h>
35
36 #include <vnet/ip/ip.h>
37
38 #include <vnet/ethernet/ethernet.h>
39 #include <vnet/devices/devices.h>
40 #include <vnet/feature/feature.h>
41
42 #include <vnet/devices/virtio/vhost-user.h>
43
44 /**
45  * @file
46  * @brief vHost User Device Driver.
47  *
48  * This file contains the source code for vHost User interface.
49  */
50
51
52 #define VHOST_DEBUG_VQ 0
53
54 #define DBG_SOCK(args...)                       \
55   {                                             \
56     vhost_user_main_t *_vum = &vhost_user_main; \
57     if (_vum->debug)                            \
58       clib_warning(args);                       \
59   };
60
61 #if VHOST_DEBUG_VQ == 1
62 #define DBG_VQ(args...) clib_warning(args);
63 #else
64 #define DBG_VQ(args...)
65 #endif
66
67 /*
68  * When an RX queue is down but active, received packets
69  * must be discarded. This value controls up to how many
70  * packets will be discarded during each round.
71  */
72 #define VHOST_USER_DOWN_DISCARD_COUNT 256
73
74 /*
75  * When the number of available buffers gets under this threshold,
76  * RX node will start discarding packets.
77  */
78 #define VHOST_USER_RX_BUFFER_STARVATION 32
79
80 /*
81  * On the receive side, the host should free descriptors as soon
82  * as possible in order to avoid TX drop in the VM.
83  * This value controls the number of copy operations that are stacked
84  * before copy is done for all and descriptors are given back to
85  * the guest.
86  * The value 64 was obtained by testing (48 and 128 were not as good).
87  */
88 #define VHOST_USER_RX_COPY_THRESHOLD 64
89 /*
90  * On the transmit side, we keep processing the buffers from vlib in the while
91  * loop and prepare the copy order to be executed later. However, the static
92  * array which we keep the copy order is limited to VHOST_USER_COPY_ARRAY_N
93  * entries. In order to not corrupt memory, we have to do the copy when the
94  * static array reaches the copy threshold. We subtract 40 in case the code
95  * goes into the inner loop for a maximum of 64k frames which may require
96  * more array entries.
97  */
98 #define VHOST_USER_TX_COPY_THRESHOLD (VHOST_USER_COPY_ARRAY_N - 40)
99
100 #define UNIX_GET_FD(unixfd_idx) \
101     (unixfd_idx != ~0) ? \
102         pool_elt_at_index (file_main.file_pool, \
103                            unixfd_idx)->file_descriptor : -1;
104
105 #define foreach_virtio_trace_flags \
106   _ (SIMPLE_CHAINED, 0, "Simple descriptor chaining") \
107   _ (SINGLE_DESC,  1, "Single descriptor packet") \
108   _ (INDIRECT, 2, "Indirect descriptor") \
109   _ (MAP_ERROR, 4, "Memory mapping error")
110
111 typedef enum
112 {
113 #define _(n,i,s) VIRTIO_TRACE_F_##n,
114   foreach_virtio_trace_flags
115 #undef _
116 } virtio_trace_flag_t;
117
118 vlib_node_registration_t vhost_user_input_node;
119
120 #define foreach_vhost_user_tx_func_error      \
121   _(NONE, "no error")  \
122   _(NOT_READY, "vhost vring not ready")  \
123   _(DOWN, "vhost interface is down")  \
124   _(PKT_DROP_NOBUF, "tx packet drops (no available descriptors)")  \
125   _(PKT_DROP_NOMRG, "tx packet drops (cannot merge descriptors)")  \
126   _(MMAP_FAIL, "mmap failure") \
127   _(INDIRECT_OVERFLOW, "indirect descriptor table overflow")
128
129 typedef enum
130 {
131 #define _(f,s) VHOST_USER_TX_FUNC_ERROR_##f,
132   foreach_vhost_user_tx_func_error
133 #undef _
134     VHOST_USER_TX_FUNC_N_ERROR,
135 } vhost_user_tx_func_error_t;
136
137 static char *vhost_user_tx_func_error_strings[] = {
138 #define _(n,s) s,
139   foreach_vhost_user_tx_func_error
140 #undef _
141 };
142
143 #define foreach_vhost_user_input_func_error      \
144   _(NO_ERROR, "no error")  \
145   _(NO_BUFFER, "no available buffer")  \
146   _(MMAP_FAIL, "mmap failure")  \
147   _(INDIRECT_OVERFLOW, "indirect descriptor overflows table")  \
148   _(UNDERSIZED_FRAME, "undersized ethernet frame received (< 14 bytes)") \
149   _(FULL_RX_QUEUE, "full rx queue (possible driver tx drop)")
150
151 typedef enum
152 {
153 #define _(f,s) VHOST_USER_INPUT_FUNC_ERROR_##f,
154   foreach_vhost_user_input_func_error
155 #undef _
156     VHOST_USER_INPUT_FUNC_N_ERROR,
157 } vhost_user_input_func_error_t;
158
159 static char *vhost_user_input_func_error_strings[] = {
160 #define _(n,s) s,
161   foreach_vhost_user_input_func_error
162 #undef _
163 };
164
165 /* *INDENT-OFF* */
166 static vhost_user_main_t vhost_user_main = {
167   .mtu_bytes = 1518,
168 };
169
170 VNET_HW_INTERFACE_CLASS (vhost_interface_class, static) = {
171   .name = "vhost-user",
172 };
173 /* *INDENT-ON* */
174
175 static u8 *
176 format_vhost_user_interface_name (u8 * s, va_list * args)
177 {
178   u32 i = va_arg (*args, u32);
179   u32 show_dev_instance = ~0;
180   vhost_user_main_t *vum = &vhost_user_main;
181
182   if (i < vec_len (vum->show_dev_instance_by_real_dev_instance))
183     show_dev_instance = vum->show_dev_instance_by_real_dev_instance[i];
184
185   if (show_dev_instance != ~0)
186     i = show_dev_instance;
187
188   s = format (s, "VirtualEthernet0/0/%d", i);
189   return s;
190 }
191
192 static int
193 vhost_user_name_renumber (vnet_hw_interface_t * hi, u32 new_dev_instance)
194 {
195   // FIXME: check if the new dev instance is already used
196   vhost_user_main_t *vum = &vhost_user_main;
197   vec_validate_init_empty (vum->show_dev_instance_by_real_dev_instance,
198                            hi->dev_instance, ~0);
199
200   vum->show_dev_instance_by_real_dev_instance[hi->dev_instance] =
201     new_dev_instance;
202
203   DBG_SOCK ("renumbered vhost-user interface dev_instance %d to %d",
204             hi->dev_instance, new_dev_instance);
205
206   return 0;
207 }
208
209 static_always_inline void *
210 map_guest_mem (vhost_user_intf_t * vui, uword addr, u32 * hint)
211 {
212   int i = *hint;
213   if (PREDICT_TRUE ((vui->regions[i].guest_phys_addr <= addr) &&
214                     ((vui->regions[i].guest_phys_addr +
215                       vui->regions[i].memory_size) > addr)))
216     {
217       return (void *) (vui->region_mmap_addr[i] + addr -
218                        vui->regions[i].guest_phys_addr);
219     }
220 #if __SSE4_2__
221   __m128i rl, rh, al, ah, r;
222   al = _mm_set1_epi64x (addr + 1);
223   ah = _mm_set1_epi64x (addr);
224
225   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[0]);
226   rl = _mm_cmpgt_epi64 (al, rl);
227   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[0]);
228   rh = _mm_cmpgt_epi64 (rh, ah);
229   r = _mm_and_si128 (rl, rh);
230
231   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[2]);
232   rl = _mm_cmpgt_epi64 (al, rl);
233   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[2]);
234   rh = _mm_cmpgt_epi64 (rh, ah);
235   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x22);
236
237   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[4]);
238   rl = _mm_cmpgt_epi64 (al, rl);
239   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[4]);
240   rh = _mm_cmpgt_epi64 (rh, ah);
241   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x44);
242
243   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[6]);
244   rl = _mm_cmpgt_epi64 (al, rl);
245   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[6]);
246   rh = _mm_cmpgt_epi64 (rh, ah);
247   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x88);
248
249   r = _mm_shuffle_epi8 (r, _mm_set_epi64x (0, 0x0e060c040a020800));
250   i = __builtin_ctzll (_mm_movemask_epi8 (r) |
251                        (1 << VHOST_MEMORY_MAX_NREGIONS));
252
253   if (i < vui->nregions)
254     {
255       *hint = i;
256       return (void *) (vui->region_mmap_addr[i] + addr -
257                        vui->regions[i].guest_phys_addr);
258     }
259 #elif __aarch64__ && __ARM_NEON
260   uint64x2_t al, ah, rl, rh, r;
261   uint32_t u32 = 0;
262
263   al = vdupq_n_u64 (addr + 1);
264   ah = vdupq_n_u64 (addr);
265
266   /*First Iteration */
267   rl = vld1q_u64 (&vui->region_guest_addr_lo[0]);
268   rl = vcgtq_u64 (al, rl);
269   rh = vld1q_u64 (&vui->region_guest_addr_hi[0]);
270   rh = vcgtq_u64 (rh, ah);
271   r = vandq_u64 (rl, rh);
272   u32 |= (vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1);
273   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 1);
274
275   if (u32)
276     {
277       i = __builtin_ctzll (u32);
278       goto vhost_map_guest_mem_done;
279     }
280
281   /*Second Iteration */
282   rl = vld1q_u64 (&vui->region_guest_addr_lo[2]);
283   rl = vcgtq_u64 (al, rl);
284   rh = vld1q_u64 (&vui->region_guest_addr_hi[2]);
285   rh = vcgtq_u64 (rh, ah);
286   r = vandq_u64 (rl, rh);
287   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1) << 2);
288   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 3);
289
290   if (u32)
291     {
292       i = __builtin_ctzll (u32);
293       goto vhost_map_guest_mem_done;
294     }
295
296   /*Third Iteration */
297   rl = vld1q_u64 (&vui->region_guest_addr_lo[4]);
298   rl = vcgtq_u64 (al, rl);
299   rh = vld1q_u64 (&vui->region_guest_addr_hi[4]);
300   rh = vcgtq_u64 (rh, ah);
301   r = vandq_u64 (rl, rh);
302   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1) << 4);
303   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 5);
304
305   if (u32)
306     {
307       i = __builtin_ctzll (u32);
308       goto vhost_map_guest_mem_done;
309     }
310
311   /*Fourth Iteration */
312   rl = vld1q_u64 (&vui->region_guest_addr_lo[6]);
313   rl = vcgtq_u64 (al, rl);
314   rh = vld1q_u64 (&vui->region_guest_addr_hi[6]);
315   rh = vcgtq_u64 (rh, ah);
316   r = vandq_u64 (rl, rh);
317   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1) << 6);
318   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 7);
319
320   i = __builtin_ctzll (u32 | (1 << VHOST_MEMORY_MAX_NREGIONS));
321
322 vhost_map_guest_mem_done:
323   if (i < vui->nregions)
324     {
325       *hint = i;
326       return (void *) (vui->region_mmap_addr[i] + addr -
327                        vui->regions[i].guest_phys_addr);
328     }
329 #else
330   for (i = 0; i < vui->nregions; i++)
331     {
332       if ((vui->regions[i].guest_phys_addr <= addr) &&
333           ((vui->regions[i].guest_phys_addr + vui->regions[i].memory_size) >
334            addr))
335         {
336           *hint = i;
337           return (void *) (vui->region_mmap_addr[i] + addr -
338                            vui->regions[i].guest_phys_addr);
339         }
340     }
341 #endif
342   DBG_VQ ("failed to map guest mem addr %llx", addr);
343   *hint = 0;
344   return 0;
345 }
346
347 static inline void *
348 map_user_mem (vhost_user_intf_t * vui, uword addr)
349 {
350   int i;
351   for (i = 0; i < vui->nregions; i++)
352     {
353       if ((vui->regions[i].userspace_addr <= addr) &&
354           ((vui->regions[i].userspace_addr + vui->regions[i].memory_size) >
355            addr))
356         {
357           return (void *) (vui->region_mmap_addr[i] + addr -
358                            vui->regions[i].userspace_addr);
359         }
360     }
361   return 0;
362 }
363
364 static long
365 get_huge_page_size (int fd)
366 {
367   struct statfs s;
368   fstatfs (fd, &s);
369   return s.f_bsize;
370 }
371
372 static void
373 unmap_all_mem_regions (vhost_user_intf_t * vui)
374 {
375   int i, r;
376   for (i = 0; i < vui->nregions; i++)
377     {
378       if (vui->region_mmap_addr[i] != MAP_FAILED)
379         {
380
381           long page_sz = get_huge_page_size (vui->region_mmap_fd[i]);
382
383           ssize_t map_sz = (vui->regions[i].memory_size +
384                             vui->regions[i].mmap_offset +
385                             page_sz - 1) & ~(page_sz - 1);
386
387           r =
388             munmap (vui->region_mmap_addr[i] - vui->regions[i].mmap_offset,
389                     map_sz);
390
391           DBG_SOCK
392             ("unmap memory region %d addr 0x%lx len 0x%lx page_sz 0x%x", i,
393              vui->region_mmap_addr[i], map_sz, page_sz);
394
395           vui->region_mmap_addr[i] = MAP_FAILED;
396
397           if (r == -1)
398             {
399               clib_warning ("failed to unmap memory region (errno %d)",
400                             errno);
401             }
402           close (vui->region_mmap_fd[i]);
403         }
404     }
405   vui->nregions = 0;
406 }
407
408 static void
409 vhost_user_tx_thread_placement (vhost_user_intf_t * vui)
410 {
411   //Let's try to assign one queue to each thread
412   u32 qid = 0;
413   u32 thread_index = 0;
414   vui->use_tx_spinlock = 0;
415   while (1)
416     {
417       for (qid = 0; qid < VHOST_VRING_MAX_N / 2; qid++)
418         {
419           vhost_user_vring_t *rxvq = &vui->vrings[VHOST_VRING_IDX_RX (qid)];
420           if (!rxvq->started || !rxvq->enabled)
421             continue;
422
423           vui->per_cpu_tx_qid[thread_index] = qid;
424           thread_index++;
425           if (thread_index == vlib_get_thread_main ()->n_vlib_mains)
426             return;
427         }
428       //We need to loop, meaning the spinlock has to be used
429       vui->use_tx_spinlock = 1;
430       if (thread_index == 0)
431         {
432           //Could not find a single valid one
433           for (thread_index = 0;
434                thread_index < vlib_get_thread_main ()->n_vlib_mains;
435                thread_index++)
436             {
437               vui->per_cpu_tx_qid[thread_index] = 0;
438             }
439           return;
440         }
441     }
442 }
443
444 /**
445  * @brief Unassign existing interface/queue to thread mappings and re-assign
446  * new interface/queue to thread mappings
447  */
448 static void
449 vhost_user_rx_thread_placement ()
450 {
451   vhost_user_main_t *vum = &vhost_user_main;
452   vhost_user_intf_t *vui;
453   vhost_user_vring_t *txvq;
454   vnet_main_t *vnm = vnet_get_main ();
455   u32 qid;
456   int rv;
457   u16 *queue;
458
459   // Scrap all existing mappings for all interfaces/queues
460   /* *INDENT-OFF* */
461   pool_foreach (vui, vum->vhost_user_interfaces, {
462       vec_foreach (queue, vui->rx_queues)
463         {
464           rv = vnet_hw_interface_unassign_rx_thread (vnm, vui->hw_if_index,
465                                                      *queue);
466           if (rv)
467             clib_warning ("Warning: unable to unassign interface %d, "
468                           "queue %d: rc=%d", vui->hw_if_index, *queue, rv);
469         }
470       vec_reset_length (vui->rx_queues);
471   });
472   /* *INDENT-ON* */
473
474   // Create the rx_queues for all interfaces
475   /* *INDENT-OFF* */
476   pool_foreach (vui, vum->vhost_user_interfaces, {
477       for (qid = 0; qid < VHOST_VRING_MAX_N / 2; qid++)
478         {
479           txvq = &vui->vrings[VHOST_VRING_IDX_TX (qid)];
480           if (txvq->started)
481             {
482               if (txvq->mode == VNET_HW_INTERFACE_RX_MODE_UNKNOWN)
483                 /* Set polling as the default */
484                 txvq->mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
485               vec_add1 (vui->rx_queues, qid);
486             }
487         }
488   });
489   /* *INDENT-ON* */
490
491   // Assign new mappings for all interfaces/queues
492   /* *INDENT-OFF* */
493   pool_foreach (vui, vum->vhost_user_interfaces, {
494       vnet_hw_interface_set_input_node (vnm, vui->hw_if_index,
495                                         vhost_user_input_node.index);
496       vec_foreach (queue, vui->rx_queues)
497         {
498           vnet_hw_interface_assign_rx_thread (vnm, vui->hw_if_index, *queue,
499                                               ~0);
500           txvq = &vui->vrings[VHOST_VRING_IDX_TX (*queue)];
501           rv = vnet_hw_interface_set_rx_mode (vnm, vui->hw_if_index, *queue,
502                                               txvq->mode);
503           if (rv)
504             clib_warning ("Warning: unable to set rx mode for interface %d, "
505                           "queue %d: rc=%d", vui->hw_if_index, *queue, rv);
506         }
507   });
508   /* *INDENT-ON* */
509 }
510
511 /** @brief Returns whether at least one TX and one RX vring are enabled */
512 int
513 vhost_user_intf_ready (vhost_user_intf_t * vui)
514 {
515   int i, found[2] = { };        //RX + TX
516
517   for (i = 0; i < VHOST_VRING_MAX_N; i++)
518     if (vui->vrings[i].started && vui->vrings[i].enabled)
519       found[i & 1] = 1;
520
521   return found[0] && found[1];
522 }
523
524 static void
525 vhost_user_update_iface_state (vhost_user_intf_t * vui)
526 {
527   /* if we have pointers to descriptor table, go up */
528   int is_up = vhost_user_intf_ready (vui);
529   if (is_up != vui->is_up)
530     {
531       DBG_SOCK ("interface %d %s", vui->sw_if_index,
532                 is_up ? "ready" : "down");
533       vnet_hw_interface_set_flags (vnet_get_main (), vui->hw_if_index,
534                                    is_up ? VNET_HW_INTERFACE_FLAG_LINK_UP :
535                                    0);
536       vui->is_up = is_up;
537     }
538   vhost_user_rx_thread_placement ();
539   vhost_user_tx_thread_placement (vui);
540 }
541
542 static void
543 vhost_user_set_interrupt_pending (vhost_user_intf_t * vui, u32 ifq)
544 {
545   u32 qid;
546   vnet_main_t *vnm = vnet_get_main ();
547
548   qid = ifq & 0xff;
549   if ((qid & 1) == 0)
550     /* Only care about the odd number, or TX, virtqueue */
551     return;
552
553   if (vhost_user_intf_ready (vui))
554     // qid >> 1 is to convert virtqueue number to vring queue index
555     vnet_device_input_set_interrupt_pending (vnm, vui->hw_if_index, qid >> 1);
556 }
557
558 static clib_error_t *
559 vhost_user_callfd_read_ready (clib_file_t * uf)
560 {
561   __attribute__ ((unused)) int n;
562   u8 buff[8];
563
564   n = read (uf->file_descriptor, ((char *) &buff), 8);
565
566   return 0;
567 }
568
569 static clib_error_t *
570 vhost_user_kickfd_read_ready (clib_file_t * uf)
571 {
572   __attribute__ ((unused)) int n;
573   u8 buff[8];
574   vhost_user_intf_t *vui =
575     pool_elt_at_index (vhost_user_main.vhost_user_interfaces,
576                        uf->private_data >> 8);
577   u32 qid = uf->private_data & 0xff;
578
579   n = read (uf->file_descriptor, ((char *) &buff), 8);
580   DBG_SOCK ("if %d KICK queue %d", uf->private_data >> 8, qid);
581   if (!vui->vrings[qid].started ||
582       (vhost_user_intf_ready (vui) != vui->is_up))
583     {
584       vlib_worker_thread_barrier_sync (vlib_get_main ());
585       vui->vrings[qid].started = 1;
586       vhost_user_update_iface_state (vui);
587       vlib_worker_thread_barrier_release (vlib_get_main ());
588     }
589
590   vhost_user_set_interrupt_pending (vui, uf->private_data);
591   return 0;
592 }
593
594 /**
595  * @brief Try once to lock the vring
596  * @return 0 on success, non-zero on failure.
597  */
598 static inline int
599 vhost_user_vring_try_lock (vhost_user_intf_t * vui, u32 qid)
600 {
601   return __sync_lock_test_and_set (vui->vring_locks[qid], 1);
602 }
603
604 /**
605  * @brief Spin until the vring is successfully locked
606  */
607 static inline void
608 vhost_user_vring_lock (vhost_user_intf_t * vui, u32 qid)
609 {
610   while (vhost_user_vring_try_lock (vui, qid))
611     ;
612 }
613
614 /**
615  * @brief Unlock the vring lock
616  */
617 static inline void
618 vhost_user_vring_unlock (vhost_user_intf_t * vui, u32 qid)
619 {
620   *vui->vring_locks[qid] = 0;
621 }
622
623 static inline void
624 vhost_user_vring_init (vhost_user_intf_t * vui, u32 qid)
625 {
626   vhost_user_vring_t *vring = &vui->vrings[qid];
627   memset (vring, 0, sizeof (*vring));
628   vring->kickfd_idx = ~0;
629   vring->callfd_idx = ~0;
630   vring->errfd = -1;
631
632   /*
633    * We have a bug with some qemu 2.5, and this may be a fix.
634    * Feel like interpretation holy text, but this is from vhost-user.txt.
635    * "
636    * One queue pair is enabled initially. More queues are enabled
637    * dynamically, by sending message VHOST_USER_SET_VRING_ENABLE.
638    * "
639    * Don't know who's right, but this is what DPDK does.
640    */
641   if (qid == 0 || qid == 1)
642     vring->enabled = 1;
643 }
644
645 static inline void
646 vhost_user_vring_close (vhost_user_intf_t * vui, u32 qid)
647 {
648   vhost_user_vring_t *vring = &vui->vrings[qid];
649   if (vring->kickfd_idx != ~0)
650     {
651       clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
652                                            vring->kickfd_idx);
653       clib_file_del (&file_main, uf);
654       vring->kickfd_idx = ~0;
655     }
656   if (vring->callfd_idx != ~0)
657     {
658       clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
659                                            vring->callfd_idx);
660       clib_file_del (&file_main, uf);
661       vring->callfd_idx = ~0;
662     }
663   if (vring->errfd != -1)
664     {
665       close (vring->errfd);
666       vring->errfd = -1;
667     }
668   vhost_user_vring_init (vui, qid);
669 }
670
671 static inline void
672 vhost_user_if_disconnect (vhost_user_intf_t * vui)
673 {
674   vnet_main_t *vnm = vnet_get_main ();
675   int q;
676
677   vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
678
679   if (vui->clib_file_index != ~0)
680     {
681       clib_file_del (&file_main, file_main.file_pool + vui->clib_file_index);
682       vui->clib_file_index = ~0;
683     }
684
685   vui->is_up = 0;
686
687   for (q = 0; q < VHOST_VRING_MAX_N; q++)
688     vhost_user_vring_close (vui, q);
689
690   unmap_all_mem_regions (vui);
691   DBG_SOCK ("interface ifindex %d disconnected", vui->sw_if_index);
692 }
693
694 #define VHOST_LOG_PAGE 0x1000
695 static_always_inline void
696 vhost_user_log_dirty_pages_2 (vhost_user_intf_t * vui,
697                               u64 addr, u64 len, u8 is_host_address)
698 {
699   if (PREDICT_TRUE (vui->log_base_addr == 0
700                     || !(vui->features & (1 << FEAT_VHOST_F_LOG_ALL))))
701     {
702       return;
703     }
704   if (is_host_address)
705     {
706       addr = pointer_to_uword (map_user_mem (vui, (uword) addr));
707     }
708   if (PREDICT_FALSE ((addr + len - 1) / VHOST_LOG_PAGE / 8 >= vui->log_size))
709     {
710       DBG_SOCK ("vhost_user_log_dirty_pages(): out of range\n");
711       return;
712     }
713
714   CLIB_MEMORY_BARRIER ();
715   u64 page = addr / VHOST_LOG_PAGE;
716   while (page * VHOST_LOG_PAGE < addr + len)
717     {
718       ((u8 *) vui->log_base_addr)[page / 8] |= 1 << page % 8;
719       page++;
720     }
721 }
722
723 static_always_inline void
724 vhost_user_log_dirty_pages (vhost_user_intf_t * vui, u64 addr, u64 len)
725 {
726   vhost_user_log_dirty_pages_2 (vui, addr, len, 0);
727 }
728
729 #define vhost_user_log_dirty_ring(vui, vq, member) \
730   if (PREDICT_FALSE(vq->log_used)) { \
731     vhost_user_log_dirty_pages(vui, vq->log_guest_addr + STRUCT_OFFSET_OF(vring_used_t, member), \
732                              sizeof(vq->used->member)); \
733   }
734
735 static clib_error_t *
736 vhost_user_socket_read (clib_file_t * uf)
737 {
738   int n, i;
739   int fd, number_of_fds = 0;
740   int fds[VHOST_MEMORY_MAX_NREGIONS];
741   vhost_user_msg_t msg;
742   struct msghdr mh;
743   struct iovec iov[1];
744   vhost_user_main_t *vum = &vhost_user_main;
745   vhost_user_intf_t *vui;
746   struct cmsghdr *cmsg;
747   u8 q;
748   clib_file_t template = { 0 };
749   vnet_main_t *vnm = vnet_get_main ();
750
751   vui = pool_elt_at_index (vum->vhost_user_interfaces, uf->private_data);
752
753   char control[CMSG_SPACE (VHOST_MEMORY_MAX_NREGIONS * sizeof (int))];
754
755   memset (&mh, 0, sizeof (mh));
756   memset (control, 0, sizeof (control));
757
758   for (i = 0; i < VHOST_MEMORY_MAX_NREGIONS; i++)
759     fds[i] = -1;
760
761   /* set the payload */
762   iov[0].iov_base = (void *) &msg;
763   iov[0].iov_len = VHOST_USER_MSG_HDR_SZ;
764
765   mh.msg_iov = iov;
766   mh.msg_iovlen = 1;
767   mh.msg_control = control;
768   mh.msg_controllen = sizeof (control);
769
770   n = recvmsg (uf->file_descriptor, &mh, 0);
771
772   /* Stop workers to avoid end of the world */
773   vlib_worker_thread_barrier_sync (vlib_get_main ());
774
775   if (n != VHOST_USER_MSG_HDR_SZ)
776     {
777       if (n == -1)
778         {
779           DBG_SOCK ("recvmsg returned error %d %s", errno, strerror (errno));
780         }
781       else
782         {
783           DBG_SOCK ("n (%d) != VHOST_USER_MSG_HDR_SZ (%d)",
784                     n, VHOST_USER_MSG_HDR_SZ);
785         }
786       goto close_socket;
787     }
788
789   if (mh.msg_flags & MSG_CTRUNC)
790     {
791       DBG_SOCK ("MSG_CTRUNC is set");
792       goto close_socket;
793     }
794
795   cmsg = CMSG_FIRSTHDR (&mh);
796
797   if (cmsg && (cmsg->cmsg_len > 0) && (cmsg->cmsg_level == SOL_SOCKET) &&
798       (cmsg->cmsg_type == SCM_RIGHTS) &&
799       (cmsg->cmsg_len - CMSG_LEN (0) <=
800        VHOST_MEMORY_MAX_NREGIONS * sizeof (int)))
801     {
802       number_of_fds = (cmsg->cmsg_len - CMSG_LEN (0)) / sizeof (int);
803       clib_memcpy (fds, CMSG_DATA (cmsg), number_of_fds * sizeof (int));
804     }
805
806   /* version 1, no reply bit set */
807   if ((msg.flags & 7) != 1)
808     {
809       DBG_SOCK ("malformed message received. closing socket");
810       goto close_socket;
811     }
812
813   {
814     int rv;
815     rv =
816       read (uf->file_descriptor, ((char *) &msg) + VHOST_USER_MSG_HDR_SZ,
817             msg.size);
818     if (rv < 0)
819       {
820         DBG_SOCK ("read failed %s", strerror (errno));
821         goto close_socket;
822       }
823     else if (rv != msg.size)
824       {
825         DBG_SOCK ("message too short (read %dB should be %dB)", rv, msg.size);
826         goto close_socket;
827       }
828   }
829
830   switch (msg.request)
831     {
832     case VHOST_USER_GET_FEATURES:
833       msg.flags |= 4;
834       msg.u64 = (1ULL << FEAT_VIRTIO_NET_F_MRG_RXBUF) |
835         (1ULL << FEAT_VIRTIO_NET_F_CTRL_VQ) |
836         (1ULL << FEAT_VIRTIO_F_ANY_LAYOUT) |
837         (1ULL << FEAT_VIRTIO_F_INDIRECT_DESC) |
838         (1ULL << FEAT_VHOST_F_LOG_ALL) |
839         (1ULL << FEAT_VIRTIO_NET_F_GUEST_ANNOUNCE) |
840         (1ULL << FEAT_VIRTIO_NET_F_MQ) |
841         (1ULL << FEAT_VHOST_USER_F_PROTOCOL_FEATURES) |
842         (1ULL << FEAT_VIRTIO_F_VERSION_1);
843       msg.u64 &= vui->feature_mask;
844       msg.size = sizeof (msg.u64);
845       DBG_SOCK ("if %d msg VHOST_USER_GET_FEATURES - reply 0x%016llx",
846                 vui->hw_if_index, msg.u64);
847       break;
848
849     case VHOST_USER_SET_FEATURES:
850       DBG_SOCK ("if %d msg VHOST_USER_SET_FEATURES features 0x%016llx",
851                 vui->hw_if_index, msg.u64);
852
853       vui->features = msg.u64;
854
855       if (vui->features &
856           ((1 << FEAT_VIRTIO_NET_F_MRG_RXBUF) |
857            (1ULL << FEAT_VIRTIO_F_VERSION_1)))
858         vui->virtio_net_hdr_sz = 12;
859       else
860         vui->virtio_net_hdr_sz = 10;
861
862       vui->is_any_layout =
863         (vui->features & (1 << FEAT_VIRTIO_F_ANY_LAYOUT)) ? 1 : 0;
864
865       ASSERT (vui->virtio_net_hdr_sz < VLIB_BUFFER_PRE_DATA_SIZE);
866       vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
867       vui->is_up = 0;
868
869       /*for (q = 0; q < VHOST_VRING_MAX_N; q++)
870          vhost_user_vring_close(&vui->vrings[q]); */
871
872       break;
873
874     case VHOST_USER_SET_MEM_TABLE:
875       DBG_SOCK ("if %d msg VHOST_USER_SET_MEM_TABLE nregions %d",
876                 vui->hw_if_index, msg.memory.nregions);
877
878       if ((msg.memory.nregions < 1) ||
879           (msg.memory.nregions > VHOST_MEMORY_MAX_NREGIONS))
880         {
881
882           DBG_SOCK ("number of mem regions must be between 1 and %i",
883                     VHOST_MEMORY_MAX_NREGIONS);
884
885           goto close_socket;
886         }
887
888       if (msg.memory.nregions != number_of_fds)
889         {
890           DBG_SOCK ("each memory region must have FD");
891           goto close_socket;
892         }
893       unmap_all_mem_regions (vui);
894       for (i = 0; i < msg.memory.nregions; i++)
895         {
896           clib_memcpy (&(vui->regions[i]), &msg.memory.regions[i],
897                        sizeof (vhost_user_memory_region_t));
898
899           long page_sz = get_huge_page_size (fds[i]);
900
901           /* align size to page */
902           ssize_t map_sz = (vui->regions[i].memory_size +
903                             vui->regions[i].mmap_offset +
904                             page_sz - 1) & ~(page_sz - 1);
905
906           vui->region_mmap_addr[i] = mmap (0, map_sz, PROT_READ | PROT_WRITE,
907                                            MAP_SHARED, fds[i], 0);
908           vui->region_guest_addr_lo[i] = vui->regions[i].guest_phys_addr;
909           vui->region_guest_addr_hi[i] = vui->regions[i].guest_phys_addr +
910             vui->regions[i].memory_size;
911
912           DBG_SOCK
913             ("map memory region %d addr 0 len 0x%lx fd %d mapped 0x%lx "
914              "page_sz 0x%x", i, map_sz, fds[i], vui->region_mmap_addr[i],
915              page_sz);
916
917           if (vui->region_mmap_addr[i] == MAP_FAILED)
918             {
919               clib_warning ("failed to map memory. errno is %d", errno);
920               goto close_socket;
921             }
922           vui->region_mmap_addr[i] += vui->regions[i].mmap_offset;
923           vui->region_mmap_fd[i] = fds[i];
924
925           vui->nregions++;
926         }
927       break;
928
929     case VHOST_USER_SET_VRING_NUM:
930       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_NUM idx %d num %d",
931                 vui->hw_if_index, msg.state.index, msg.state.num);
932
933       if ((msg.state.num > 32768) ||    /* maximum ring size is 32768 */
934           (msg.state.num == 0) ||       /* it cannot be zero */
935           ((msg.state.num - 1) & msg.state.num))        /* must be power of 2 */
936         goto close_socket;
937       vui->vrings[msg.state.index].qsz_mask = msg.state.num - 1;
938       break;
939
940     case VHOST_USER_SET_VRING_ADDR:
941       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_ADDR idx %d",
942                 vui->hw_if_index, msg.state.index);
943
944       if (msg.state.index >= VHOST_VRING_MAX_N)
945         {
946           DBG_SOCK ("invalid vring index VHOST_USER_SET_VRING_ADDR:"
947                     " %d >= %d", msg.state.index, VHOST_VRING_MAX_N);
948           goto close_socket;
949         }
950
951       if (msg.size < sizeof (msg.addr))
952         {
953           DBG_SOCK ("vhost message is too short (%d < %d)",
954                     msg.size, sizeof (msg.addr));
955           goto close_socket;
956         }
957
958       vui->vrings[msg.state.index].desc = (vring_desc_t *)
959         map_user_mem (vui, msg.addr.desc_user_addr);
960       vui->vrings[msg.state.index].used = (vring_used_t *)
961         map_user_mem (vui, msg.addr.used_user_addr);
962       vui->vrings[msg.state.index].avail = (vring_avail_t *)
963         map_user_mem (vui, msg.addr.avail_user_addr);
964
965       if ((vui->vrings[msg.state.index].desc == NULL) ||
966           (vui->vrings[msg.state.index].used == NULL) ||
967           (vui->vrings[msg.state.index].avail == NULL))
968         {
969           DBG_SOCK ("failed to map user memory for hw_if_index %d",
970                     vui->hw_if_index);
971           goto close_socket;
972         }
973
974       vui->vrings[msg.state.index].log_guest_addr = msg.addr.log_guest_addr;
975       vui->vrings[msg.state.index].log_used =
976         (msg.addr.flags & (1 << VHOST_VRING_F_LOG)) ? 1 : 0;
977
978       /* Spec says: If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated,
979          the ring is initialized in an enabled state. */
980       if (!(vui->features & (1 << FEAT_VHOST_USER_F_PROTOCOL_FEATURES)))
981         {
982           vui->vrings[msg.state.index].enabled = 1;
983         }
984
985       vui->vrings[msg.state.index].last_used_idx =
986         vui->vrings[msg.state.index].last_avail_idx =
987         vui->vrings[msg.state.index].used->idx;
988
989       /* tell driver that we don't want interrupts */
990       vui->vrings[msg.state.index].used->flags = VRING_USED_F_NO_NOTIFY;
991       break;
992
993     case VHOST_USER_SET_OWNER:
994       DBG_SOCK ("if %d msg VHOST_USER_SET_OWNER", vui->hw_if_index);
995       break;
996
997     case VHOST_USER_RESET_OWNER:
998       DBG_SOCK ("if %d msg VHOST_USER_RESET_OWNER", vui->hw_if_index);
999       break;
1000
1001     case VHOST_USER_SET_VRING_CALL:
1002       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_CALL %d",
1003                 vui->hw_if_index, msg.u64);
1004
1005       q = (u8) (msg.u64 & 0xFF);
1006
1007       /* if there is old fd, delete and close it */
1008       if (vui->vrings[q].callfd_idx != ~0)
1009         {
1010           clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
1011                                                vui->vrings[q].callfd_idx);
1012           clib_file_del (&file_main, uf);
1013           vui->vrings[q].callfd_idx = ~0;
1014         }
1015
1016       if (!(msg.u64 & VHOST_USER_VRING_NOFD_MASK))
1017         {
1018           if (number_of_fds != 1)
1019             {
1020               DBG_SOCK ("More than one fd received !");
1021               goto close_socket;
1022             }
1023
1024           template.read_function = vhost_user_callfd_read_ready;
1025           template.file_descriptor = fds[0];
1026           template.private_data =
1027             ((vui - vhost_user_main.vhost_user_interfaces) << 8) + q;
1028           vui->vrings[q].callfd_idx = clib_file_add (&file_main, &template);
1029         }
1030       else
1031         vui->vrings[q].callfd_idx = ~0;
1032       break;
1033
1034     case VHOST_USER_SET_VRING_KICK:
1035       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_KICK %d",
1036                 vui->hw_if_index, msg.u64);
1037
1038       q = (u8) (msg.u64 & 0xFF);
1039
1040       if (vui->vrings[q].kickfd_idx != ~0)
1041         {
1042           clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
1043                                                vui->vrings[q].kickfd_idx);
1044           clib_file_del (&file_main, uf);
1045           vui->vrings[q].kickfd_idx = ~0;
1046         }
1047
1048       if (!(msg.u64 & VHOST_USER_VRING_NOFD_MASK))
1049         {
1050           if (number_of_fds != 1)
1051             {
1052               DBG_SOCK ("More than one fd received !");
1053               goto close_socket;
1054             }
1055
1056           template.read_function = vhost_user_kickfd_read_ready;
1057           template.file_descriptor = fds[0];
1058           template.private_data =
1059             (((uword) (vui - vhost_user_main.vhost_user_interfaces)) << 8) +
1060             q;
1061           vui->vrings[q].kickfd_idx = clib_file_add (&file_main, &template);
1062         }
1063       else
1064         {
1065           //When no kickfd is set, the queue is initialized as started
1066           vui->vrings[q].kickfd_idx = ~0;
1067           vui->vrings[q].started = 1;
1068         }
1069
1070       break;
1071
1072     case VHOST_USER_SET_VRING_ERR:
1073       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_ERR %d",
1074                 vui->hw_if_index, msg.u64);
1075
1076       q = (u8) (msg.u64 & 0xFF);
1077
1078       if (vui->vrings[q].errfd != -1)
1079         close (vui->vrings[q].errfd);
1080
1081       if (!(msg.u64 & VHOST_USER_VRING_NOFD_MASK))
1082         {
1083           if (number_of_fds != 1)
1084             goto close_socket;
1085
1086           vui->vrings[q].errfd = fds[0];
1087         }
1088       else
1089         vui->vrings[q].errfd = -1;
1090
1091       break;
1092
1093     case VHOST_USER_SET_VRING_BASE:
1094       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_BASE idx %d num %d",
1095                 vui->hw_if_index, msg.state.index, msg.state.num);
1096
1097       vui->vrings[msg.state.index].last_avail_idx = msg.state.num;
1098       break;
1099
1100     case VHOST_USER_GET_VRING_BASE:
1101       if (msg.state.index >= VHOST_VRING_MAX_N)
1102         {
1103           DBG_SOCK ("invalid vring index VHOST_USER_GET_VRING_BASE:"
1104                     " %d >= %d", msg.state.index, VHOST_VRING_MAX_N);
1105           goto close_socket;
1106         }
1107
1108       /*
1109        * Copy last_avail_idx from the vring before closing it because
1110        * closing the vring also initializes the vring last_avail_idx
1111        */
1112       msg.state.num = vui->vrings[msg.state.index].last_avail_idx;
1113       msg.flags |= 4;
1114       msg.size = sizeof (msg.state);
1115
1116       /* Spec says: Client must [...] stop ring upon receiving VHOST_USER_GET_VRING_BASE. */
1117       vhost_user_vring_close (vui, msg.state.index);
1118       DBG_SOCK ("if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
1119                 vui->hw_if_index, msg.state.index, msg.state.num);
1120       break;
1121
1122     case VHOST_USER_NONE:
1123       DBG_SOCK ("if %d msg VHOST_USER_NONE", vui->hw_if_index);
1124
1125       break;
1126
1127     case VHOST_USER_SET_LOG_BASE:
1128       {
1129         DBG_SOCK ("if %d msg VHOST_USER_SET_LOG_BASE", vui->hw_if_index);
1130
1131         if (msg.size != sizeof (msg.log))
1132           {
1133             DBG_SOCK
1134               ("invalid msg size for VHOST_USER_SET_LOG_BASE: %d instead of %d",
1135                msg.size, sizeof (msg.log));
1136             goto close_socket;
1137           }
1138
1139         if (!
1140             (vui->protocol_features & (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD)))
1141           {
1142             DBG_SOCK
1143               ("VHOST_USER_PROTOCOL_F_LOG_SHMFD not set but VHOST_USER_SET_LOG_BASE received");
1144             goto close_socket;
1145           }
1146
1147         fd = fds[0];
1148         /* align size to page */
1149         long page_sz = get_huge_page_size (fd);
1150         ssize_t map_sz =
1151           (msg.log.size + msg.log.offset + page_sz - 1) & ~(page_sz - 1);
1152
1153         vui->log_base_addr = mmap (0, map_sz, PROT_READ | PROT_WRITE,
1154                                    MAP_SHARED, fd, 0);
1155
1156         DBG_SOCK
1157           ("map log region addr 0 len 0x%lx off 0x%lx fd %d mapped 0x%lx",
1158            map_sz, msg.log.offset, fd, vui->log_base_addr);
1159
1160         if (vui->log_base_addr == MAP_FAILED)
1161           {
1162             clib_warning ("failed to map memory. errno is %d", errno);
1163             goto close_socket;
1164           }
1165
1166         vui->log_base_addr += msg.log.offset;
1167         vui->log_size = msg.log.size;
1168
1169         msg.flags |= 4;
1170         msg.size = sizeof (msg.u64);
1171
1172         break;
1173       }
1174
1175     case VHOST_USER_SET_LOG_FD:
1176       DBG_SOCK ("if %d msg VHOST_USER_SET_LOG_FD", vui->hw_if_index);
1177
1178       break;
1179
1180     case VHOST_USER_GET_PROTOCOL_FEATURES:
1181       msg.flags |= 4;
1182       msg.u64 = (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD) |
1183         (1 << VHOST_USER_PROTOCOL_F_MQ);
1184       msg.size = sizeof (msg.u64);
1185       DBG_SOCK
1186         ("if %d msg VHOST_USER_GET_PROTOCOL_FEATURES - reply 0x%016llx",
1187          vui->hw_if_index, msg.u64);
1188       break;
1189
1190     case VHOST_USER_SET_PROTOCOL_FEATURES:
1191       DBG_SOCK
1192         ("if %d msg VHOST_USER_SET_PROTOCOL_FEATURES features 0x%016llx",
1193          vui->hw_if_index, msg.u64);
1194
1195       vui->protocol_features = msg.u64;
1196
1197       break;
1198
1199     case VHOST_USER_GET_QUEUE_NUM:
1200       msg.flags |= 4;
1201       msg.u64 = VHOST_VRING_MAX_N;
1202       msg.size = sizeof (msg.u64);
1203       DBG_SOCK ("if %d msg VHOST_USER_GET_QUEUE_NUM - reply %d",
1204                 vui->hw_if_index, msg.u64);
1205       break;
1206
1207     case VHOST_USER_SET_VRING_ENABLE:
1208       DBG_SOCK ("if %d VHOST_USER_SET_VRING_ENABLE: %s queue %d",
1209                 vui->hw_if_index, msg.state.num ? "enable" : "disable",
1210                 msg.state.index);
1211       if (msg.state.index >= VHOST_VRING_MAX_N)
1212         {
1213           DBG_SOCK ("invalid vring index VHOST_USER_SET_VRING_ENABLE:"
1214                     " %d >= %d", msg.state.index, VHOST_VRING_MAX_N);
1215           goto close_socket;
1216         }
1217
1218       vui->vrings[msg.state.index].enabled = msg.state.num;
1219       break;
1220
1221     default:
1222       DBG_SOCK ("unknown vhost-user message %d received. closing socket",
1223                 msg.request);
1224       goto close_socket;
1225     }
1226
1227   /* if we need to reply */
1228   if (msg.flags & 4)
1229     {
1230       n =
1231         send (uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
1232       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
1233         {
1234           DBG_SOCK ("could not send message response");
1235           goto close_socket;
1236         }
1237     }
1238
1239   vhost_user_update_iface_state (vui);
1240   vlib_worker_thread_barrier_release (vlib_get_main ());
1241   return 0;
1242
1243 close_socket:
1244   vhost_user_if_disconnect (vui);
1245   vhost_user_update_iface_state (vui);
1246   vlib_worker_thread_barrier_release (vlib_get_main ());
1247   return 0;
1248 }
1249
1250 static clib_error_t *
1251 vhost_user_socket_error (clib_file_t * uf)
1252 {
1253   vlib_main_t *vm = vlib_get_main ();
1254   vhost_user_main_t *vum = &vhost_user_main;
1255   vhost_user_intf_t *vui =
1256     pool_elt_at_index (vum->vhost_user_interfaces, uf->private_data);
1257
1258   DBG_SOCK ("socket error on if %d", vui->sw_if_index);
1259   vlib_worker_thread_barrier_sync (vm);
1260   vhost_user_if_disconnect (vui);
1261   vhost_user_rx_thread_placement ();
1262   vlib_worker_thread_barrier_release (vm);
1263   return 0;
1264 }
1265
1266 static clib_error_t *
1267 vhost_user_socksvr_accept_ready (clib_file_t * uf)
1268 {
1269   int client_fd, client_len;
1270   struct sockaddr_un client;
1271   clib_file_t template = { 0 };
1272   vhost_user_main_t *vum = &vhost_user_main;
1273   vhost_user_intf_t *vui;
1274
1275   vui = pool_elt_at_index (vum->vhost_user_interfaces, uf->private_data);
1276
1277   client_len = sizeof (client);
1278   client_fd = accept (uf->file_descriptor,
1279                       (struct sockaddr *) &client,
1280                       (socklen_t *) & client_len);
1281
1282   if (client_fd < 0)
1283     return clib_error_return_unix (0, "accept");
1284
1285   DBG_SOCK ("New client socket for vhost interface %d", vui->sw_if_index);
1286   template.read_function = vhost_user_socket_read;
1287   template.error_function = vhost_user_socket_error;
1288   template.file_descriptor = client_fd;
1289   template.private_data = vui - vhost_user_main.vhost_user_interfaces;
1290   vui->clib_file_index = clib_file_add (&file_main, &template);
1291   return 0;
1292 }
1293
1294 static clib_error_t *
1295 vhost_user_init (vlib_main_t * vm)
1296 {
1297   clib_error_t *error;
1298   vhost_user_main_t *vum = &vhost_user_main;
1299   vlib_thread_main_t *tm = vlib_get_thread_main ();
1300
1301   error = vlib_call_init_function (vm, ip4_init);
1302   if (error)
1303     return error;
1304
1305   vum->coalesce_frames = 32;
1306   vum->coalesce_time = 1e-3;
1307
1308   vec_validate (vum->cpus, tm->n_vlib_mains - 1);
1309
1310   vhost_cpu_t *cpu;
1311   vec_foreach (cpu, vum->cpus)
1312   {
1313     /* This is actually not necessary as validate already zeroes it
1314      * Just keeping the loop here for later because I am lazy. */
1315     cpu->rx_buffers_len = 0;
1316   }
1317
1318   vum->random = random_default_seed ();
1319
1320   mhash_init_c_string (&vum->if_index_by_sock_name, sizeof (uword));
1321
1322   return 0;
1323 }
1324
1325 VLIB_INIT_FUNCTION (vhost_user_init);
1326
1327 static u8 *
1328 format_vhost_trace (u8 * s, va_list * va)
1329 {
1330   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
1331   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
1332   CLIB_UNUSED (vnet_main_t * vnm) = vnet_get_main ();
1333   vhost_user_main_t *vum = &vhost_user_main;
1334   vhost_trace_t *t = va_arg (*va, vhost_trace_t *);
1335   vhost_user_intf_t *vui = pool_elt_at_index (vum->vhost_user_interfaces,
1336                                               t->device_index);
1337
1338   vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, vui->sw_if_index);
1339
1340   u32 indent = format_get_indent (s);
1341
1342   s = format (s, "%U %U queue %d\n", format_white_space, indent,
1343               format_vnet_sw_interface_name, vnm, sw, t->qid);
1344
1345   s = format (s, "%U virtio flags:\n", format_white_space, indent);
1346 #define _(n,i,st) \
1347           if (t->virtio_ring_flags & (1 << VIRTIO_TRACE_F_##n)) \
1348             s = format (s, "%U  %s %s\n", format_white_space, indent, #n, st);
1349   foreach_virtio_trace_flags
1350 #undef _
1351     s = format (s, "%U virtio_net_hdr first_desc_len %u\n",
1352                 format_white_space, indent, t->first_desc_len);
1353
1354   s = format (s, "%U   flags 0x%02x gso_type %u\n",
1355               format_white_space, indent,
1356               t->hdr.hdr.flags, t->hdr.hdr.gso_type);
1357
1358   if (vui->virtio_net_hdr_sz == 12)
1359     s = format (s, "%U   num_buff %u",
1360                 format_white_space, indent, t->hdr.num_buffers);
1361
1362   return s;
1363 }
1364
1365 void
1366 vhost_user_rx_trace (vhost_trace_t * t,
1367                      vhost_user_intf_t * vui, u16 qid,
1368                      vlib_buffer_t * b, vhost_user_vring_t * txvq)
1369 {
1370   vhost_user_main_t *vum = &vhost_user_main;
1371   u32 last_avail_idx = txvq->last_avail_idx;
1372   u32 desc_current = txvq->avail->ring[last_avail_idx & txvq->qsz_mask];
1373   vring_desc_t *hdr_desc = 0;
1374   virtio_net_hdr_mrg_rxbuf_t *hdr;
1375   u32 hint = 0;
1376
1377   memset (t, 0, sizeof (*t));
1378   t->device_index = vui - vum->vhost_user_interfaces;
1379   t->qid = qid;
1380
1381   hdr_desc = &txvq->desc[desc_current];
1382   if (txvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT)
1383     {
1384       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_INDIRECT;
1385       /* Header is the first here */
1386       hdr_desc = map_guest_mem (vui, txvq->desc[desc_current].addr, &hint);
1387     }
1388   if (txvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT)
1389     {
1390       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_SIMPLE_CHAINED;
1391     }
1392   if (!(txvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT) &&
1393       !(txvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT))
1394     {
1395       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_SINGLE_DESC;
1396     }
1397
1398   t->first_desc_len = hdr_desc ? hdr_desc->len : 0;
1399
1400   if (!hdr_desc || !(hdr = map_guest_mem (vui, hdr_desc->addr, &hint)))
1401     {
1402       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_MAP_ERROR;
1403     }
1404   else
1405     {
1406       u32 len = vui->virtio_net_hdr_sz;
1407       memcpy (&t->hdr, hdr, len > hdr_desc->len ? hdr_desc->len : len);
1408     }
1409 }
1410
1411 static inline void
1412 vhost_user_send_call (vlib_main_t * vm, vhost_user_vring_t * vq)
1413 {
1414   vhost_user_main_t *vum = &vhost_user_main;
1415   u64 x = 1;
1416   int fd = UNIX_GET_FD (vq->callfd_idx);
1417   int rv;
1418
1419   rv = write (fd, &x, sizeof (x));
1420   if (rv <= 0)
1421     {
1422       clib_unix_warning
1423         ("Error: Could not write to unix socket for callfd %d", fd);
1424       return;
1425     }
1426
1427   vq->n_since_last_int = 0;
1428   vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
1429 }
1430
1431 static_always_inline u32
1432 vhost_user_input_copy (vhost_user_intf_t * vui, vhost_copy_t * cpy,
1433                        u16 copy_len, u32 * map_hint)
1434 {
1435   void *src0, *src1, *src2, *src3;
1436   if (PREDICT_TRUE (copy_len >= 4))
1437     {
1438       if (PREDICT_FALSE (!(src2 = map_guest_mem (vui, cpy[0].src, map_hint))))
1439         return 1;
1440       if (PREDICT_FALSE (!(src3 = map_guest_mem (vui, cpy[1].src, map_hint))))
1441         return 1;
1442
1443       while (PREDICT_TRUE (copy_len >= 4))
1444         {
1445           src0 = src2;
1446           src1 = src3;
1447
1448           if (PREDICT_FALSE
1449               (!(src2 = map_guest_mem (vui, cpy[2].src, map_hint))))
1450             return 1;
1451           if (PREDICT_FALSE
1452               (!(src3 = map_guest_mem (vui, cpy[3].src, map_hint))))
1453             return 1;
1454
1455           CLIB_PREFETCH (src2, 64, LOAD);
1456           CLIB_PREFETCH (src3, 64, LOAD);
1457
1458           clib_memcpy ((void *) cpy[0].dst, src0, cpy[0].len);
1459           clib_memcpy ((void *) cpy[1].dst, src1, cpy[1].len);
1460           copy_len -= 2;
1461           cpy += 2;
1462         }
1463     }
1464   while (copy_len)
1465     {
1466       if (PREDICT_FALSE (!(src0 = map_guest_mem (vui, cpy->src, map_hint))))
1467         return 1;
1468       clib_memcpy ((void *) cpy->dst, src0, cpy->len);
1469       copy_len -= 1;
1470       cpy += 1;
1471     }
1472   return 0;
1473 }
1474
1475 /**
1476  * Try to discard packets from the tx ring (VPP RX path).
1477  * Returns the number of discarded packets.
1478  */
1479 u32
1480 vhost_user_rx_discard_packet (vlib_main_t * vm,
1481                               vhost_user_intf_t * vui,
1482                               vhost_user_vring_t * txvq, u32 discard_max)
1483 {
1484   /*
1485    * On the RX side, each packet corresponds to one descriptor
1486    * (it is the same whether it is a shallow descriptor, chained, or indirect).
1487    * Therefore, discarding a packet is like discarding a descriptor.
1488    */
1489   u32 discarded_packets = 0;
1490   u32 avail_idx = txvq->avail->idx;
1491   while (discarded_packets != discard_max)
1492     {
1493       if (avail_idx == txvq->last_avail_idx)
1494         goto out;
1495
1496       u16 desc_chain_head =
1497         txvq->avail->ring[txvq->last_avail_idx & txvq->qsz_mask];
1498       txvq->last_avail_idx++;
1499       txvq->used->ring[txvq->last_used_idx & txvq->qsz_mask].id =
1500         desc_chain_head;
1501       txvq->used->ring[txvq->last_used_idx & txvq->qsz_mask].len = 0;
1502       vhost_user_log_dirty_ring (vui, txvq,
1503                                  ring[txvq->last_used_idx & txvq->qsz_mask]);
1504       txvq->last_used_idx++;
1505       discarded_packets++;
1506     }
1507
1508 out:
1509   CLIB_MEMORY_BARRIER ();
1510   txvq->used->idx = txvq->last_used_idx;
1511   vhost_user_log_dirty_ring (vui, txvq, idx);
1512   return discarded_packets;
1513 }
1514
1515 /*
1516  * In case of overflow, we need to rewind the array of allocated buffers.
1517  */
1518 static void
1519 vhost_user_input_rewind_buffers (vlib_main_t * vm,
1520                                  vhost_cpu_t * cpu, vlib_buffer_t * b_head)
1521 {
1522   u32 bi_current = cpu->rx_buffers[cpu->rx_buffers_len];
1523   vlib_buffer_t *b_current = vlib_get_buffer (vm, bi_current);
1524   b_current->current_length = 0;
1525   b_current->flags = 0;
1526   while (b_current != b_head)
1527     {
1528       cpu->rx_buffers_len++;
1529       bi_current = cpu->rx_buffers[cpu->rx_buffers_len];
1530       b_current = vlib_get_buffer (vm, bi_current);
1531       b_current->current_length = 0;
1532       b_current->flags = 0;
1533     }
1534   cpu->rx_buffers_len++;
1535 }
1536
1537 static u32
1538 vhost_user_if_input (vlib_main_t * vm,
1539                      vhost_user_main_t * vum,
1540                      vhost_user_intf_t * vui,
1541                      u16 qid, vlib_node_runtime_t * node,
1542                      vnet_hw_interface_rx_mode mode)
1543 {
1544   vhost_user_vring_t *txvq = &vui->vrings[VHOST_VRING_IDX_TX (qid)];
1545   u16 n_rx_packets = 0;
1546   u32 n_rx_bytes = 0;
1547   u16 n_left;
1548   u32 n_left_to_next, *to_next;
1549   u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
1550   u32 n_trace = vlib_get_trace_count (vm, node);
1551   u32 map_hint = 0;
1552   u16 thread_index = vlib_get_thread_index ();
1553   u16 copy_len = 0;
1554
1555   {
1556     /* do we have pending interrupts ? */
1557     vhost_user_vring_t *rxvq = &vui->vrings[VHOST_VRING_IDX_RX (qid)];
1558     f64 now = vlib_time_now (vm);
1559
1560     if ((txvq->n_since_last_int) && (txvq->int_deadline < now))
1561       vhost_user_send_call (vm, txvq);
1562
1563     if ((rxvq->n_since_last_int) && (rxvq->int_deadline < now))
1564       vhost_user_send_call (vm, rxvq);
1565   }
1566
1567   /*
1568    * For adaptive mode, it is optimized to reduce interrupts.
1569    * If the scheduler switches the input node to polling due
1570    * to burst of traffic, we tell the driver no interrupt.
1571    * When the traffic subsides, the scheduler switches the node back to
1572    * interrupt mode. We must tell the driver we want interrupt.
1573    */
1574   if (PREDICT_FALSE (mode == VNET_HW_INTERFACE_RX_MODE_ADAPTIVE))
1575     {
1576       if ((node->flags &
1577            VLIB_NODE_FLAG_SWITCH_FROM_POLLING_TO_INTERRUPT_MODE) ||
1578           !(node->flags &
1579             VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE))
1580         /* Tell driver we want notification */
1581         txvq->used->flags = 0;
1582       else
1583         /* Tell driver we don't want notification */
1584         txvq->used->flags = VRING_USED_F_NO_NOTIFY;
1585     }
1586
1587   if (PREDICT_FALSE (txvq->avail->flags & 0xFFFE))
1588     return 0;
1589
1590   n_left = (u16) (txvq->avail->idx - txvq->last_avail_idx);
1591
1592   /* nothing to do */
1593   if (PREDICT_FALSE (n_left == 0))
1594     return 0;
1595
1596   if (PREDICT_FALSE (!vui->admin_up || !(txvq->enabled)))
1597     {
1598       /*
1599        * Discard input packet if interface is admin down or vring is not
1600        * enabled.
1601        * "For example, for a networking device, in the disabled state
1602        * client must not supply any new RX packets, but must process
1603        * and discard any TX packets."
1604        */
1605       vhost_user_rx_discard_packet (vm, vui, txvq,
1606                                     VHOST_USER_DOWN_DISCARD_COUNT);
1607       return 0;
1608     }
1609
1610   if (PREDICT_FALSE (n_left == (txvq->qsz_mask + 1)))
1611     {
1612       /*
1613        * Informational error logging when VPP is not
1614        * receiving packets fast enough.
1615        */
1616       vlib_error_count (vm, node->node_index,
1617                         VHOST_USER_INPUT_FUNC_ERROR_FULL_RX_QUEUE, 1);
1618     }
1619
1620   if (n_left > VLIB_FRAME_SIZE)
1621     n_left = VLIB_FRAME_SIZE;
1622
1623   /*
1624    * For small packets (<2kB), we will not need more than one vlib buffer
1625    * per packet. In case packets are bigger, we will just yeld at some point
1626    * in the loop and come back later. This is not an issue as for big packet,
1627    * processing cost really comes from the memory copy.
1628    * The assumption is that big packets will fit in 40 buffers.
1629    */
1630   if (PREDICT_FALSE (vum->cpus[thread_index].rx_buffers_len < n_left + 1 ||
1631                      vum->cpus[thread_index].rx_buffers_len < 40))
1632     {
1633       u32 curr_len = vum->cpus[thread_index].rx_buffers_len;
1634       vum->cpus[thread_index].rx_buffers_len +=
1635         vlib_buffer_alloc_from_free_list (vm,
1636                                           vum->cpus[thread_index].rx_buffers +
1637                                           curr_len,
1638                                           VHOST_USER_RX_BUFFERS_N - curr_len,
1639                                           VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
1640
1641       if (PREDICT_FALSE
1642           (vum->cpus[thread_index].rx_buffers_len <
1643            VHOST_USER_RX_BUFFER_STARVATION))
1644         {
1645           /* In case of buffer starvation, discard some packets from the queue
1646            * and log the event.
1647            * We keep doing best effort for the remaining packets. */
1648           u32 flush = (n_left + 1 > vum->cpus[thread_index].rx_buffers_len) ?
1649             n_left + 1 - vum->cpus[thread_index].rx_buffers_len : 1;
1650           flush = vhost_user_rx_discard_packet (vm, vui, txvq, flush);
1651
1652           n_left -= flush;
1653           vlib_increment_simple_counter (vnet_main.
1654                                          interface_main.sw_if_counters +
1655                                          VNET_INTERFACE_COUNTER_DROP,
1656                                          vlib_get_thread_index (),
1657                                          vui->sw_if_index, flush);
1658
1659           vlib_error_count (vm, vhost_user_input_node.index,
1660                             VHOST_USER_INPUT_FUNC_ERROR_NO_BUFFER, flush);
1661         }
1662     }
1663
1664   while (n_left > 0)
1665     {
1666       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1667
1668       while (n_left > 0 && n_left_to_next > 0)
1669         {
1670           vlib_buffer_t *b_head, *b_current;
1671           u32 bi_current;
1672           u16 desc_current;
1673           u32 desc_data_offset;
1674           vring_desc_t *desc_table = txvq->desc;
1675
1676           if (PREDICT_FALSE (vum->cpus[thread_index].rx_buffers_len <= 1))
1677             {
1678               /* Not enough rx_buffers
1679                * Note: We yeld on 1 so we don't need to do an additional
1680                * check for the next buffer prefetch.
1681                */
1682               n_left = 0;
1683               break;
1684             }
1685
1686           desc_current =
1687             txvq->avail->ring[txvq->last_avail_idx & txvq->qsz_mask];
1688           vum->cpus[thread_index].rx_buffers_len--;
1689           bi_current = (vum->cpus[thread_index].rx_buffers)
1690             [vum->cpus[thread_index].rx_buffers_len];
1691           b_head = b_current = vlib_get_buffer (vm, bi_current);
1692           to_next[0] = bi_current;      //We do that now so we can forget about bi_current
1693           to_next++;
1694           n_left_to_next--;
1695
1696           vlib_prefetch_buffer_with_index (vm,
1697                                            (vum->
1698                                             cpus[thread_index].rx_buffers)
1699                                            [vum->cpus[thread_index].
1700                                             rx_buffers_len - 1], LOAD);
1701
1702           /* Just preset the used descriptor id and length for later */
1703           txvq->used->ring[txvq->last_used_idx & txvq->qsz_mask].id =
1704             desc_current;
1705           txvq->used->ring[txvq->last_used_idx & txvq->qsz_mask].len = 0;
1706           vhost_user_log_dirty_ring (vui, txvq,
1707                                      ring[txvq->last_used_idx &
1708                                           txvq->qsz_mask]);
1709
1710           /* The buffer should already be initialized */
1711           b_head->total_length_not_including_first_buffer = 0;
1712           b_head->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
1713
1714           if (PREDICT_FALSE (n_trace))
1715             {
1716               //TODO: next_index is not exactly known at that point
1717               vlib_trace_buffer (vm, node, next_index, b_head,
1718                                  /* follow_chain */ 0);
1719               vhost_trace_t *t0 =
1720                 vlib_add_trace (vm, node, b_head, sizeof (t0[0]));
1721               vhost_user_rx_trace (t0, vui, qid, b_head, txvq);
1722               n_trace--;
1723               vlib_set_trace_count (vm, node, n_trace);
1724             }
1725
1726           /* This depends on the setup but is very consistent
1727            * So I think the CPU branch predictor will make a pretty good job
1728            * at optimizing the decision. */
1729           if (txvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT)
1730             {
1731               desc_table = map_guest_mem (vui, txvq->desc[desc_current].addr,
1732                                           &map_hint);
1733               desc_current = 0;
1734               if (PREDICT_FALSE (desc_table == 0))
1735                 {
1736                   vlib_error_count (vm, node->node_index,
1737                                     VHOST_USER_INPUT_FUNC_ERROR_MMAP_FAIL, 1);
1738                   goto out;
1739                 }
1740             }
1741
1742           if (PREDICT_TRUE (vui->is_any_layout) ||
1743               (!(desc_table[desc_current].flags & VIRTQ_DESC_F_NEXT)))
1744             {
1745               /* ANYLAYOUT or single buffer */
1746               desc_data_offset = vui->virtio_net_hdr_sz;
1747             }
1748           else
1749             {
1750               /* CSR case without ANYLAYOUT, skip 1st buffer */
1751               desc_data_offset = desc_table[desc_current].len;
1752             }
1753
1754           while (1)
1755             {
1756               /* Get more input if necessary. Or end of packet. */
1757               if (desc_data_offset == desc_table[desc_current].len)
1758                 {
1759                   if (PREDICT_FALSE (desc_table[desc_current].flags &
1760                                      VIRTQ_DESC_F_NEXT))
1761                     {
1762                       desc_current = desc_table[desc_current].next;
1763                       desc_data_offset = 0;
1764                     }
1765                   else
1766                     {
1767                       goto out;
1768                     }
1769                 }
1770
1771               /* Get more output if necessary. Or end of packet. */
1772               if (PREDICT_FALSE
1773                   (b_current->current_length == VLIB_BUFFER_DATA_SIZE))
1774                 {
1775                   if (PREDICT_FALSE
1776                       (vum->cpus[thread_index].rx_buffers_len == 0))
1777                     {
1778                       /* Cancel speculation */
1779                       to_next--;
1780                       n_left_to_next++;
1781
1782                       /*
1783                        * Checking if there are some left buffers.
1784                        * If not, just rewind the used buffers and stop.
1785                        * Note: Scheduled copies are not cancelled. This is
1786                        * not an issue as they would still be valid. Useless,
1787                        * but valid.
1788                        */
1789                       vhost_user_input_rewind_buffers (vm,
1790                                                        &vum->cpus
1791                                                        [thread_index],
1792                                                        b_head);
1793                       n_left = 0;
1794                       goto stop;
1795                     }
1796
1797                   /* Get next output */
1798                   vum->cpus[thread_index].rx_buffers_len--;
1799                   u32 bi_next =
1800                     (vum->cpus[thread_index].rx_buffers)[vum->cpus
1801                                                          [thread_index].rx_buffers_len];
1802                   b_current->next_buffer = bi_next;
1803                   b_current->flags |= VLIB_BUFFER_NEXT_PRESENT;
1804                   bi_current = bi_next;
1805                   b_current = vlib_get_buffer (vm, bi_current);
1806                 }
1807
1808               /* Prepare a copy order executed later for the data */
1809               vhost_copy_t *cpy = &vum->cpus[thread_index].copy[copy_len];
1810               copy_len++;
1811               u32 desc_data_l =
1812                 desc_table[desc_current].len - desc_data_offset;
1813               cpy->len = VLIB_BUFFER_DATA_SIZE - b_current->current_length;
1814               cpy->len = (cpy->len > desc_data_l) ? desc_data_l : cpy->len;
1815               cpy->dst = (uword) (vlib_buffer_get_current (b_current) +
1816                                   b_current->current_length);
1817               cpy->src = desc_table[desc_current].addr + desc_data_offset;
1818
1819               desc_data_offset += cpy->len;
1820
1821               b_current->current_length += cpy->len;
1822               b_head->total_length_not_including_first_buffer += cpy->len;
1823             }
1824
1825         out:
1826           CLIB_PREFETCH (&n_left, sizeof (n_left), LOAD);
1827
1828           n_rx_bytes += b_head->total_length_not_including_first_buffer;
1829           n_rx_packets++;
1830
1831           b_head->total_length_not_including_first_buffer -=
1832             b_head->current_length;
1833
1834           /* consume the descriptor and return it as used */
1835           txvq->last_avail_idx++;
1836           txvq->last_used_idx++;
1837
1838           VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b_head);
1839
1840           vnet_buffer (b_head)->sw_if_index[VLIB_RX] = vui->sw_if_index;
1841           vnet_buffer (b_head)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1842           b_head->error = 0;
1843
1844           {
1845             u32 next0 = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
1846
1847             /* redirect if feature path enabled */
1848             vnet_feature_start_device_input_x1 (vui->sw_if_index, &next0,
1849                                                 b_head);
1850
1851             u32 bi = to_next[-1];       //Cannot use to_next[-1] in the macro
1852             vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1853                                              to_next, n_left_to_next,
1854                                              bi, next0);
1855           }
1856
1857           n_left--;
1858
1859           /*
1860            * Although separating memory copies from virtio ring parsing
1861            * is beneficial, we can offer to perform the copies from time
1862            * to time in order to free some space in the ring.
1863            */
1864           if (PREDICT_FALSE (copy_len >= VHOST_USER_RX_COPY_THRESHOLD))
1865             {
1866               if (PREDICT_FALSE
1867                   (vhost_user_input_copy (vui, vum->cpus[thread_index].copy,
1868                                           copy_len, &map_hint)))
1869                 {
1870                   vlib_error_count (vm, node->node_index,
1871                                     VHOST_USER_INPUT_FUNC_ERROR_MMAP_FAIL, 1);
1872                 }
1873               copy_len = 0;
1874
1875               /* give buffers back to driver */
1876               CLIB_MEMORY_BARRIER ();
1877               txvq->used->idx = txvq->last_used_idx;
1878               vhost_user_log_dirty_ring (vui, txvq, idx);
1879             }
1880         }
1881     stop:
1882       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1883     }
1884
1885   /* Do the memory copies */
1886   if (PREDICT_FALSE
1887       (vhost_user_input_copy (vui, vum->cpus[thread_index].copy,
1888                               copy_len, &map_hint)))
1889     {
1890       vlib_error_count (vm, node->node_index,
1891                         VHOST_USER_INPUT_FUNC_ERROR_MMAP_FAIL, 1);
1892     }
1893
1894   /* give buffers back to driver */
1895   CLIB_MEMORY_BARRIER ();
1896   txvq->used->idx = txvq->last_used_idx;
1897   vhost_user_log_dirty_ring (vui, txvq, idx);
1898
1899   /* interrupt (call) handling */
1900   if ((txvq->callfd_idx != ~0) &&
1901       !(txvq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
1902     {
1903       txvq->n_since_last_int += n_rx_packets;
1904
1905       if (txvq->n_since_last_int > vum->coalesce_frames)
1906         vhost_user_send_call (vm, txvq);
1907     }
1908
1909   /* increase rx counters */
1910   vlib_increment_combined_counter
1911     (vnet_main.interface_main.combined_sw_if_counters
1912      + VNET_INTERFACE_COUNTER_RX,
1913      vlib_get_thread_index (), vui->sw_if_index, n_rx_packets, n_rx_bytes);
1914
1915   vnet_device_increment_rx_packets (thread_index, n_rx_packets);
1916
1917   return n_rx_packets;
1918 }
1919
1920 static uword
1921 vhost_user_input (vlib_main_t * vm,
1922                   vlib_node_runtime_t * node, vlib_frame_t * f)
1923 {
1924   vhost_user_main_t *vum = &vhost_user_main;
1925   uword n_rx_packets = 0;
1926   vhost_user_intf_t *vui;
1927   vnet_device_input_runtime_t *rt =
1928     (vnet_device_input_runtime_t *) node->runtime_data;
1929   vnet_device_and_queue_t *dq;
1930
1931   vec_foreach (dq, rt->devices_and_queues)
1932   {
1933     if (clib_smp_swap (&dq->interrupt_pending, 0) ||
1934         (node->state == VLIB_NODE_STATE_POLLING))
1935       {
1936         vui =
1937           pool_elt_at_index (vum->vhost_user_interfaces, dq->dev_instance);
1938         n_rx_packets = vhost_user_if_input (vm, vum, vui, dq->queue_id, node,
1939                                             dq->mode);
1940       }
1941   }
1942
1943   return n_rx_packets;
1944 }
1945
1946 /* *INDENT-OFF* */
1947 VLIB_REGISTER_NODE (vhost_user_input_node) = {
1948   .function = vhost_user_input,
1949   .type = VLIB_NODE_TYPE_INPUT,
1950   .name = "vhost-user-input",
1951   .sibling_of = "device-input",
1952
1953   /* Will be enabled if/when hardware is detected. */
1954   .state = VLIB_NODE_STATE_DISABLED,
1955
1956   .format_buffer = format_ethernet_header_with_length,
1957   .format_trace = format_vhost_trace,
1958
1959   .n_errors = VHOST_USER_INPUT_FUNC_N_ERROR,
1960   .error_strings = vhost_user_input_func_error_strings,
1961 };
1962
1963 VLIB_NODE_FUNCTION_MULTIARCH (vhost_user_input_node, vhost_user_input)
1964 /* *INDENT-ON* */
1965
1966
1967 void
1968 vhost_user_tx_trace (vhost_trace_t * t,
1969                      vhost_user_intf_t * vui, u16 qid,
1970                      vlib_buffer_t * b, vhost_user_vring_t * rxvq)
1971 {
1972   vhost_user_main_t *vum = &vhost_user_main;
1973   u32 last_avail_idx = rxvq->last_avail_idx;
1974   u32 desc_current = rxvq->avail->ring[last_avail_idx & rxvq->qsz_mask];
1975   vring_desc_t *hdr_desc = 0;
1976   u32 hint = 0;
1977
1978   memset (t, 0, sizeof (*t));
1979   t->device_index = vui - vum->vhost_user_interfaces;
1980   t->qid = qid;
1981
1982   hdr_desc = &rxvq->desc[desc_current];
1983   if (rxvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT)
1984     {
1985       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_INDIRECT;
1986       /* Header is the first here */
1987       hdr_desc = map_guest_mem (vui, rxvq->desc[desc_current].addr, &hint);
1988     }
1989   if (rxvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT)
1990     {
1991       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_SIMPLE_CHAINED;
1992     }
1993   if (!(rxvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT) &&
1994       !(rxvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT))
1995     {
1996       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_SINGLE_DESC;
1997     }
1998
1999   t->first_desc_len = hdr_desc ? hdr_desc->len : 0;
2000 }
2001
2002 static_always_inline u32
2003 vhost_user_tx_copy (vhost_user_intf_t * vui, vhost_copy_t * cpy,
2004                     u16 copy_len, u32 * map_hint)
2005 {
2006   void *dst0, *dst1, *dst2, *dst3;
2007   if (PREDICT_TRUE (copy_len >= 4))
2008     {
2009       if (PREDICT_FALSE (!(dst2 = map_guest_mem (vui, cpy[0].dst, map_hint))))
2010         return 1;
2011       if (PREDICT_FALSE (!(dst3 = map_guest_mem (vui, cpy[1].dst, map_hint))))
2012         return 1;
2013       while (PREDICT_TRUE (copy_len >= 4))
2014         {
2015           dst0 = dst2;
2016           dst1 = dst3;
2017
2018           if (PREDICT_FALSE
2019               (!(dst2 = map_guest_mem (vui, cpy[2].dst, map_hint))))
2020             return 1;
2021           if (PREDICT_FALSE
2022               (!(dst3 = map_guest_mem (vui, cpy[3].dst, map_hint))))
2023             return 1;
2024
2025           CLIB_PREFETCH ((void *) cpy[2].src, 64, LOAD);
2026           CLIB_PREFETCH ((void *) cpy[3].src, 64, LOAD);
2027
2028           clib_memcpy (dst0, (void *) cpy[0].src, cpy[0].len);
2029           clib_memcpy (dst1, (void *) cpy[1].src, cpy[1].len);
2030
2031           vhost_user_log_dirty_pages_2 (vui, cpy[0].dst, cpy[0].len, 1);
2032           vhost_user_log_dirty_pages_2 (vui, cpy[1].dst, cpy[1].len, 1);
2033           copy_len -= 2;
2034           cpy += 2;
2035         }
2036     }
2037   while (copy_len)
2038     {
2039       if (PREDICT_FALSE (!(dst0 = map_guest_mem (vui, cpy->dst, map_hint))))
2040         return 1;
2041       clib_memcpy (dst0, (void *) cpy->src, cpy->len);
2042       vhost_user_log_dirty_pages_2 (vui, cpy->dst, cpy->len, 1);
2043       copy_len -= 1;
2044       cpy += 1;
2045     }
2046   return 0;
2047 }
2048
2049
2050 static uword
2051 vhost_user_tx (vlib_main_t * vm,
2052                vlib_node_runtime_t * node, vlib_frame_t * frame)
2053 {
2054   u32 *buffers = vlib_frame_args (frame);
2055   u32 n_left = frame->n_vectors;
2056   vhost_user_main_t *vum = &vhost_user_main;
2057   vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
2058   vhost_user_intf_t *vui =
2059     pool_elt_at_index (vum->vhost_user_interfaces, rd->dev_instance);
2060   u32 qid = ~0;
2061   vhost_user_vring_t *rxvq;
2062   u8 error;
2063   u32 thread_index = vlib_get_thread_index ();
2064   u32 map_hint = 0;
2065   u8 retry = 8;
2066   u16 copy_len;
2067   u16 tx_headers_len;
2068
2069   if (PREDICT_FALSE (!vui->admin_up))
2070     {
2071       error = VHOST_USER_TX_FUNC_ERROR_DOWN;
2072       goto done3;
2073     }
2074
2075   if (PREDICT_FALSE (!vui->is_up))
2076     {
2077       error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
2078       goto done3;
2079     }
2080
2081   qid =
2082     VHOST_VRING_IDX_RX (*vec_elt_at_index
2083                         (vui->per_cpu_tx_qid, thread_index));
2084   rxvq = &vui->vrings[qid];
2085   if (PREDICT_FALSE (vui->use_tx_spinlock))
2086     vhost_user_vring_lock (vui, qid);
2087
2088 retry:
2089   error = VHOST_USER_TX_FUNC_ERROR_NONE;
2090   tx_headers_len = 0;
2091   copy_len = 0;
2092   while (n_left > 0)
2093     {
2094       vlib_buffer_t *b0, *current_b0;
2095       u16 desc_head, desc_index, desc_len;
2096       vring_desc_t *desc_table;
2097       uword buffer_map_addr;
2098       u32 buffer_len;
2099       u16 bytes_left;
2100
2101       if (PREDICT_TRUE (n_left > 1))
2102         vlib_prefetch_buffer_with_index (vm, buffers[1], LOAD);
2103
2104       b0 = vlib_get_buffer (vm, buffers[0]);
2105
2106       if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2107         {
2108           vum->cpus[thread_index].current_trace =
2109             vlib_add_trace (vm, node, b0,
2110                             sizeof (*vum->cpus[thread_index].current_trace));
2111           vhost_user_tx_trace (vum->cpus[thread_index].current_trace,
2112                                vui, qid / 2, b0, rxvq);
2113         }
2114
2115       if (PREDICT_FALSE (rxvq->last_avail_idx == rxvq->avail->idx))
2116         {
2117           error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
2118           goto done;
2119         }
2120
2121       desc_table = rxvq->desc;
2122       desc_head = desc_index =
2123         rxvq->avail->ring[rxvq->last_avail_idx & rxvq->qsz_mask];
2124
2125       /* Go deeper in case of indirect descriptor
2126        * I don't know of any driver providing indirect for RX. */
2127       if (PREDICT_FALSE (rxvq->desc[desc_head].flags & VIRTQ_DESC_F_INDIRECT))
2128         {
2129           if (PREDICT_FALSE
2130               (rxvq->desc[desc_head].len < sizeof (vring_desc_t)))
2131             {
2132               error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
2133               goto done;
2134             }
2135           if (PREDICT_FALSE
2136               (!(desc_table =
2137                  map_guest_mem (vui, rxvq->desc[desc_index].addr,
2138                                 &map_hint))))
2139             {
2140               error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
2141               goto done;
2142             }
2143           desc_index = 0;
2144         }
2145
2146       desc_len = vui->virtio_net_hdr_sz;
2147       buffer_map_addr = desc_table[desc_index].addr;
2148       buffer_len = desc_table[desc_index].len;
2149
2150       {
2151         // Get a header from the header array
2152         virtio_net_hdr_mrg_rxbuf_t *hdr =
2153           &vum->cpus[thread_index].tx_headers[tx_headers_len];
2154         tx_headers_len++;
2155         hdr->hdr.flags = 0;
2156         hdr->hdr.gso_type = 0;
2157         hdr->num_buffers = 1;   //This is local, no need to check
2158
2159         // Prepare a copy order executed later for the header
2160         vhost_copy_t *cpy = &vum->cpus[thread_index].copy[copy_len];
2161         copy_len++;
2162         cpy->len = vui->virtio_net_hdr_sz;
2163         cpy->dst = buffer_map_addr;
2164         cpy->src = (uword) hdr;
2165       }
2166
2167       buffer_map_addr += vui->virtio_net_hdr_sz;
2168       buffer_len -= vui->virtio_net_hdr_sz;
2169       bytes_left = b0->current_length;
2170       current_b0 = b0;
2171       while (1)
2172         {
2173           if (buffer_len == 0)
2174             {                   //Get new output
2175               if (desc_table[desc_index].flags & VIRTQ_DESC_F_NEXT)
2176                 {
2177                   //Next one is chained
2178                   desc_index = desc_table[desc_index].next;
2179                   buffer_map_addr = desc_table[desc_index].addr;
2180                   buffer_len = desc_table[desc_index].len;
2181                 }
2182               else if (vui->virtio_net_hdr_sz == 12)    //MRG is available
2183                 {
2184                   virtio_net_hdr_mrg_rxbuf_t *hdr =
2185                     &vum->cpus[thread_index].tx_headers[tx_headers_len - 1];
2186
2187                   //Move from available to used buffer
2188                   rxvq->used->ring[rxvq->last_used_idx & rxvq->qsz_mask].id =
2189                     desc_head;
2190                   rxvq->used->ring[rxvq->last_used_idx & rxvq->qsz_mask].len =
2191                     desc_len;
2192                   vhost_user_log_dirty_ring (vui, rxvq,
2193                                              ring[rxvq->last_used_idx &
2194                                                   rxvq->qsz_mask]);
2195
2196                   rxvq->last_avail_idx++;
2197                   rxvq->last_used_idx++;
2198                   hdr->num_buffers++;
2199                   desc_len = 0;
2200
2201                   if (PREDICT_FALSE
2202                       (rxvq->last_avail_idx == rxvq->avail->idx))
2203                     {
2204                       //Dequeue queued descriptors for this packet
2205                       rxvq->last_used_idx -= hdr->num_buffers - 1;
2206                       rxvq->last_avail_idx -= hdr->num_buffers - 1;
2207                       error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
2208                       goto done;
2209                     }
2210
2211                   desc_table = rxvq->desc;
2212                   desc_head = desc_index =
2213                     rxvq->avail->ring[rxvq->last_avail_idx & rxvq->qsz_mask];
2214                   if (PREDICT_FALSE
2215                       (rxvq->desc[desc_head].flags & VIRTQ_DESC_F_INDIRECT))
2216                     {
2217                       //It is seriously unlikely that a driver will put indirect descriptor
2218                       //after non-indirect descriptor.
2219                       if (PREDICT_FALSE
2220                           (rxvq->desc[desc_head].len < sizeof (vring_desc_t)))
2221                         {
2222                           error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
2223                           goto done;
2224                         }
2225                       if (PREDICT_FALSE
2226                           (!(desc_table =
2227                              map_guest_mem (vui,
2228                                             rxvq->desc[desc_index].addr,
2229                                             &map_hint))))
2230                         {
2231                           error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
2232                           goto done;
2233                         }
2234                       desc_index = 0;
2235                     }
2236                   buffer_map_addr = desc_table[desc_index].addr;
2237                   buffer_len = desc_table[desc_index].len;
2238                 }
2239               else
2240                 {
2241                   error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOMRG;
2242                   goto done;
2243                 }
2244             }
2245
2246           {
2247             vhost_copy_t *cpy = &vum->cpus[thread_index].copy[copy_len];
2248             copy_len++;
2249             cpy->len = bytes_left;
2250             cpy->len = (cpy->len > buffer_len) ? buffer_len : cpy->len;
2251             cpy->dst = buffer_map_addr;
2252             cpy->src = (uword) vlib_buffer_get_current (current_b0) +
2253               current_b0->current_length - bytes_left;
2254
2255             bytes_left -= cpy->len;
2256             buffer_len -= cpy->len;
2257             buffer_map_addr += cpy->len;
2258             desc_len += cpy->len;
2259
2260             CLIB_PREFETCH (&rxvq->desc, CLIB_CACHE_LINE_BYTES, LOAD);
2261           }
2262
2263           // Check if vlib buffer has more data. If not, get more or break.
2264           if (PREDICT_TRUE (!bytes_left))
2265             {
2266               if (PREDICT_FALSE
2267                   (current_b0->flags & VLIB_BUFFER_NEXT_PRESENT))
2268                 {
2269                   current_b0 = vlib_get_buffer (vm, current_b0->next_buffer);
2270                   bytes_left = current_b0->current_length;
2271                 }
2272               else
2273                 {
2274                   //End of packet
2275                   break;
2276                 }
2277             }
2278         }
2279
2280       //Move from available to used ring
2281       rxvq->used->ring[rxvq->last_used_idx & rxvq->qsz_mask].id = desc_head;
2282       rxvq->used->ring[rxvq->last_used_idx & rxvq->qsz_mask].len = desc_len;
2283       vhost_user_log_dirty_ring (vui, rxvq,
2284                                  ring[rxvq->last_used_idx & rxvq->qsz_mask]);
2285       rxvq->last_avail_idx++;
2286       rxvq->last_used_idx++;
2287
2288       if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2289         {
2290           vum->cpus[thread_index].current_trace->hdr =
2291             vum->cpus[thread_index].tx_headers[tx_headers_len - 1];
2292         }
2293
2294       n_left--;                 //At the end for error counting when 'goto done' is invoked
2295
2296       /*
2297        * Do the copy periodically to prevent
2298        * vum->cpus[thread_index].copy array overflow and corrupt memory
2299        */
2300       if (PREDICT_FALSE (copy_len >= VHOST_USER_TX_COPY_THRESHOLD))
2301         {
2302           if (PREDICT_FALSE
2303               (vhost_user_tx_copy (vui, vum->cpus[thread_index].copy,
2304                                    copy_len, &map_hint)))
2305             {
2306               vlib_error_count (vm, node->node_index,
2307                                 VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
2308             }
2309           copy_len = 0;
2310
2311           /* give buffers back to driver */
2312           CLIB_MEMORY_BARRIER ();
2313           rxvq->used->idx = rxvq->last_used_idx;
2314           vhost_user_log_dirty_ring (vui, rxvq, idx);
2315         }
2316       buffers++;
2317     }
2318
2319 done:
2320   //Do the memory copies
2321   if (PREDICT_FALSE
2322       (vhost_user_tx_copy (vui, vum->cpus[thread_index].copy,
2323                            copy_len, &map_hint)))
2324     {
2325       vlib_error_count (vm, node->node_index,
2326                         VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
2327     }
2328
2329   CLIB_MEMORY_BARRIER ();
2330   rxvq->used->idx = rxvq->last_used_idx;
2331   vhost_user_log_dirty_ring (vui, rxvq, idx);
2332
2333   /*
2334    * When n_left is set, error is always set to something too.
2335    * In case error is due to lack of remaining buffers, we go back up and
2336    * retry.
2337    * The idea is that it is better to waste some time on packets
2338    * that have been processed already than dropping them and get
2339    * more fresh packets with a good likelyhood that they will be dropped too.
2340    * This technique also gives more time to VM driver to pick-up packets.
2341    * In case the traffic flows from physical to virtual interfaces, this
2342    * technique will end-up leveraging the physical NIC buffer in order to
2343    * absorb the VM's CPU jitter.
2344    */
2345   if (n_left && (error == VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF) && retry)
2346     {
2347       retry--;
2348       goto retry;
2349     }
2350
2351   /* interrupt (call) handling */
2352   if ((rxvq->callfd_idx != ~0) &&
2353       !(rxvq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
2354     {
2355       rxvq->n_since_last_int += frame->n_vectors - n_left;
2356
2357       if (rxvq->n_since_last_int > vum->coalesce_frames)
2358         vhost_user_send_call (vm, rxvq);
2359     }
2360
2361   vhost_user_vring_unlock (vui, qid);
2362
2363 done3:
2364   if (PREDICT_FALSE (n_left && error != VHOST_USER_TX_FUNC_ERROR_NONE))
2365     {
2366       vlib_error_count (vm, node->node_index, error, n_left);
2367       vlib_increment_simple_counter
2368         (vnet_main.interface_main.sw_if_counters
2369          + VNET_INTERFACE_COUNTER_DROP,
2370          thread_index, vui->sw_if_index, n_left);
2371     }
2372
2373   vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
2374   return frame->n_vectors;
2375 }
2376
2377 static uword
2378 vhost_user_send_interrupt_process (vlib_main_t * vm,
2379                                    vlib_node_runtime_t * rt, vlib_frame_t * f)
2380 {
2381   vhost_user_intf_t *vui;
2382   f64 timeout = 3153600000.0 /* 100 years */ ;
2383   uword event_type, *event_data = 0;
2384   vhost_user_main_t *vum = &vhost_user_main;
2385   u16 *queue;
2386   f64 now, poll_time_remaining;
2387   f64 next_timeout;
2388   u8 stop_timer = 0;
2389
2390   while (1)
2391     {
2392       poll_time_remaining =
2393         vlib_process_wait_for_event_or_clock (vm, timeout);
2394       event_type = vlib_process_get_events (vm, &event_data);
2395       vec_reset_length (event_data);
2396
2397       /*
2398        * Use the remaining timeout if it is less than coalesce time to avoid
2399        * resetting the existing timer in the middle of expiration
2400        */
2401       timeout = poll_time_remaining;
2402       if (vlib_process_suspend_time_is_zero (timeout) ||
2403           (timeout > vum->coalesce_time))
2404         timeout = vum->coalesce_time;
2405
2406       now = vlib_time_now (vm);
2407       switch (event_type)
2408         {
2409         case VHOST_USER_EVENT_STOP_TIMER:
2410           stop_timer = 1;
2411           break;
2412
2413         case VHOST_USER_EVENT_START_TIMER:
2414           stop_timer = 0;
2415           if (!vlib_process_suspend_time_is_zero (poll_time_remaining))
2416             break;
2417           /* fall through */
2418
2419         case ~0:
2420           /* *INDENT-OFF* */
2421           pool_foreach (vui, vum->vhost_user_interfaces, {
2422               next_timeout = timeout;
2423               vec_foreach (queue, vui->rx_queues)
2424                 {
2425                   vhost_user_vring_t *rxvq =
2426                     &vui->vrings[VHOST_VRING_IDX_RX (*queue)];
2427                   vhost_user_vring_t *txvq =
2428                     &vui->vrings[VHOST_VRING_IDX_TX (*queue)];
2429
2430                   if (txvq->n_since_last_int)
2431                     {
2432                       if (now >= txvq->int_deadline)
2433                         vhost_user_send_call (vm, txvq);
2434                       else
2435                         next_timeout = txvq->int_deadline - now;
2436                     }
2437
2438                   if (rxvq->n_since_last_int)
2439                     {
2440                       if (now >= rxvq->int_deadline)
2441                         vhost_user_send_call (vm, rxvq);
2442                       else
2443                         next_timeout = rxvq->int_deadline - now;
2444                     }
2445
2446                   if ((next_timeout < timeout) && (next_timeout > 0.0))
2447                     timeout = next_timeout;
2448                 }
2449           });
2450           /* *INDENT-ON* */
2451           break;
2452
2453         default:
2454           clib_warning ("BUG: unhandled event type %d", event_type);
2455           break;
2456         }
2457       /* No less than 1 millisecond */
2458       if (timeout < 1e-3)
2459         timeout = 1e-3;
2460       if (stop_timer)
2461         timeout = 3153600000.0;
2462     }
2463   return 0;
2464 }
2465
2466 /* *INDENT-OFF* */
2467 VLIB_REGISTER_NODE (vhost_user_send_interrupt_node,static) = {
2468     .function = vhost_user_send_interrupt_process,
2469     .type = VLIB_NODE_TYPE_PROCESS,
2470     .name = "vhost-user-send-interrupt-process",
2471 };
2472 /* *INDENT-ON* */
2473
2474 static clib_error_t *
2475 vhost_user_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index,
2476                                      u32 qid, vnet_hw_interface_rx_mode mode)
2477 {
2478   vlib_main_t *vm = vnm->vlib_main;
2479   vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
2480   vhost_user_main_t *vum = &vhost_user_main;
2481   vhost_user_intf_t *vui =
2482     pool_elt_at_index (vum->vhost_user_interfaces, hif->dev_instance);
2483   vhost_user_vring_t *txvq = &vui->vrings[VHOST_VRING_IDX_TX (qid)];
2484
2485   if ((mode == VNET_HW_INTERFACE_RX_MODE_INTERRUPT) ||
2486       (mode == VNET_HW_INTERFACE_RX_MODE_ADAPTIVE))
2487     {
2488       if (txvq->kickfd_idx == ~0)
2489         {
2490           // We cannot support interrupt mode if the driver opts out
2491           return clib_error_return (0, "Driver does not support interrupt");
2492         }
2493       if (txvq->mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
2494         {
2495           vum->ifq_count++;
2496           // Start the timer if this is the first encounter on interrupt
2497           // interface/queue
2498           if ((vum->ifq_count == 1) &&
2499               (vum->coalesce_time > 0.0) && (vum->coalesce_frames > 0))
2500             vlib_process_signal_event (vm,
2501                                        vhost_user_send_interrupt_node.index,
2502                                        VHOST_USER_EVENT_START_TIMER, 0);
2503         }
2504     }
2505   else if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
2506     {
2507       if (((txvq->mode == VNET_HW_INTERFACE_RX_MODE_INTERRUPT) ||
2508            (txvq->mode == VNET_HW_INTERFACE_RX_MODE_ADAPTIVE)) &&
2509           vum->ifq_count)
2510         {
2511           vum->ifq_count--;
2512           // Stop the timer if there is no more interrupt interface/queue
2513           if ((vum->ifq_count == 0) &&
2514               (vum->coalesce_time > 0.0) && (vum->coalesce_frames > 0))
2515             vlib_process_signal_event (vm,
2516                                        vhost_user_send_interrupt_node.index,
2517                                        VHOST_USER_EVENT_STOP_TIMER, 0);
2518         }
2519     }
2520
2521   txvq->mode = mode;
2522   if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
2523     txvq->used->flags = VRING_USED_F_NO_NOTIFY;
2524   else if ((mode == VNET_HW_INTERFACE_RX_MODE_ADAPTIVE) ||
2525            (mode == VNET_HW_INTERFACE_RX_MODE_INTERRUPT))
2526     txvq->used->flags = 0;
2527   else
2528     {
2529       clib_warning ("BUG: unhandled mode %d changed for if %d queue %d", mode,
2530                     hw_if_index, qid);
2531       return clib_error_return (0, "unsupported");
2532     }
2533
2534   return 0;
2535 }
2536
2537 static clib_error_t *
2538 vhost_user_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
2539                                     u32 flags)
2540 {
2541   vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
2542   uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
2543   vhost_user_main_t *vum = &vhost_user_main;
2544   vhost_user_intf_t *vui =
2545     pool_elt_at_index (vum->vhost_user_interfaces, hif->dev_instance);
2546
2547   vui->admin_up = is_up;
2548
2549   if (is_up && vui->is_up)
2550     vnet_hw_interface_set_flags (vnm, vui->hw_if_index,
2551                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
2552
2553   return /* no error */ 0;
2554 }
2555
2556 /* *INDENT-OFF* */
2557 VNET_DEVICE_CLASS (vhost_user_dev_class,static) = {
2558   .name = "vhost-user",
2559   .tx_function = vhost_user_tx,
2560   .tx_function_n_errors = VHOST_USER_TX_FUNC_N_ERROR,
2561   .tx_function_error_strings = vhost_user_tx_func_error_strings,
2562   .format_device_name = format_vhost_user_interface_name,
2563   .name_renumber = vhost_user_name_renumber,
2564   .admin_up_down_function = vhost_user_interface_admin_up_down,
2565   .rx_mode_change_function = vhost_user_interface_rx_mode_change,
2566   .format_tx_trace = format_vhost_trace,
2567 };
2568
2569 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (vhost_user_dev_class,
2570                                    vhost_user_tx)
2571 /* *INDENT-ON* */
2572
2573 static uword
2574 vhost_user_process (vlib_main_t * vm,
2575                     vlib_node_runtime_t * rt, vlib_frame_t * f)
2576 {
2577   vhost_user_main_t *vum = &vhost_user_main;
2578   vhost_user_intf_t *vui;
2579   struct sockaddr_un sun;
2580   int sockfd;
2581   clib_file_t template = { 0 };
2582   f64 timeout = 3153600000.0 /* 100 years */ ;
2583   uword *event_data = 0;
2584
2585   sockfd = -1;
2586   sun.sun_family = AF_UNIX;
2587   template.read_function = vhost_user_socket_read;
2588   template.error_function = vhost_user_socket_error;
2589
2590   while (1)
2591     {
2592       vlib_process_wait_for_event_or_clock (vm, timeout);
2593       vlib_process_get_events (vm, &event_data);
2594       vec_reset_length (event_data);
2595
2596       timeout = 3.0;
2597
2598       /* *INDENT-OFF* */
2599       pool_foreach (vui, vum->vhost_user_interfaces, {
2600
2601           if (vui->unix_server_index == ~0) { //Nothing to do for server sockets
2602               if (vui->clib_file_index == ~0)
2603                 {
2604                   if ((sockfd < 0) &&
2605                       ((sockfd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0))
2606                     {
2607                       /*
2608                        * 1st time error or new error for this interface,
2609                        * spit out the message and record the error
2610                        */
2611                       if (!vui->sock_errno || (vui->sock_errno != errno))
2612                         {
2613                           clib_unix_warning
2614                             ("Error: Could not open unix socket for %s",
2615                              vui->sock_filename);
2616                           vui->sock_errno = errno;
2617                         }
2618                       continue;
2619                     }
2620
2621                   /* try to connect */
2622                   strncpy (sun.sun_path, (char *) vui->sock_filename,
2623                            sizeof (sun.sun_path) - 1);
2624
2625                   /* Avoid hanging VPP if the other end does not accept */
2626                   if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0)
2627                       clib_unix_warning ("fcntl");
2628
2629                   if (connect (sockfd, (struct sockaddr *) &sun,
2630                                sizeof (struct sockaddr_un)) == 0)
2631                     {
2632                       /* Set the socket to blocking as it was before */
2633                       if (fcntl(sockfd, F_SETFL, 0) < 0)
2634                         clib_unix_warning ("fcntl2");
2635
2636                       vui->sock_errno = 0;
2637                       template.file_descriptor = sockfd;
2638                       template.private_data =
2639                           vui - vhost_user_main.vhost_user_interfaces;
2640                       vui->clib_file_index = clib_file_add (&file_main, &template);
2641
2642                       /* This sockfd is considered consumed */
2643                       sockfd = -1;
2644                     }
2645                   else
2646                     {
2647                       vui->sock_errno = errno;
2648                     }
2649                 }
2650               else
2651                 {
2652                   /* check if socket is alive */
2653                   int error = 0;
2654                   socklen_t len = sizeof (error);
2655                   int fd = UNIX_GET_FD(vui->clib_file_index);
2656                   int retval =
2657                       getsockopt (fd, SOL_SOCKET, SO_ERROR, &error, &len);
2658
2659                   if (retval)
2660                     {
2661                       DBG_SOCK ("getsockopt returned %d", retval);
2662                       vhost_user_if_disconnect (vui);
2663                     }
2664                 }
2665           }
2666       });
2667       /* *INDENT-ON* */
2668     }
2669   return 0;
2670 }
2671
2672 /* *INDENT-OFF* */
2673 VLIB_REGISTER_NODE (vhost_user_process_node,static) = {
2674     .function = vhost_user_process,
2675     .type = VLIB_NODE_TYPE_PROCESS,
2676     .name = "vhost-user-process",
2677 };
2678 /* *INDENT-ON* */
2679
2680 /**
2681  * Disables and reset interface structure.
2682  * It can then be either init again, or removed from used interfaces.
2683  */
2684 static void
2685 vhost_user_term_if (vhost_user_intf_t * vui)
2686 {
2687   int q;
2688   vhost_user_main_t *vum = &vhost_user_main;
2689
2690   // disconnect interface sockets
2691   vhost_user_if_disconnect (vui);
2692   vhost_user_update_iface_state (vui);
2693
2694   for (q = 0; q < VHOST_VRING_MAX_N; q++)
2695     {
2696       clib_mem_free ((void *) vui->vring_locks[q]);
2697     }
2698
2699   if (vui->unix_server_index != ~0)
2700     {
2701       //Close server socket
2702       clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
2703                                            vui->unix_server_index);
2704       clib_file_del (&file_main, uf);
2705       vui->unix_server_index = ~0;
2706       unlink (vui->sock_filename);
2707     }
2708
2709   mhash_unset (&vum->if_index_by_sock_name, vui->sock_filename,
2710                &vui->if_index);
2711 }
2712
2713 int
2714 vhost_user_delete_if (vnet_main_t * vnm, vlib_main_t * vm, u32 sw_if_index)
2715 {
2716   vhost_user_main_t *vum = &vhost_user_main;
2717   vhost_user_intf_t *vui;
2718   int rv = 0;
2719   vnet_hw_interface_t *hwif;
2720   u16 *queue;
2721
2722   if (!(hwif = vnet_get_sup_hw_interface (vnm, sw_if_index)) ||
2723       hwif->dev_class_index != vhost_user_dev_class.index)
2724     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
2725
2726   DBG_SOCK ("Deleting vhost-user interface %s (instance %d)",
2727             hwif->name, hwif->dev_instance);
2728
2729   vui = pool_elt_at_index (vum->vhost_user_interfaces, hwif->dev_instance);
2730
2731   vec_foreach (queue, vui->rx_queues)
2732   {
2733     vhost_user_vring_t *txvq;
2734
2735     txvq = &vui->vrings[VHOST_VRING_IDX_TX (*queue)];
2736     if ((vum->ifq_count > 0) &&
2737         ((txvq->mode == VNET_HW_INTERFACE_RX_MODE_INTERRUPT) ||
2738          (txvq->mode == VNET_HW_INTERFACE_RX_MODE_ADAPTIVE)))
2739       {
2740         vum->ifq_count--;
2741         // Stop the timer if there is no more interrupt interface/queue
2742         if ((vum->ifq_count == 0) &&
2743             (vum->coalesce_time > 0.0) && (vum->coalesce_frames > 0))
2744           {
2745             vlib_process_signal_event (vm,
2746                                        vhost_user_send_interrupt_node.index,
2747                                        VHOST_USER_EVENT_STOP_TIMER, 0);
2748             break;
2749           }
2750       }
2751   }
2752
2753   // Disable and reset interface
2754   vhost_user_term_if (vui);
2755
2756   // Reset renumbered iface
2757   if (hwif->dev_instance <
2758       vec_len (vum->show_dev_instance_by_real_dev_instance))
2759     vum->show_dev_instance_by_real_dev_instance[hwif->dev_instance] = ~0;
2760
2761   // Delete ethernet interface
2762   ethernet_delete_interface (vnm, vui->hw_if_index);
2763
2764   // Back to pool
2765   pool_put (vum->vhost_user_interfaces, vui);
2766
2767   return rv;
2768 }
2769
2770 static clib_error_t *
2771 vhost_user_exit (vlib_main_t * vm)
2772 {
2773   vnet_main_t *vnm = vnet_get_main ();
2774   vhost_user_main_t *vum = &vhost_user_main;
2775   vhost_user_intf_t *vui;
2776
2777   vlib_worker_thread_barrier_sync (vlib_get_main ());
2778   /* *INDENT-OFF* */
2779   pool_foreach (vui, vum->vhost_user_interfaces, {
2780       vhost_user_delete_if (vnm, vm, vui->sw_if_index);
2781   });
2782   /* *INDENT-ON* */
2783   vlib_worker_thread_barrier_release (vlib_get_main ());
2784   return 0;
2785 }
2786
2787 VLIB_MAIN_LOOP_EXIT_FUNCTION (vhost_user_exit);
2788
2789 /**
2790  * Open server unix socket on specified sock_filename.
2791  */
2792 static int
2793 vhost_user_init_server_sock (const char *sock_filename, int *sock_fd)
2794 {
2795   int rv = 0;
2796   struct sockaddr_un un = { };
2797   int fd;
2798   /* create listening socket */
2799   if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
2800     return VNET_API_ERROR_SYSCALL_ERROR_1;
2801
2802   un.sun_family = AF_UNIX;
2803   strncpy ((char *) un.sun_path, (char *) sock_filename,
2804            sizeof (un.sun_path) - 1);
2805
2806   /* remove if exists */
2807   unlink ((char *) sock_filename);
2808
2809   if (bind (fd, (struct sockaddr *) &un, sizeof (un)) == -1)
2810     {
2811       rv = VNET_API_ERROR_SYSCALL_ERROR_2;
2812       goto error;
2813     }
2814
2815   if (listen (fd, 1) == -1)
2816     {
2817       rv = VNET_API_ERROR_SYSCALL_ERROR_3;
2818       goto error;
2819     }
2820
2821   *sock_fd = fd;
2822   return 0;
2823
2824 error:
2825   close (fd);
2826   return rv;
2827 }
2828
2829 /**
2830  * Create ethernet interface for vhost user interface.
2831  */
2832 static void
2833 vhost_user_create_ethernet (vnet_main_t * vnm, vlib_main_t * vm,
2834                             vhost_user_intf_t * vui, u8 * hwaddress)
2835 {
2836   vhost_user_main_t *vum = &vhost_user_main;
2837   u8 hwaddr[6];
2838   clib_error_t *error;
2839
2840   /* create hw and sw interface */
2841   if (hwaddress)
2842     {
2843       clib_memcpy (hwaddr, hwaddress, 6);
2844     }
2845   else
2846     {
2847       random_u32 (&vum->random);
2848       clib_memcpy (hwaddr + 2, &vum->random, sizeof (vum->random));
2849       hwaddr[0] = 2;
2850       hwaddr[1] = 0xfe;
2851     }
2852
2853   error = ethernet_register_interface
2854     (vnm,
2855      vhost_user_dev_class.index,
2856      vui - vum->vhost_user_interfaces /* device instance */ ,
2857      hwaddr /* ethernet address */ ,
2858      &vui->hw_if_index, 0 /* flag change */ );
2859
2860   if (error)
2861     clib_error_report (error);
2862
2863   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, vui->hw_if_index);
2864   hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = 9000;
2865 }
2866
2867 /*
2868  *  Initialize vui with specified attributes
2869  */
2870 static void
2871 vhost_user_vui_init (vnet_main_t * vnm,
2872                      vhost_user_intf_t * vui,
2873                      int server_sock_fd,
2874                      const char *sock_filename,
2875                      u64 feature_mask, u32 * sw_if_index)
2876 {
2877   vnet_sw_interface_t *sw;
2878   int q;
2879   vhost_user_main_t *vum = &vhost_user_main;
2880   vnet_hw_interface_t *hw;
2881
2882   hw = vnet_get_hw_interface (vnm, vui->hw_if_index);
2883   sw = vnet_get_hw_sw_interface (vnm, vui->hw_if_index);
2884   if (server_sock_fd != -1)
2885     {
2886       clib_file_t template = { 0 };
2887       template.read_function = vhost_user_socksvr_accept_ready;
2888       template.file_descriptor = server_sock_fd;
2889       template.private_data = vui - vum->vhost_user_interfaces; //hw index
2890       vui->unix_server_index = clib_file_add (&file_main, &template);
2891     }
2892   else
2893     {
2894       vui->unix_server_index = ~0;
2895     }
2896
2897   vui->sw_if_index = sw->sw_if_index;
2898   strncpy (vui->sock_filename, sock_filename,
2899            ARRAY_LEN (vui->sock_filename) - 1);
2900   vui->sock_errno = 0;
2901   vui->is_up = 0;
2902   vui->feature_mask = feature_mask;
2903   vui->clib_file_index = ~0;
2904   vui->log_base_addr = 0;
2905   vui->if_index = vui - vum->vhost_user_interfaces;
2906   mhash_set_mem (&vum->if_index_by_sock_name, vui->sock_filename,
2907                  &vui->if_index, 0);
2908
2909   for (q = 0; q < VHOST_VRING_MAX_N; q++)
2910     vhost_user_vring_init (vui, q);
2911
2912   hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE;
2913   vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
2914
2915   if (sw_if_index)
2916     *sw_if_index = vui->sw_if_index;
2917
2918   for (q = 0; q < VHOST_VRING_MAX_N; q++)
2919     {
2920       vui->vring_locks[q] = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
2921                                                     CLIB_CACHE_LINE_BYTES);
2922       memset ((void *) vui->vring_locks[q], 0, CLIB_CACHE_LINE_BYTES);
2923     }
2924
2925   vec_validate (vui->per_cpu_tx_qid,
2926                 vlib_get_thread_main ()->n_vlib_mains - 1);
2927   vhost_user_tx_thread_placement (vui);
2928 }
2929
2930 int
2931 vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
2932                       const char *sock_filename,
2933                       u8 is_server,
2934                       u32 * sw_if_index,
2935                       u64 feature_mask,
2936                       u8 renumber, u32 custom_dev_instance, u8 * hwaddr)
2937 {
2938   vhost_user_intf_t *vui = NULL;
2939   u32 sw_if_idx = ~0;
2940   int rv = 0;
2941   int server_sock_fd = -1;
2942   vhost_user_main_t *vum = &vhost_user_main;
2943   uword *if_index;
2944
2945   if (sock_filename == NULL || !(strlen (sock_filename) > 0))
2946     {
2947       return VNET_API_ERROR_INVALID_ARGUMENT;
2948     }
2949
2950   if_index = mhash_get (&vum->if_index_by_sock_name, (void *) sock_filename);
2951   if (if_index)
2952     {
2953       if (sw_if_index)
2954         {
2955           vui = &vum->vhost_user_interfaces[*if_index];
2956           *sw_if_index = vui->sw_if_index;
2957         }
2958       return VNET_API_ERROR_IF_ALREADY_EXISTS;
2959     }
2960
2961   if (is_server)
2962     {
2963       if ((rv =
2964            vhost_user_init_server_sock (sock_filename, &server_sock_fd)) != 0)
2965         {
2966           return rv;
2967         }
2968     }
2969
2970   pool_get (vhost_user_main.vhost_user_interfaces, vui);
2971
2972   vhost_user_create_ethernet (vnm, vm, vui, hwaddr);
2973   vhost_user_vui_init (vnm, vui, server_sock_fd, sock_filename,
2974                        feature_mask, &sw_if_idx);
2975
2976   if (renumber)
2977     vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
2978
2979   if (sw_if_index)
2980     *sw_if_index = sw_if_idx;
2981
2982   // Process node must connect
2983   vlib_process_signal_event (vm, vhost_user_process_node.index, 0, 0);
2984
2985   return rv;
2986 }
2987
2988 int
2989 vhost_user_modify_if (vnet_main_t * vnm, vlib_main_t * vm,
2990                       const char *sock_filename,
2991                       u8 is_server,
2992                       u32 sw_if_index,
2993                       u64 feature_mask, u8 renumber, u32 custom_dev_instance)
2994 {
2995   vhost_user_main_t *vum = &vhost_user_main;
2996   vhost_user_intf_t *vui = NULL;
2997   u32 sw_if_idx = ~0;
2998   int server_sock_fd = -1;
2999   int rv = 0;
3000   vnet_hw_interface_t *hwif;
3001   uword *if_index;
3002
3003   if (!(hwif = vnet_get_sup_hw_interface (vnm, sw_if_index)) ||
3004       hwif->dev_class_index != vhost_user_dev_class.index)
3005     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
3006
3007   if (sock_filename == NULL || !(strlen (sock_filename) > 0))
3008     return VNET_API_ERROR_INVALID_ARGUMENT;
3009
3010   vui = vec_elt_at_index (vum->vhost_user_interfaces, hwif->dev_instance);
3011
3012   /*
3013    * Disallow changing the interface to have the same path name
3014    * as other interface
3015    */
3016   if_index = mhash_get (&vum->if_index_by_sock_name, (void *) sock_filename);
3017   if (if_index && (*if_index != vui->if_index))
3018     return VNET_API_ERROR_IF_ALREADY_EXISTS;
3019
3020   // First try to open server socket
3021   if (is_server)
3022     if ((rv = vhost_user_init_server_sock (sock_filename,
3023                                            &server_sock_fd)) != 0)
3024       return rv;
3025
3026   vhost_user_term_if (vui);
3027   vhost_user_vui_init (vnm, vui, server_sock_fd,
3028                        sock_filename, feature_mask, &sw_if_idx);
3029
3030   if (renumber)
3031     vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
3032
3033   // Process node must connect
3034   vlib_process_signal_event (vm, vhost_user_process_node.index, 0, 0);
3035
3036   return rv;
3037 }
3038
3039 clib_error_t *
3040 vhost_user_connect_command_fn (vlib_main_t * vm,
3041                                unformat_input_t * input,
3042                                vlib_cli_command_t * cmd)
3043 {
3044   unformat_input_t _line_input, *line_input = &_line_input;
3045   u8 *sock_filename = NULL;
3046   u32 sw_if_index;
3047   u8 is_server = 0;
3048   u64 feature_mask = (u64) ~ (0ULL);
3049   u8 renumber = 0;
3050   u32 custom_dev_instance = ~0;
3051   u8 hwaddr[6];
3052   u8 *hw = NULL;
3053   clib_error_t *error = NULL;
3054
3055   /* Get a line of input. */
3056   if (!unformat_user (input, unformat_line_input, line_input))
3057     return 0;
3058
3059   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3060     {
3061       if (unformat (line_input, "socket %s", &sock_filename))
3062         ;
3063       else if (unformat (line_input, "server"))
3064         is_server = 1;
3065       else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
3066         ;
3067       else
3068         if (unformat
3069             (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
3070         hw = hwaddr;
3071       else if (unformat (line_input, "renumber %d", &custom_dev_instance))
3072         {
3073           renumber = 1;
3074         }
3075       else
3076         {
3077           error = clib_error_return (0, "unknown input `%U'",
3078                                      format_unformat_error, line_input);
3079           goto done;
3080         }
3081     }
3082
3083   vnet_main_t *vnm = vnet_get_main ();
3084
3085   int rv;
3086   if ((rv = vhost_user_create_if (vnm, vm, (char *) sock_filename,
3087                                   is_server, &sw_if_index, feature_mask,
3088                                   renumber, custom_dev_instance, hw)))
3089     {
3090       error = clib_error_return (0, "vhost_user_create_if returned %d", rv);
3091       goto done;
3092     }
3093
3094   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
3095                    sw_if_index);
3096
3097 done:
3098   vec_free (sock_filename);
3099   unformat_free (line_input);
3100
3101   return error;
3102 }
3103
3104 clib_error_t *
3105 vhost_user_delete_command_fn (vlib_main_t * vm,
3106                               unformat_input_t * input,
3107                               vlib_cli_command_t * cmd)
3108 {
3109   unformat_input_t _line_input, *line_input = &_line_input;
3110   u32 sw_if_index = ~0;
3111   vnet_main_t *vnm = vnet_get_main ();
3112   clib_error_t *error = NULL;
3113
3114   /* Get a line of input. */
3115   if (!unformat_user (input, unformat_line_input, line_input))
3116     return 0;
3117
3118   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3119     {
3120       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
3121         ;
3122       else if (unformat
3123                (line_input, "%U", unformat_vnet_sw_interface, vnm,
3124                 &sw_if_index))
3125         {
3126           vnet_hw_interface_t *hwif =
3127             vnet_get_sup_hw_interface (vnm, sw_if_index);
3128           if (hwif == NULL ||
3129               vhost_user_dev_class.index != hwif->dev_class_index)
3130             {
3131               error = clib_error_return (0, "Not a vhost interface");
3132               goto done;
3133             }
3134         }
3135       else
3136         {
3137           error = clib_error_return (0, "unknown input `%U'",
3138                                      format_unformat_error, line_input);
3139           goto done;
3140         }
3141     }
3142
3143   vhost_user_delete_if (vnm, vm, sw_if_index);
3144
3145 done:
3146   unformat_free (line_input);
3147
3148   return error;
3149 }
3150
3151 int
3152 vhost_user_dump_ifs (vnet_main_t * vnm, vlib_main_t * vm,
3153                      vhost_user_intf_details_t ** out_vuids)
3154 {
3155   int rv = 0;
3156   vhost_user_main_t *vum = &vhost_user_main;
3157   vhost_user_intf_t *vui;
3158   vhost_user_intf_details_t *r_vuids = NULL;
3159   vhost_user_intf_details_t *vuid = NULL;
3160   u32 *hw_if_indices = 0;
3161   vnet_hw_interface_t *hi;
3162   u8 *s = NULL;
3163   int i;
3164
3165   if (!out_vuids)
3166     return -1;
3167
3168   pool_foreach (vui, vum->vhost_user_interfaces,
3169                 vec_add1 (hw_if_indices, vui->hw_if_index);
3170     );
3171
3172   for (i = 0; i < vec_len (hw_if_indices); i++)
3173     {
3174       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
3175       vui = pool_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
3176
3177       vec_add2 (r_vuids, vuid, 1);
3178       vuid->sw_if_index = vui->sw_if_index;
3179       vuid->virtio_net_hdr_sz = vui->virtio_net_hdr_sz;
3180       vuid->features = vui->features;
3181       vuid->num_regions = vui->nregions;
3182       vuid->is_server = vui->unix_server_index != ~0;
3183       vuid->sock_errno = vui->sock_errno;
3184       strncpy ((char *) vuid->sock_filename, (char *) vui->sock_filename,
3185                ARRAY_LEN (vuid->sock_filename) - 1);
3186
3187       s = format (s, "%v%c", hi->name, 0);
3188
3189       strncpy ((char *) vuid->if_name, (char *) s,
3190                ARRAY_LEN (vuid->if_name) - 1);
3191       _vec_len (s) = 0;
3192     }
3193
3194   vec_free (s);
3195   vec_free (hw_if_indices);
3196
3197   *out_vuids = r_vuids;
3198
3199   return rv;
3200 }
3201
3202 clib_error_t *
3203 show_vhost_user_command_fn (vlib_main_t * vm,
3204                             unformat_input_t * input,
3205                             vlib_cli_command_t * cmd)
3206 {
3207   clib_error_t *error = 0;
3208   vnet_main_t *vnm = vnet_get_main ();
3209   vhost_user_main_t *vum = &vhost_user_main;
3210   vhost_user_intf_t *vui;
3211   u32 hw_if_index, *hw_if_indices = 0;
3212   vnet_hw_interface_t *hi;
3213   u16 *queue;
3214   u32 ci;
3215   int i, j, q;
3216   int show_descr = 0;
3217   struct feat_struct
3218   {
3219     u8 bit;
3220     char *str;
3221   };
3222   struct feat_struct *feat_entry;
3223
3224   static struct feat_struct feat_array[] = {
3225 #define _(s,b) { .str = #s, .bit = b, },
3226     foreach_virtio_net_feature
3227 #undef _
3228     {.str = NULL}
3229   };
3230
3231 #define foreach_protocol_feature \
3232   _(VHOST_USER_PROTOCOL_F_MQ) \
3233   _(VHOST_USER_PROTOCOL_F_LOG_SHMFD)
3234
3235   static struct feat_struct proto_feat_array[] = {
3236 #define _(s) { .str = #s, .bit = s},
3237     foreach_protocol_feature
3238 #undef _
3239     {.str = NULL}
3240   };
3241
3242   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3243     {
3244       if (unformat
3245           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
3246         {
3247           vec_add1 (hw_if_indices, hw_if_index);
3248         }
3249       else if (unformat (input, "descriptors") || unformat (input, "desc"))
3250         show_descr = 1;
3251       else
3252         {
3253           error = clib_error_return (0, "unknown input `%U'",
3254                                      format_unformat_error, input);
3255           goto done;
3256         }
3257     }
3258   if (vec_len (hw_if_indices) == 0)
3259     {
3260       pool_foreach (vui, vum->vhost_user_interfaces,
3261                     vec_add1 (hw_if_indices, vui->hw_if_index);
3262         );
3263     }
3264   vlib_cli_output (vm, "Virtio vhost-user interfaces");
3265   vlib_cli_output (vm, "Global:\n  coalesce frames %d time %e",
3266                    vum->coalesce_frames, vum->coalesce_time);
3267   vlib_cli_output (vm, "  number of rx virtqueues in interrupt mode: %d",
3268                    vum->ifq_count);
3269
3270   for (i = 0; i < vec_len (hw_if_indices); i++)
3271     {
3272       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
3273       vui = pool_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
3274       vlib_cli_output (vm, "Interface: %s (ifindex %d)",
3275                        hi->name, hw_if_indices[i]);
3276
3277       vlib_cli_output (vm, "virtio_net_hdr_sz %d\n"
3278                        " features mask (0x%llx): \n"
3279                        " features (0x%llx): \n",
3280                        vui->virtio_net_hdr_sz, vui->feature_mask,
3281                        vui->features);
3282
3283       feat_entry = (struct feat_struct *) &feat_array;
3284       while (feat_entry->str)
3285         {
3286           if (vui->features & (1ULL << feat_entry->bit))
3287             vlib_cli_output (vm, "   %s (%d)", feat_entry->str,
3288                              feat_entry->bit);
3289           feat_entry++;
3290         }
3291
3292       vlib_cli_output (vm, "  protocol features (0x%llx)",
3293                        vui->protocol_features);
3294       feat_entry = (struct feat_struct *) &proto_feat_array;
3295       while (feat_entry->str)
3296         {
3297           if (vui->protocol_features & (1ULL << feat_entry->bit))
3298             vlib_cli_output (vm, "   %s (%d)", feat_entry->str,
3299                              feat_entry->bit);
3300           feat_entry++;
3301         }
3302
3303       vlib_cli_output (vm, "\n");
3304
3305       vlib_cli_output (vm, " socket filename %s type %s errno \"%s\"\n\n",
3306                        vui->sock_filename,
3307                        (vui->unix_server_index != ~0) ? "server" : "client",
3308                        strerror (vui->sock_errno));
3309
3310       vlib_cli_output (vm, " rx placement: ");
3311
3312       vec_foreach (queue, vui->rx_queues)
3313       {
3314         vnet_main_t *vnm = vnet_get_main ();
3315         uword thread_index;
3316         vnet_hw_interface_rx_mode mode;
3317
3318         thread_index = vnet_get_device_input_thread_index (vnm,
3319                                                            vui->hw_if_index,
3320                                                            *queue);
3321         vnet_hw_interface_get_rx_mode (vnm, vui->hw_if_index, *queue, &mode);
3322         vlib_cli_output (vm, "   thread %d on vring %d, %U\n",
3323                          thread_index, VHOST_VRING_IDX_TX (*queue),
3324                          format_vnet_hw_interface_rx_mode, mode);
3325       }
3326
3327       vlib_cli_output (vm, " tx placement: %s\n",
3328                        vui->use_tx_spinlock ? "spin-lock" : "lock-free");
3329
3330       vec_foreach_index (ci, vui->per_cpu_tx_qid)
3331       {
3332         vlib_cli_output (vm, "   thread %d on vring %d\n", ci,
3333                          VHOST_VRING_IDX_RX (vui->per_cpu_tx_qid[ci]));
3334       }
3335
3336       vlib_cli_output (vm, "\n");
3337
3338       vlib_cli_output (vm, " Memory regions (total %d)\n", vui->nregions);
3339
3340       if (vui->nregions)
3341         {
3342           vlib_cli_output (vm,
3343                            " region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr\n");
3344           vlib_cli_output (vm,
3345                            " ====== ===== ================== ================== ================== ================== ==================\n");
3346         }
3347       for (j = 0; j < vui->nregions; j++)
3348         {
3349           vlib_cli_output (vm,
3350                            "  %d     %-5d 0x%016lx 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
3351                            j, vui->region_mmap_fd[j],
3352                            vui->regions[j].guest_phys_addr,
3353                            vui->regions[j].memory_size,
3354                            vui->regions[j].userspace_addr,
3355                            vui->regions[j].mmap_offset,
3356                            pointer_to_uword (vui->region_mmap_addr[j]));
3357         }
3358       for (q = 0; q < VHOST_VRING_MAX_N; q++)
3359         {
3360           if (!vui->vrings[q].started)
3361             continue;
3362
3363           vlib_cli_output (vm, "\n Virtqueue %d (%s%s)\n", q,
3364                            (q & 1) ? "RX" : "TX",
3365                            vui->vrings[q].enabled ? "" : " disabled");
3366
3367           vlib_cli_output (vm,
3368                            "  qsz %d last_avail_idx %d last_used_idx %d\n",
3369                            vui->vrings[q].qsz_mask + 1,
3370                            vui->vrings[q].last_avail_idx,
3371                            vui->vrings[q].last_used_idx);
3372
3373           if (vui->vrings[q].avail && vui->vrings[q].used)
3374             vlib_cli_output (vm,
3375                              "  avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
3376                              vui->vrings[q].avail->flags,
3377                              vui->vrings[q].avail->idx,
3378                              vui->vrings[q].used->flags,
3379                              vui->vrings[q].used->idx);
3380
3381           int kickfd = UNIX_GET_FD (vui->vrings[q].kickfd_idx);
3382           int callfd = UNIX_GET_FD (vui->vrings[q].callfd_idx);
3383           vlib_cli_output (vm, "  kickfd %d callfd %d errfd %d\n",
3384                            kickfd, callfd, vui->vrings[q].errfd);
3385
3386           if (show_descr)
3387             {
3388               vlib_cli_output (vm, "\n  descriptor table:\n");
3389               vlib_cli_output (vm,
3390                                "   id          addr         len  flags  next      user_addr\n");
3391               vlib_cli_output (vm,
3392                                "  ===== ================== ===== ====== ===== ==================\n");
3393               for (j = 0; j < vui->vrings[q].qsz_mask + 1; j++)
3394                 {
3395                   u32 mem_hint = 0;
3396                   vlib_cli_output (vm,
3397                                    "  %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
3398                                    j, vui->vrings[q].desc[j].addr,
3399                                    vui->vrings[q].desc[j].len,
3400                                    vui->vrings[q].desc[j].flags,
3401                                    vui->vrings[q].desc[j].next,
3402                                    pointer_to_uword (map_guest_mem
3403                                                      (vui,
3404                                                       vui->vrings[q].desc[j].
3405                                                       addr, &mem_hint)));
3406                 }
3407             }
3408         }
3409       vlib_cli_output (vm, "\n");
3410     }
3411 done:
3412   vec_free (hw_if_indices);
3413   return error;
3414 }
3415
3416 /*
3417  * CLI functions
3418  */
3419
3420 /*?
3421  * Create a vHost User interface. Once created, a new virtual interface
3422  * will exist with the name '<em>VirtualEthernet0/0/x</em>', where '<em>x</em>'
3423  * is the next free index.
3424  *
3425  * There are several parameters associated with a vHost interface:
3426  *
3427  * - <b>socket <socket-filename></b> - Name of the linux socket used by hypervisor
3428  * and VPP to manage the vHost interface. If in '<em>server</em>' mode, VPP will
3429  * create the socket if it does not already exist. If in '<em>client</em>' mode,
3430  * hypervisor will create the socket if it does not already exist. The VPP code
3431  * is indifferent to the file location. However, if SELinux is enabled, then the
3432  * socket needs to be created in '<em>/var/run/vpp/</em>'.
3433  *
3434  * - <b>server</b> - Optional flag to indicate that VPP should be the server for
3435  * the linux socket. If not provided, VPP will be the client. In '<em>server</em>'
3436  *  mode, the VM can be reset without tearing down the vHost Interface. In
3437  * '<em>client</em>' mode, VPP can be reset without bringing down the VM and
3438  * tearing down the vHost Interface.
3439  *
3440  * - <b>feature-mask <hex></b> - Optional virtio/vhost feature set negotiated at
3441  * startup. <b>This is intended for degugging only.</b> It is recommended that this
3442  * parameter not be used except by experienced users. By default, all supported
3443  * features will be advertised. Otherwise, provide the set of features desired.
3444  *   - 0x000008000 (15) - VIRTIO_NET_F_MRG_RXBUF
3445  *   - 0x000020000 (17) - VIRTIO_NET_F_CTRL_VQ
3446  *   - 0x000200000 (21) - VIRTIO_NET_F_GUEST_ANNOUNCE
3447  *   - 0x000400000 (22) - VIRTIO_NET_F_MQ
3448  *   - 0x004000000 (26) - VHOST_F_LOG_ALL
3449  *   - 0x008000000 (27) - VIRTIO_F_ANY_LAYOUT
3450  *   - 0x010000000 (28) - VIRTIO_F_INDIRECT_DESC
3451  *   - 0x040000000 (30) - VHOST_USER_F_PROTOCOL_FEATURES
3452  *   - 0x100000000 (32) - VIRTIO_F_VERSION_1
3453  *
3454  * - <b>hwaddr <mac-addr></b> - Optional ethernet address, can be in either
3455  * X:X:X:X:X:X unix or X.X.X cisco format.
3456  *
3457  * - <b>renumber <dev_instance></b> - Optional parameter which allows the instance
3458  * in the name to be specified. If instance already exists, name will be used
3459  * anyway and multiple instances will have the same name. Use with caution.
3460  *
3461  * @cliexpar
3462  * Example of how to create a vhost interface with VPP as the client and all features enabled:
3463  * @cliexstart{create vhost-user socket /var/run/vpp/vhost1.sock}
3464  * VirtualEthernet0/0/0
3465  * @cliexend
3466  * Example of how to create a vhost interface with VPP as the server and with just
3467  * multiple queues enabled:
3468  * @cliexstart{create vhost-user socket /var/run/vpp/vhost2.sock server feature-mask 0x40400000}
3469  * VirtualEthernet0/0/1
3470  * @cliexend
3471  * Once the vHost interface is created, enable the interface using:
3472  * @cliexcmd{set interface state VirtualEthernet0/0/0 up}
3473 ?*/
3474 /* *INDENT-OFF* */
3475 VLIB_CLI_COMMAND (vhost_user_connect_command, static) = {
3476     .path = "create vhost-user",
3477     .short_help = "create vhost-user socket <socket-filename> [server] "
3478     "[feature-mask <hex>] [hwaddr <mac-addr>] [renumber <dev_instance>] ",
3479     .function = vhost_user_connect_command_fn,
3480 };
3481 /* *INDENT-ON* */
3482
3483 /*?
3484  * Delete a vHost User interface using the interface name or the
3485  * software interface index. Use the '<em>show interface</em>'
3486  * command to determine the software interface index. On deletion,
3487  * the linux socket will not be deleted.
3488  *
3489  * @cliexpar
3490  * Example of how to delete a vhost interface by name:
3491  * @cliexcmd{delete vhost-user VirtualEthernet0/0/1}
3492  * Example of how to delete a vhost interface by software interface index:
3493  * @cliexcmd{delete vhost-user sw_if_index 1}
3494 ?*/
3495 /* *INDENT-OFF* */
3496 VLIB_CLI_COMMAND (vhost_user_delete_command, static) = {
3497     .path = "delete vhost-user",
3498     .short_help = "delete vhost-user {<interface> | sw_if_index <sw_idx>}",
3499     .function = vhost_user_delete_command_fn,
3500 };
3501
3502 /*?
3503  * Display the attributes of a single vHost User interface (provide interface
3504  * name), multiple vHost User interfaces (provide a list of interface names seperated
3505  * by spaces) or all Vhost User interfaces (omit an interface name to display all
3506  * vHost interfaces).
3507  *
3508  * @cliexpar
3509  * @parblock
3510  * Example of how to display a vhost interface:
3511  * @cliexstart{show vhost-user VirtualEthernet0/0/0}
3512  * Virtio vhost-user interfaces
3513  * Global:
3514  *   coalesce frames 32 time 1e-3
3515  * Interface: VirtualEthernet0/0/0 (ifindex 1)
3516  * virtio_net_hdr_sz 12
3517  *  features mask (0xffffffffffffffff):
3518  *  features (0x50408000):
3519  *    VIRTIO_NET_F_MRG_RXBUF (15)
3520  *    VIRTIO_NET_F_MQ (22)
3521  *    VIRTIO_F_INDIRECT_DESC (28)
3522  *    VHOST_USER_F_PROTOCOL_FEATURES (30)
3523  *   protocol features (0x3)
3524  *    VHOST_USER_PROTOCOL_F_MQ (0)
3525  *    VHOST_USER_PROTOCOL_F_LOG_SHMFD (1)
3526  *
3527  *  socket filename /var/run/vpp/vhost1.sock type client errno "Success"
3528  *
3529  * rx placement:
3530  *    thread 1 on vring 1
3531  *    thread 1 on vring 5
3532  *    thread 2 on vring 3
3533  *    thread 2 on vring 7
3534  *  tx placement: spin-lock
3535  *    thread 0 on vring 0
3536  *    thread 1 on vring 2
3537  *    thread 2 on vring 0
3538  *
3539  * Memory regions (total 2)
3540  * region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr
3541  * ====== ===== ================== ================== ================== ================== ==================
3542  *   0     60    0x0000000000000000 0x00000000000a0000 0x00002aaaaac00000 0x0000000000000000 0x00002aab2b400000
3543  *   1     61    0x00000000000c0000 0x000000003ff40000 0x00002aaaaacc0000 0x00000000000c0000 0x00002aababcc0000
3544  *
3545  *  Virtqueue 0 (TX)
3546  *   qsz 256 last_avail_idx 0 last_used_idx 0
3547  *   avail.flags 1 avail.idx 128 used.flags 1 used.idx 0
3548  *   kickfd 62 callfd 64 errfd -1
3549  *
3550  *  Virtqueue 1 (RX)
3551  *   qsz 256 last_avail_idx 0 last_used_idx 0
3552  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
3553  *   kickfd 65 callfd 66 errfd -1
3554  *
3555  *  Virtqueue 2 (TX)
3556  *   qsz 256 last_avail_idx 0 last_used_idx 0
3557  *   avail.flags 1 avail.idx 128 used.flags 1 used.idx 0
3558  *   kickfd 63 callfd 70 errfd -1
3559  *
3560  *  Virtqueue 3 (RX)
3561  *   qsz 256 last_avail_idx 0 last_used_idx 0
3562  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
3563  *   kickfd 72 callfd 74 errfd -1
3564  *
3565  *  Virtqueue 4 (TX disabled)
3566  *   qsz 256 last_avail_idx 0 last_used_idx 0
3567  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
3568  *   kickfd 76 callfd 78 errfd -1
3569  *
3570  *  Virtqueue 5 (RX disabled)
3571  *   qsz 256 last_avail_idx 0 last_used_idx 0
3572  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
3573  *   kickfd 80 callfd 82 errfd -1
3574  *
3575  *  Virtqueue 6 (TX disabled)
3576  *   qsz 256 last_avail_idx 0 last_used_idx 0
3577  *  avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
3578  *   kickfd 84 callfd 86 errfd -1
3579  *
3580  *  Virtqueue 7 (RX disabled)
3581  *   qsz 256 last_avail_idx 0 last_used_idx 0
3582  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
3583  *   kickfd 88 callfd 90 errfd -1
3584  *
3585  * @cliexend
3586  *
3587  * The optional '<em>descriptors</em>' parameter will display the same output as
3588  * the previous example but will include the descriptor table for each queue.
3589  * The output is truncated below:
3590  * @cliexstart{show vhost-user VirtualEthernet0/0/0 descriptors}
3591  * Virtio vhost-user interfaces
3592  * Global:
3593  *   coalesce frames 32 time 1e-3
3594  * Interface: VirtualEthernet0/0/0 (ifindex 1)
3595  * virtio_net_hdr_sz 12
3596  *  features mask (0xffffffffffffffff):
3597  *  features (0x50408000):
3598  *    VIRTIO_NET_F_MRG_RXBUF (15)
3599  *    VIRTIO_NET_F_MQ (22)
3600  * :
3601  *  Virtqueue 0 (TX)
3602  *   qsz 256 last_avail_idx 0 last_used_idx 0
3603  *   avail.flags 1 avail.idx 128 used.flags 1 used.idx 0
3604  *   kickfd 62 callfd 64 errfd -1
3605  *
3606  *   descriptor table:
3607  *    id          addr         len  flags  next      user_addr
3608  *   ===== ================== ===== ====== ===== ==================
3609  *   0     0x0000000010b6e974 2060  0x0002 1     0x00002aabbc76e974
3610  *   1     0x0000000010b6e034 2060  0x0002 2     0x00002aabbc76e034
3611  *   2     0x0000000010b6d6f4 2060  0x0002 3     0x00002aabbc76d6f4
3612  *   3     0x0000000010b6cdb4 2060  0x0002 4     0x00002aabbc76cdb4
3613  *   4     0x0000000010b6c474 2060  0x0002 5     0x00002aabbc76c474
3614  *   5     0x0000000010b6bb34 2060  0x0002 6     0x00002aabbc76bb34
3615  *   6     0x0000000010b6b1f4 2060  0x0002 7     0x00002aabbc76b1f4
3616  *   7     0x0000000010b6a8b4 2060  0x0002 8     0x00002aabbc76a8b4
3617  *   8     0x0000000010b69f74 2060  0x0002 9     0x00002aabbc769f74
3618  *   9     0x0000000010b69634 2060  0x0002 10    0x00002aabbc769634
3619  *   10    0x0000000010b68cf4 2060  0x0002 11    0x00002aabbc768cf4
3620  * :
3621  *   249   0x0000000000000000 0     0x0000 250   0x00002aab2b400000
3622  *   250   0x0000000000000000 0     0x0000 251   0x00002aab2b400000
3623  *   251   0x0000000000000000 0     0x0000 252   0x00002aab2b400000
3624  *   252   0x0000000000000000 0     0x0000 253   0x00002aab2b400000
3625  *   253   0x0000000000000000 0     0x0000 254   0x00002aab2b400000
3626  *   254   0x0000000000000000 0     0x0000 255   0x00002aab2b400000
3627  *   255   0x0000000000000000 0     0x0000 32768 0x00002aab2b400000
3628  *
3629  *  Virtqueue 1 (RX)
3630  *   qsz 256 last_avail_idx 0 last_used_idx 0
3631  * :
3632  * @cliexend
3633  * @endparblock
3634 ?*/
3635 /* *INDENT-OFF* */
3636 VLIB_CLI_COMMAND (show_vhost_user_command, static) = {
3637     .path = "show vhost-user",
3638     .short_help = "show vhost-user [<interface> [<interface> [..]]] [descriptors]",
3639     .function = show_vhost_user_command_fn,
3640 };
3641 /* *INDENT-ON* */
3642
3643 clib_error_t *
3644 debug_vhost_user_command_fn (vlib_main_t * vm,
3645                              unformat_input_t * input,
3646                              vlib_cli_command_t * cmd)
3647 {
3648   unformat_input_t _line_input, *line_input = &_line_input;
3649   clib_error_t *error = NULL;
3650   vhost_user_main_t *vum = &vhost_user_main;
3651   u8 onoff = 0;
3652   u8 input_found = 0;
3653
3654   /* Get a line of input. */
3655   if (!unformat_user (input, unformat_line_input, line_input))
3656     return clib_error_return (0, "missing argument");
3657
3658   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3659     {
3660       if (input_found)
3661         {
3662           error = clib_error_return (0, "unknown input `%U'",
3663                                      format_unformat_error, line_input);
3664           goto done;
3665         }
3666
3667       if (unformat (line_input, "on"))
3668         {
3669           input_found = 1;
3670           onoff = 1;
3671         }
3672       else if (unformat (line_input, "off"))
3673         {
3674           input_found = 1;
3675           onoff = 0;
3676         }
3677       else
3678         {
3679           error = clib_error_return (0, "unknown input `%U'",
3680                                      format_unformat_error, line_input);
3681           goto done;
3682         }
3683     }
3684
3685   vum->debug = onoff;
3686
3687 done:
3688   unformat_free (line_input);
3689
3690   return error;
3691 }
3692
3693 /* *INDENT-OFF* */
3694 VLIB_CLI_COMMAND (debug_vhost_user_command, static) = {
3695     .path = "debug vhost-user",
3696     .short_help = "debug vhost-user <on | off>",
3697     .function = debug_vhost_user_command_fn,
3698 };
3699 /* *INDENT-ON* */
3700
3701 static clib_error_t *
3702 vhost_user_config (vlib_main_t * vm, unformat_input_t * input)
3703 {
3704   vhost_user_main_t *vum = &vhost_user_main;
3705
3706   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3707     {
3708       if (unformat (input, "coalesce-frames %d", &vum->coalesce_frames))
3709         ;
3710       else if (unformat (input, "coalesce-time %f", &vum->coalesce_time))
3711         ;
3712       else if (unformat (input, "dont-dump-memory"))
3713         vum->dont_dump_vhost_user_memory = 1;
3714       else
3715         return clib_error_return (0, "unknown input `%U'",
3716                                   format_unformat_error, input);
3717     }
3718
3719   return 0;
3720 }
3721
3722 /* vhost-user { ... } configuration. */
3723 VLIB_CONFIG_FUNCTION (vhost_user_config, "vhost-user");
3724
3725 void
3726 vhost_user_unmap_all (void)
3727 {
3728   vhost_user_main_t *vum = &vhost_user_main;
3729   vhost_user_intf_t *vui;
3730
3731   if (vum->dont_dump_vhost_user_memory)
3732     {
3733       pool_foreach (vui, vum->vhost_user_interfaces,
3734                     unmap_all_mem_regions (vui);
3735         );
3736     }
3737 }
3738
3739 /*
3740  * fd.io coding-style-patch-verification: ON
3741  *
3742  * Local Variables:
3743  * eval: (c-set-style "gnu")
3744  * End:
3745  */