vhost: predict map_guest_mem returns similar results over time
[vpp.git] / vnet / 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
40 #include <vnet/devices/virtio/vhost-user.h>
41
42 #define VHOST_USER_DEBUG_SOCKET 0
43 #define VHOST_USER_DEBUG_VQ 0
44
45 /* Set to get virtio_net_hdr in buffer pre-data
46    details will be shown in  packet trace */
47 #define VHOST_USER_COPY_TX_HDR 0
48
49 #if VHOST_USER_DEBUG_SOCKET == 1
50 #define DBG_SOCK(args...) clib_warning(args);
51 #else
52 #define DBG_SOCK(args...)
53 #endif
54
55 #if VHOST_USER_DEBUG_VQ == 1
56 #define DBG_VQ(args...) clib_warning(args);
57 #else
58 #define DBG_VQ(args...)
59 #endif
60
61 vlib_node_registration_t vhost_user_input_node;
62
63 #define foreach_vhost_user_tx_func_error      \
64   _(NONE, "no error")  \
65   _(NOT_READY, "vhost user state error")  \
66   _(PKT_DROP_NOBUF, "tx packet drops (no available descriptors)")  \
67   _(PKT_DROP_NOMRG, "tx packet drops (cannot merge descriptors)")  \
68   _(MMAP_FAIL, "mmap failure") \
69   _(INDIRECT_OVERFLOW, "indirect descriptor table overflow")
70
71 typedef enum
72 {
73 #define _(f,s) VHOST_USER_TX_FUNC_ERROR_##f,
74   foreach_vhost_user_tx_func_error
75 #undef _
76     VHOST_USER_TX_FUNC_N_ERROR,
77 } vhost_user_tx_func_error_t;
78
79 static char *vhost_user_tx_func_error_strings[] = {
80 #define _(n,s) s,
81   foreach_vhost_user_tx_func_error
82 #undef _
83 };
84
85 #define foreach_vhost_user_input_func_error      \
86   _(NO_ERROR, "no error")  \
87   _(NO_BUFFER, "no available buffer")  \
88   _(MMAP_FAIL, "mmap failure")  \
89   _(INDIRECT_OVERFLOW, "indirect descriptor overflows table")  \
90   _(UNDERSIZED_FRAME, "undersized ethernet frame received (< 14 bytes)") \
91   _(FULL_RX_QUEUE, "full rx queue (possible driver tx drop)")
92
93 typedef enum
94 {
95 #define _(f,s) VHOST_USER_INPUT_FUNC_ERROR_##f,
96   foreach_vhost_user_input_func_error
97 #undef _
98     VHOST_USER_INPUT_FUNC_N_ERROR,
99 } vhost_user_input_func_error_t;
100
101 static char *vhost_user_input_func_error_strings[] = {
102 #define _(n,s) s,
103   foreach_vhost_user_input_func_error
104 #undef _
105 };
106
107 /* *INDENT-OFF* */
108 static vhost_user_main_t vhost_user_main = {
109   .mtu_bytes = 1518,
110 };
111
112 VNET_HW_INTERFACE_CLASS (vhost_interface_class, static) = {
113   .name = "vhost-user",
114 };
115 /* *INDENT-ON* */
116
117 static u8 *
118 format_vhost_user_interface_name (u8 * s, va_list * args)
119 {
120   u32 i = va_arg (*args, u32);
121   u32 show_dev_instance = ~0;
122   vhost_user_main_t *vum = &vhost_user_main;
123
124   if (i < vec_len (vum->show_dev_instance_by_real_dev_instance))
125     show_dev_instance = vum->show_dev_instance_by_real_dev_instance[i];
126
127   if (show_dev_instance != ~0)
128     i = show_dev_instance;
129
130   s = format (s, "VirtualEthernet0/0/%d", i);
131   return s;
132 }
133
134 static int
135 vhost_user_name_renumber (vnet_hw_interface_t * hi, u32 new_dev_instance)
136 {
137   vhost_user_main_t *vum = &vhost_user_main;
138
139   vec_validate_init_empty (vum->show_dev_instance_by_real_dev_instance,
140                            hi->dev_instance, ~0);
141
142   vum->show_dev_instance_by_real_dev_instance[hi->dev_instance] =
143     new_dev_instance;
144
145   DBG_SOCK ("renumbered vhost-user interface dev_instance %d to %d",
146             hi->dev_instance, new_dev_instance);
147
148   return 0;
149 }
150
151 static_always_inline void *
152 map_guest_mem (vhost_user_intf_t * vui, uword addr, u32 * hint)
153 {
154   int i = *hint;
155   if (PREDICT_TRUE ((vui->regions[i].guest_phys_addr <= addr) &&
156                     ((vui->regions[i].guest_phys_addr +
157                       vui->regions[i].memory_size) > addr)))
158     {
159       return (void *) (vui->region_mmap_addr[i] + addr -
160                        vui->regions[i].guest_phys_addr);
161     }
162 #if __SSE4_2__
163   __m128i rl, rh, al, ah, r;
164   al = _mm_set1_epi64x (addr + 1);
165   ah = _mm_set1_epi64x (addr);
166
167   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[0]);
168   rl = _mm_cmpgt_epi64 (al, rl);
169   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[0]);
170   rh = _mm_cmpgt_epi64 (rh, ah);
171   r = _mm_and_si128 (rl, rh);
172
173   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[2]);
174   rl = _mm_cmpgt_epi64 (al, rl);
175   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[2]);
176   rh = _mm_cmpgt_epi64 (rh, ah);
177   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x22);
178
179   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[4]);
180   rl = _mm_cmpgt_epi64 (al, rl);
181   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[4]);
182   rh = _mm_cmpgt_epi64 (rh, ah);
183   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x44);
184
185   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[6]);
186   rl = _mm_cmpgt_epi64 (al, rl);
187   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[6]);
188   rh = _mm_cmpgt_epi64 (rh, ah);
189   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x88);
190
191   r = _mm_shuffle_epi8 (r, _mm_set_epi64x (0, 0x0e060c040a020800));
192   i = __builtin_ctzll (_mm_movemask_epi8 (r));
193
194   if (i < vui->nregions)
195     {
196       *hint = i;
197       return (void *) (vui->region_mmap_addr[i] + addr -
198                        vui->regions[i].guest_phys_addr);
199     }
200
201 #else
202   for (i = 0; i < vui->nregions; i++)
203     {
204       if ((vui->regions[i].guest_phys_addr <= addr) &&
205           ((vui->regions[i].guest_phys_addr + vui->regions[i].memory_size) >
206            addr))
207         {
208           *hint = i;
209           return (void *) (vui->region_mmap_addr[i] + addr -
210                            vui->regions[i].guest_phys_addr);
211         }
212     }
213 #endif
214   DBG_VQ ("failed to map guest mem addr %llx", addr);
215   *hint = 0;
216   return 0;
217 }
218
219 static inline void *
220 map_user_mem (vhost_user_intf_t * vui, uword addr)
221 {
222   int i;
223   for (i = 0; i < vui->nregions; i++)
224     {
225       if ((vui->regions[i].userspace_addr <= addr) &&
226           ((vui->regions[i].userspace_addr + vui->regions[i].memory_size) >
227            addr))
228         {
229           return (void *) (vui->region_mmap_addr[i] + addr -
230                            vui->regions[i].userspace_addr);
231         }
232     }
233   return 0;
234 }
235
236 static long
237 get_huge_page_size (int fd)
238 {
239   struct statfs s;
240   fstatfs (fd, &s);
241   return s.f_bsize;
242 }
243
244 static void
245 unmap_all_mem_regions (vhost_user_intf_t * vui)
246 {
247   int i, r;
248   for (i = 0; i < vui->nregions; i++)
249     {
250       if (vui->region_mmap_addr[i] != (void *) -1)
251         {
252
253           long page_sz = get_huge_page_size (vui->region_mmap_fd[i]);
254
255           ssize_t map_sz = (vui->regions[i].memory_size +
256                             vui->regions[i].mmap_offset +
257                             page_sz) & ~(page_sz - 1);
258
259           r =
260             munmap (vui->region_mmap_addr[i] - vui->regions[i].mmap_offset,
261                     map_sz);
262
263           DBG_SOCK
264             ("unmap memory region %d addr 0x%lx len 0x%lx page_sz 0x%x", i,
265              vui->region_mmap_addr[i], map_sz, page_sz);
266
267           vui->region_mmap_addr[i] = (void *) -1;
268
269           if (r == -1)
270             {
271               clib_warning ("failed to unmap memory region (errno %d)",
272                             errno);
273             }
274           close (vui->region_mmap_fd[i]);
275         }
276     }
277   vui->nregions = 0;
278 }
279
280
281 static clib_error_t *
282 vhost_user_callfd_read_ready (unix_file_t * uf)
283 {
284   __attribute__ ((unused)) int n;
285   u8 buff[8];
286   n = read (uf->file_descriptor, ((char *) &buff), 8);
287   return 0;
288 }
289
290 static inline void
291 vhost_user_if_disconnect (vhost_user_intf_t * vui)
292 {
293   vhost_user_main_t *vum = &vhost_user_main;
294   vnet_main_t *vnm = vnet_get_main ();
295   int q;
296
297   vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
298
299   if (vui->unix_file_index != ~0)
300     {
301       unix_file_del (&unix_main, unix_main.file_pool + vui->unix_file_index);
302       vui->unix_file_index = ~0;
303     }
304   else
305     close (vui->unix_fd);
306
307   hash_unset (vum->vhost_user_interface_index_by_sock_fd, vui->unix_fd);
308   hash_unset (vum->vhost_user_interface_index_by_listener_fd, vui->unix_fd);
309   vui->unix_fd = -1;
310   vui->is_up = 0;
311   for (q = 0; q < vui->num_vrings; q++)
312     {
313       if (vui->vrings[q].callfd > -1)
314         {
315           unix_file_t *uf = pool_elt_at_index (unix_main.file_pool,
316                                                vui->vrings[q].callfd_idx);
317           unix_file_del (&unix_main, uf);
318         }
319
320       if (vui->vrings[q].kickfd > -1)
321         close (vui->vrings[q].kickfd);
322
323       vui->vrings[q].callfd = -1;
324       vui->vrings[q].kickfd = -1;
325       vui->vrings[q].desc = NULL;
326       vui->vrings[q].avail = NULL;
327       vui->vrings[q].used = NULL;
328       vui->vrings[q].log_guest_addr = 0;
329       vui->vrings[q].log_used = 0;
330     }
331
332   unmap_all_mem_regions (vui);
333   DBG_SOCK ("interface ifindex %d disconnected", vui->sw_if_index);
334 }
335
336 #define VHOST_LOG_PAGE 0x1000
337 always_inline void
338 vhost_user_log_dirty_pages (vhost_user_intf_t * vui, u64 addr, u64 len)
339 {
340   if (PREDICT_TRUE (vui->log_base_addr == 0
341                     || !(vui->features & (1 << FEAT_VHOST_F_LOG_ALL))))
342     {
343       return;
344     }
345   if (PREDICT_FALSE ((addr + len - 1) / VHOST_LOG_PAGE / 8 >= vui->log_size))
346     {
347       DBG_SOCK ("vhost_user_log_dirty_pages(): out of range\n");
348       return;
349     }
350
351   CLIB_MEMORY_BARRIER ();
352   u64 page = addr / VHOST_LOG_PAGE;
353   while (page * VHOST_LOG_PAGE < addr + len)
354     {
355       ((u8 *) vui->log_base_addr)[page / 8] |= 1 << page % 8;
356       page++;
357     }
358 }
359
360 #define vhost_user_log_dirty_ring(vui, vq, member) \
361   if (PREDICT_FALSE(vq->log_used)) { \
362     vhost_user_log_dirty_pages(vui, vq->log_guest_addr + STRUCT_OFFSET_OF(vring_used_t, member), \
363                              sizeof(vq->used->member)); \
364   }
365
366 static clib_error_t *
367 vhost_user_socket_read (unix_file_t * uf)
368 {
369   int n, i;
370   int fd, number_of_fds = 0;
371   int fds[VHOST_MEMORY_MAX_NREGIONS];
372   vhost_user_msg_t msg;
373   struct msghdr mh;
374   struct iovec iov[1];
375   vhost_user_main_t *vum = &vhost_user_main;
376   vhost_user_intf_t *vui;
377   struct cmsghdr *cmsg;
378   uword *p;
379   u8 q;
380   unix_file_t template = { 0 };
381   vnet_main_t *vnm = vnet_get_main ();
382
383   p = hash_get (vum->vhost_user_interface_index_by_sock_fd,
384                 uf->file_descriptor);
385   if (p == 0)
386     {
387       DBG_SOCK ("FD %d doesn't belong to any interface", uf->file_descriptor);
388       return 0;
389     }
390   else
391     vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
392
393   char control[CMSG_SPACE (VHOST_MEMORY_MAX_NREGIONS * sizeof (int))];
394
395   memset (&mh, 0, sizeof (mh));
396   memset (control, 0, sizeof (control));
397
398   for (i = 0; i < VHOST_MEMORY_MAX_NREGIONS; i++)
399     fds[i] = -1;
400
401   /* set the payload */
402   iov[0].iov_base = (void *) &msg;
403   iov[0].iov_len = VHOST_USER_MSG_HDR_SZ;
404
405   mh.msg_iov = iov;
406   mh.msg_iovlen = 1;
407   mh.msg_control = control;
408   mh.msg_controllen = sizeof (control);
409
410   n = recvmsg (uf->file_descriptor, &mh, 0);
411
412   if (n != VHOST_USER_MSG_HDR_SZ)
413     goto close_socket;
414
415   if (mh.msg_flags & MSG_CTRUNC)
416     {
417       goto close_socket;
418     }
419
420   cmsg = CMSG_FIRSTHDR (&mh);
421
422   if (cmsg && (cmsg->cmsg_len > 0) && (cmsg->cmsg_level == SOL_SOCKET) &&
423       (cmsg->cmsg_type == SCM_RIGHTS) &&
424       (cmsg->cmsg_len - CMSG_LEN (0) <=
425        VHOST_MEMORY_MAX_NREGIONS * sizeof (int)))
426     {
427       number_of_fds = (cmsg->cmsg_len - CMSG_LEN (0)) / sizeof (int);
428       clib_memcpy (fds, CMSG_DATA (cmsg), number_of_fds * sizeof (int));
429     }
430
431   /* version 1, no reply bit set */
432   if ((msg.flags & 7) != 1)
433     {
434       DBG_SOCK ("malformed message received. closing socket");
435       goto close_socket;
436     }
437
438   {
439     int rv __attribute__ ((unused));
440     /* $$$$ pay attention to rv */
441     rv = read (uf->file_descriptor, ((char *) &msg) + n, msg.size);
442   }
443
444   switch (msg.request)
445     {
446     case VHOST_USER_GET_FEATURES:
447       DBG_SOCK ("if %d msg VHOST_USER_GET_FEATURES", vui->hw_if_index);
448
449       msg.flags |= 4;
450       msg.u64 = (1 << FEAT_VIRTIO_NET_F_MRG_RXBUF) |
451         (1 << FEAT_VIRTIO_F_ANY_LAYOUT) |
452         (1 << FEAT_VIRTIO_F_INDIRECT_DESC) |
453         (1 << FEAT_VHOST_F_LOG_ALL) |
454         (1 << FEAT_VIRTIO_NET_F_GUEST_ANNOUNCE) |
455         (1 << FEAT_VHOST_USER_F_PROTOCOL_FEATURES) |
456         (1UL << FEAT_VIRTIO_F_VERSION_1);
457       msg.u64 &= vui->feature_mask;
458
459       msg.size = sizeof (msg.u64);
460       break;
461
462     case VHOST_USER_SET_FEATURES:
463       DBG_SOCK ("if %d msg VHOST_USER_SET_FEATURES features 0x%016llx",
464                 vui->hw_if_index, msg.u64);
465
466       vui->features = msg.u64;
467
468       if (vui->features & (1 << FEAT_VIRTIO_NET_F_MRG_RXBUF))
469         vui->virtio_net_hdr_sz = 12;
470       else
471         vui->virtio_net_hdr_sz = 10;
472
473       vui->is_any_layout =
474         (vui->features & (1 << FEAT_VIRTIO_F_ANY_LAYOUT)) ? 1 : 0;
475
476       ASSERT (vui->virtio_net_hdr_sz < VLIB_BUFFER_PRE_DATA_SIZE);
477       vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
478       vui->is_up = 0;
479
480       for (q = 0; q < 2; q++)
481         {
482           vui->vrings[q].desc = 0;
483           vui->vrings[q].avail = 0;
484           vui->vrings[q].used = 0;
485           vui->vrings[q].log_guest_addr = 0;
486           vui->vrings[q].log_used = 0;
487         }
488
489       DBG_SOCK ("interface %d disconnected", vui->sw_if_index);
490
491       break;
492
493     case VHOST_USER_SET_MEM_TABLE:
494       DBG_SOCK ("if %d msg VHOST_USER_SET_MEM_TABLE nregions %d",
495                 vui->hw_if_index, msg.memory.nregions);
496
497       if ((msg.memory.nregions < 1) ||
498           (msg.memory.nregions > VHOST_MEMORY_MAX_NREGIONS))
499         {
500
501           DBG_SOCK ("number of mem regions must be between 1 and %i",
502                     VHOST_MEMORY_MAX_NREGIONS);
503
504           goto close_socket;
505         }
506
507       if (msg.memory.nregions != number_of_fds)
508         {
509           DBG_SOCK ("each memory region must have FD");
510           goto close_socket;
511         }
512       unmap_all_mem_regions (vui);
513       for (i = 0; i < msg.memory.nregions; i++)
514         {
515           clib_memcpy (&(vui->regions[i]), &msg.memory.regions[i],
516                        sizeof (vhost_user_memory_region_t));
517
518           long page_sz = get_huge_page_size (fds[i]);
519
520           /* align size to 2M page */
521           ssize_t map_sz = (vui->regions[i].memory_size +
522                             vui->regions[i].mmap_offset +
523                             page_sz) & ~(page_sz - 1);
524
525           vui->region_mmap_addr[i] = mmap (0, map_sz, PROT_READ | PROT_WRITE,
526                                            MAP_SHARED, fds[i], 0);
527           vui->region_guest_addr_lo[i] = vui->regions[i].guest_phys_addr;
528           vui->region_guest_addr_hi[i] = vui->regions[i].guest_phys_addr +
529             vui->regions[i].memory_size;
530
531           DBG_SOCK
532             ("map memory region %d addr 0 len 0x%lx fd %d mapped 0x%lx "
533              "page_sz 0x%x", i, map_sz, fds[i], vui->region_mmap_addr[i],
534              page_sz);
535
536           if (vui->region_mmap_addr[i] == MAP_FAILED)
537             {
538               clib_warning ("failed to map memory. errno is %d", errno);
539               goto close_socket;
540             }
541           vui->region_mmap_addr[i] += vui->regions[i].mmap_offset;
542           vui->region_mmap_fd[i] = fds[i];
543         }
544       vui->nregions = msg.memory.nregions;
545       break;
546
547     case VHOST_USER_SET_VRING_NUM:
548       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_NUM idx %d num %d",
549                 vui->hw_if_index, msg.state.index, msg.state.num);
550
551       if ((msg.state.num > 32768) ||    /* maximum ring size is 32768 */
552           (msg.state.num == 0) ||       /* it cannot be zero */
553           (msg.state.num % 2))  /* must be power of 2 */
554         goto close_socket;
555       vui->vrings[msg.state.index].qsz = msg.state.num;
556       break;
557
558     case VHOST_USER_SET_VRING_ADDR:
559       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_ADDR idx %d",
560                 vui->hw_if_index, msg.state.index);
561
562       vui->vrings[msg.state.index].desc = (vring_desc_t *)
563         map_user_mem (vui, msg.addr.desc_user_addr);
564       vui->vrings[msg.state.index].used = (vring_used_t *)
565         map_user_mem (vui, msg.addr.used_user_addr);
566       vui->vrings[msg.state.index].avail = (vring_avail_t *)
567         map_user_mem (vui, msg.addr.avail_user_addr);
568
569       if ((vui->vrings[msg.state.index].desc == NULL) ||
570           (vui->vrings[msg.state.index].used == NULL) ||
571           (vui->vrings[msg.state.index].avail == NULL))
572         {
573           DBG_SOCK ("failed to map user memory for hw_if_index %d",
574                     vui->hw_if_index);
575           goto close_socket;
576         }
577
578       vui->vrings[msg.state.index].log_guest_addr = msg.addr.log_guest_addr;
579       vui->vrings[msg.state.index].log_used =
580         (msg.addr.flags & (1 << VHOST_VRING_F_LOG)) ? 1 : 0;
581
582       /* Spec says: If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated,
583          the ring is initialized in an enabled state. */
584
585       if (!(vui->features & (1 << FEAT_VHOST_USER_F_PROTOCOL_FEATURES)))
586         {
587           vui->vrings[msg.state.index].enabled = 1;
588         }
589
590       vui->vrings[msg.state.index].last_used_idx =
591         vui->vrings[msg.state.index].used->idx;
592
593       /* tell driver that we don't want interrupts */
594       vui->vrings[msg.state.index].used->flags |= 1;
595       break;
596
597     case VHOST_USER_SET_OWNER:
598       DBG_SOCK ("if %d msg VHOST_USER_SET_OWNER", vui->hw_if_index);
599       break;
600
601     case VHOST_USER_RESET_OWNER:
602       DBG_SOCK ("if %d msg VHOST_USER_RESET_OWNER", vui->hw_if_index);
603       break;
604
605     case VHOST_USER_SET_VRING_CALL:
606       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_CALL u64 %d",
607                 vui->hw_if_index, msg.u64);
608
609       q = (u8) (msg.u64 & 0xFF);
610
611       if (!(msg.u64 & 0x100))
612         {
613           if (number_of_fds != 1)
614             goto close_socket;
615
616           /* if there is old fd, delete it */
617           if (vui->vrings[q].callfd > -1)
618             {
619               unix_file_t *uf = pool_elt_at_index (unix_main.file_pool,
620                                                    vui->vrings[q].callfd_idx);
621               unix_file_del (&unix_main, uf);
622             }
623           vui->vrings[q].callfd = fds[0];
624           template.read_function = vhost_user_callfd_read_ready;
625           template.file_descriptor = fds[0];
626           vui->vrings[q].callfd_idx = unix_file_add (&unix_main, &template);
627         }
628       else
629         vui->vrings[q].callfd = -1;
630       break;
631
632     case VHOST_USER_SET_VRING_KICK:
633       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_KICK u64 %d",
634                 vui->hw_if_index, msg.u64);
635
636       q = (u8) (msg.u64 & 0xFF);
637
638       if (!(msg.u64 & 0x100))
639         {
640           if (number_of_fds != 1)
641             goto close_socket;
642
643           if (vui->vrings[q].kickfd > -1)
644             close (vui->vrings[q].kickfd);
645
646           vui->vrings[q].kickfd = fds[0];
647         }
648       else
649         vui->vrings[q].kickfd = -1;
650       break;
651
652     case VHOST_USER_SET_VRING_ERR:
653       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_ERR u64 %d",
654                 vui->hw_if_index, msg.u64);
655
656       q = (u8) (msg.u64 & 0xFF);
657
658       if (!(msg.u64 & 0x100))
659         {
660           if (number_of_fds != 1)
661             goto close_socket;
662
663           fd = fds[0];
664         }
665       else
666         fd = -1;
667
668       vui->vrings[q].errfd = fd;
669       break;
670
671     case VHOST_USER_SET_VRING_BASE:
672       DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_BASE idx %d num %d",
673                 vui->hw_if_index, msg.state.index, msg.state.num);
674
675       vui->vrings[msg.state.index].last_avail_idx = msg.state.num;
676       break;
677
678     case VHOST_USER_GET_VRING_BASE:
679       DBG_SOCK ("if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
680                 vui->hw_if_index, msg.state.index, msg.state.num);
681
682       /* Spec says: Client must [...] stop ring upon receiving VHOST_USER_GET_VRING_BASE. */
683       vui->vrings[msg.state.index].enabled = 0;
684
685       msg.state.num = vui->vrings[msg.state.index].last_avail_idx;
686       msg.flags |= 4;
687       msg.size = sizeof (msg.state);
688       break;
689
690     case VHOST_USER_NONE:
691       DBG_SOCK ("if %d msg VHOST_USER_NONE", vui->hw_if_index);
692
693       break;
694
695     case VHOST_USER_SET_LOG_BASE:
696       {
697         DBG_SOCK ("if %d msg VHOST_USER_SET_LOG_BASE", vui->hw_if_index);
698
699         if (msg.size != sizeof (msg.log))
700           {
701             DBG_SOCK
702               ("invalid msg size for VHOST_USER_SET_LOG_BASE: %d instead of %d",
703                msg.size, sizeof (msg.log));
704             goto close_socket;
705           }
706
707         if (!
708             (vui->protocol_features & (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD)))
709           {
710             DBG_SOCK
711               ("VHOST_USER_PROTOCOL_F_LOG_SHMFD not set but VHOST_USER_SET_LOG_BASE received");
712             goto close_socket;
713           }
714
715         fd = fds[0];
716         /* align size to 2M page */
717         long page_sz = get_huge_page_size (fd);
718         ssize_t map_sz =
719           (msg.log.size + msg.log.offset + page_sz) & ~(page_sz - 1);
720
721         vui->log_base_addr = mmap (0, map_sz, PROT_READ | PROT_WRITE,
722                                    MAP_SHARED, fd, 0);
723
724         DBG_SOCK
725           ("map log region addr 0 len 0x%lx off 0x%lx fd %d mapped 0x%lx",
726            map_sz, msg.log.offset, fd, vui->log_base_addr);
727
728         if (vui->log_base_addr == MAP_FAILED)
729           {
730             clib_warning ("failed to map memory. errno is %d", errno);
731             goto close_socket;
732           }
733
734         vui->log_base_addr += msg.log.offset;
735         vui->log_size = msg.log.size;
736
737         msg.flags |= 4;
738         msg.size = sizeof (msg.u64);
739
740         break;
741       }
742
743     case VHOST_USER_SET_LOG_FD:
744       DBG_SOCK ("if %d msg VHOST_USER_SET_LOG_FD", vui->hw_if_index);
745
746       break;
747
748     case VHOST_USER_GET_PROTOCOL_FEATURES:
749       DBG_SOCK ("if %d msg VHOST_USER_GET_PROTOCOL_FEATURES",
750                 vui->hw_if_index);
751
752       msg.flags |= 4;
753       msg.u64 = (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD);
754       msg.size = sizeof (msg.u64);
755       break;
756
757     case VHOST_USER_SET_PROTOCOL_FEATURES:
758       DBG_SOCK ("if %d msg VHOST_USER_SET_PROTOCOL_FEATURES features 0x%lx",
759                 vui->hw_if_index, msg.u64);
760
761       vui->protocol_features = msg.u64;
762
763       break;
764
765     case VHOST_USER_SET_VRING_ENABLE:
766       DBG_SOCK ("if %d VHOST_USER_SET_VRING_ENABLE, enable: %d",
767                 vui->hw_if_index, msg.state.num);
768       vui->vrings[msg.state.index].enabled = msg.state.num;
769       break;
770
771     default:
772       DBG_SOCK ("unknown vhost-user message %d received. closing socket",
773                 msg.request);
774       goto close_socket;
775     }
776
777   /* if we have pointers to descriptor table, go up */
778   if (!vui->is_up &&
779       vui->vrings[VHOST_NET_VRING_IDX_TX].desc &&
780       vui->vrings[VHOST_NET_VRING_IDX_RX].desc)
781     {
782
783       DBG_SOCK ("interface %d connected", vui->sw_if_index);
784
785       vnet_hw_interface_set_flags (vnm, vui->hw_if_index,
786                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
787       vui->is_up = 1;
788
789     }
790
791   /* if we need to reply */
792   if (msg.flags & 4)
793     {
794       n =
795         send (uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
796       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
797         goto close_socket;
798     }
799
800   return 0;
801
802 close_socket:
803   vhost_user_if_disconnect (vui);
804   return 0;
805 }
806
807 static clib_error_t *
808 vhost_user_socket_error (unix_file_t * uf)
809 {
810   vhost_user_main_t *vum = &vhost_user_main;
811   vhost_user_intf_t *vui;
812   uword *p;
813
814   p = hash_get (vum->vhost_user_interface_index_by_sock_fd,
815                 uf->file_descriptor);
816   if (p == 0)
817     {
818       DBG_SOCK ("fd %d doesn't belong to any interface", uf->file_descriptor);
819       return 0;
820     }
821   else
822     vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
823
824   vhost_user_if_disconnect (vui);
825   return 0;
826 }
827
828 static clib_error_t *
829 vhost_user_socksvr_accept_ready (unix_file_t * uf)
830 {
831   int client_fd, client_len;
832   struct sockaddr_un client;
833   unix_file_t template = { 0 };
834   vhost_user_main_t *vum = &vhost_user_main;
835   vhost_user_intf_t *vui;
836   uword *p;
837
838   p = hash_get (vum->vhost_user_interface_index_by_listener_fd,
839                 uf->file_descriptor);
840   if (p == 0)
841     {
842       DBG_SOCK ("fd %d doesn't belong to any interface", uf->file_descriptor);
843       return 0;
844     }
845   else
846     vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
847
848   client_len = sizeof (client);
849   client_fd = accept (uf->file_descriptor,
850                       (struct sockaddr *) &client,
851                       (socklen_t *) & client_len);
852
853   if (client_fd < 0)
854     return clib_error_return_unix (0, "accept");
855
856   template.read_function = vhost_user_socket_read;
857   template.error_function = vhost_user_socket_error;
858   template.file_descriptor = client_fd;
859   vui->unix_file_index = unix_file_add (&unix_main, &template);
860
861   vui->client_fd = client_fd;
862   hash_set (vum->vhost_user_interface_index_by_sock_fd, vui->client_fd,
863             vui - vum->vhost_user_interfaces);
864
865   return 0;
866 }
867
868 static clib_error_t *
869 vhost_user_init (vlib_main_t * vm)
870 {
871   clib_error_t *error;
872   vhost_user_main_t *vum = &vhost_user_main;
873   vlib_thread_main_t *tm = vlib_get_thread_main ();
874   vlib_thread_registration_t *tr;
875   uword *p;
876
877   error = vlib_call_init_function (vm, ip4_init);
878   if (error)
879     return error;
880
881   vum->vhost_user_interface_index_by_listener_fd =
882     hash_create (0, sizeof (uword));
883   vum->vhost_user_interface_index_by_sock_fd =
884     hash_create (0, sizeof (uword));
885   vum->vhost_user_interface_index_by_sw_if_index =
886     hash_create (0, sizeof (uword));
887   vum->coalesce_frames = 32;
888   vum->coalesce_time = 1e-3;
889
890   vec_validate_aligned (vum->rx_buffers, tm->n_vlib_mains - 1,
891                         CLIB_CACHE_LINE_BYTES);
892
893   /* find out which cpus will be used for input */
894   vum->input_cpu_first_index = 0;
895   vum->input_cpu_count = 1;
896   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
897   tr = p ? (vlib_thread_registration_t *) p[0] : 0;
898
899   if (tr && tr->count > 0)
900     {
901       vum->input_cpu_first_index = tr->first_index;
902       vum->input_cpu_count = tr->count;
903     }
904
905   return 0;
906 }
907
908 VLIB_INIT_FUNCTION (vhost_user_init);
909
910 static clib_error_t *
911 vhost_user_exit (vlib_main_t * vm)
912 {
913   /* TODO cleanup */
914   return 0;
915 }
916
917 VLIB_MAIN_LOOP_EXIT_FUNCTION (vhost_user_exit);
918
919 enum
920 {
921   VHOST_USER_RX_NEXT_ETHERNET_INPUT,
922   VHOST_USER_RX_NEXT_DROP,
923   VHOST_USER_RX_N_NEXT,
924 };
925
926
927 typedef struct
928 {
929   u16 virtqueue;
930   u16 device_index;
931 #if VHOST_USER_COPY_TX_HDR == 1
932   virtio_net_hdr_t hdr;
933 #endif
934 } vhost_user_input_trace_t;
935
936 static u8 *
937 format_vhost_user_input_trace (u8 * s, va_list * va)
938 {
939   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
940   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
941   CLIB_UNUSED (vnet_main_t * vnm) = vnet_get_main ();
942   vhost_user_main_t *vum = &vhost_user_main;
943   vhost_user_input_trace_t *t = va_arg (*va, vhost_user_input_trace_t *);
944   vhost_user_intf_t *vui = vec_elt_at_index (vum->vhost_user_interfaces,
945                                              t->device_index);
946
947   vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, vui->sw_if_index);
948
949 #if VHOST_USER_COPY_TX_HDR == 1
950   uword indent = format_get_indent (s);
951 #endif
952
953   s = format (s, "%U virtqueue %d",
954               format_vnet_sw_interface_name, vnm, sw, t->virtqueue);
955
956 #if VHOST_USER_COPY_TX_HDR == 1
957   s = format (s, "\n%Uvirtio_net_hdr flags 0x%02x gso_type %u hdr_len %u",
958               format_white_space, indent,
959               t->hdr.flags, t->hdr.gso_type, t->hdr.hdr_len);
960 #endif
961
962   return s;
963 }
964
965 void
966 vhost_user_rx_trace (vlib_main_t * vm,
967                      vlib_node_runtime_t * node,
968                      vhost_user_intf_t * vui, i16 virtqueue)
969 {
970   u32 *b, n_left;
971   vhost_user_main_t *vum = &vhost_user_main;
972
973   u32 next_index = VHOST_USER_RX_NEXT_ETHERNET_INPUT;
974
975   n_left = vec_len (vui->d_trace_buffers);
976   b = vui->d_trace_buffers;
977
978   while (n_left >= 1)
979     {
980       u32 bi0;
981       vlib_buffer_t *b0;
982       vhost_user_input_trace_t *t0;
983
984       bi0 = b[0];
985       n_left -= 1;
986
987       b0 = vlib_get_buffer (vm, bi0);
988       vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 0);
989       t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
990       t0->virtqueue = virtqueue;
991       t0->device_index = vui - vum->vhost_user_interfaces;
992 #if VHOST_USER_COPY_TX_HDR == 1
993       clib_memcpy (&t0->hdr, b0->pre_data, sizeof (virtio_net_hdr_t));
994 #endif
995
996       b += 1;
997     }
998 }
999
1000 static inline void
1001 vhost_user_send_call (vlib_main_t * vm, vhost_user_vring_t * vq)
1002 {
1003   vhost_user_main_t *vum = &vhost_user_main;
1004   u64 x = 1;
1005   int rv __attribute__ ((unused));
1006   /* $$$$ pay attention to rv */
1007   rv = write (vq->callfd, &x, sizeof (x));
1008   vq->n_since_last_int = 0;
1009   vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
1010 }
1011
1012
1013 static u32
1014 vhost_user_if_input (vlib_main_t * vm,
1015                      vhost_user_main_t * vum,
1016                      vhost_user_intf_t * vui, vlib_node_runtime_t * node)
1017 {
1018   vhost_user_vring_t *txvq = &vui->vrings[VHOST_NET_VRING_IDX_TX];
1019   vhost_user_vring_t *rxvq = &vui->vrings[VHOST_NET_VRING_IDX_RX];
1020   uword n_rx_packets = 0, n_rx_bytes = 0;
1021   uword n_left;
1022   u32 n_left_to_next, *to_next;
1023   u32 next_index = 0;
1024   u32 next0;
1025   uword n_trace = vlib_get_trace_count (vm, node);
1026   u16 qsz_mask;
1027   u32 cpu_index, rx_len, drops, flush;
1028   f64 now = vlib_time_now (vm);
1029   u32 map_guest_hint_desc = 0;
1030   u32 map_guest_hint_indirect = 0;
1031   u32 *map_guest_hint_p = &map_guest_hint_desc;
1032
1033   vec_reset_length (vui->d_trace_buffers);
1034
1035   /* no descriptor ptr - bail out */
1036   if (PREDICT_FALSE (!txvq->desc || !txvq->avail || !txvq->enabled))
1037     return 0;
1038
1039   /* do we have pending intterupts ? */
1040   if ((txvq->n_since_last_int) && (txvq->int_deadline < now))
1041     vhost_user_send_call (vm, txvq);
1042
1043   if ((rxvq->n_since_last_int) && (rxvq->int_deadline < now))
1044     vhost_user_send_call (vm, rxvq);
1045
1046   /* only bit 0 of avail.flags is used so we don't want to deal with this
1047      interface if any other bit is set */
1048   if (PREDICT_FALSE (txvq->avail->flags & 0xFFFE))
1049     return 0;
1050
1051   n_left = (u16) (txvq->avail->idx - txvq->last_avail_idx);
1052
1053   /* nothing to do */
1054   if (PREDICT_FALSE (n_left == 0))
1055     return 0;
1056
1057   if (PREDICT_FALSE (n_left == txvq->qsz))
1058     {
1059       //Informational error logging when VPP is not receiving packets fast enough
1060       vlib_error_count (vm, node->node_index,
1061                         VHOST_USER_INPUT_FUNC_ERROR_FULL_RX_QUEUE, 1);
1062     }
1063
1064   if (PREDICT_FALSE (!vui->admin_up))
1065     {
1066       /* if intf is admin down, just drop all packets waiting in the ring */
1067       txvq->last_avail_idx = txvq->last_used_idx = txvq->avail->idx;
1068       CLIB_MEMORY_BARRIER ();
1069       txvq->used->idx = txvq->last_used_idx;
1070       vhost_user_log_dirty_ring (vui, txvq, idx);
1071       vhost_user_send_call (vm, txvq);
1072       return 0;
1073     }
1074
1075   qsz_mask = txvq->qsz - 1;
1076   cpu_index = os_get_cpu_number ();
1077   drops = 0;
1078   flush = 0;
1079
1080   if (n_left > VLIB_FRAME_SIZE)
1081     n_left = VLIB_FRAME_SIZE;
1082
1083   /* Allocate some buffers.
1084    * Note that buffers that are chained for jumbo
1085    * frames are allocated separately using a slower path.
1086    * The idea is to be certain to have enough buffers at least
1087    * to cycle through the descriptors without having to check for errors.
1088    * For jumbo frames, the bottleneck is memory copy anyway.
1089    */
1090   if (PREDICT_FALSE (!vum->rx_buffers[cpu_index]))
1091     {
1092       vec_alloc (vum->rx_buffers[cpu_index], 2 * VLIB_FRAME_SIZE);
1093
1094       if (PREDICT_FALSE (!vum->rx_buffers[cpu_index]))
1095         flush = n_left;         //Drop all input
1096     }
1097
1098   if (PREDICT_FALSE (_vec_len (vum->rx_buffers[cpu_index]) < n_left))
1099     {
1100       u32 curr_len = _vec_len (vum->rx_buffers[cpu_index]);
1101       _vec_len (vum->rx_buffers[cpu_index]) +=
1102         vlib_buffer_alloc_from_free_list (vm,
1103                                           vum->rx_buffers[cpu_index] +
1104                                           curr_len,
1105                                           2 * VLIB_FRAME_SIZE - curr_len,
1106                                           VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
1107
1108       if (PREDICT_FALSE (n_left > _vec_len (vum->rx_buffers[cpu_index])))
1109         flush = n_left - _vec_len (vum->rx_buffers[cpu_index]);
1110     }
1111
1112   if (PREDICT_FALSE (flush))
1113     {
1114       //Remove some input buffers
1115       drops += flush;
1116       n_left -= flush;
1117       vlib_error_count (vm, vhost_user_input_node.index,
1118                         VHOST_USER_INPUT_FUNC_ERROR_NO_BUFFER, flush);
1119       while (flush)
1120         {
1121           u16 desc_chain_head =
1122             txvq->avail->ring[txvq->last_avail_idx & qsz_mask];
1123           txvq->last_avail_idx++;
1124           txvq->used->ring[txvq->last_used_idx & qsz_mask].id =
1125             desc_chain_head;
1126           txvq->used->ring[txvq->last_used_idx & qsz_mask].len = 0;
1127           vhost_user_log_dirty_ring (vui, txvq,
1128                                      ring[txvq->last_used_idx & qsz_mask]);
1129           txvq->last_used_idx++;
1130           flush--;
1131         }
1132     }
1133
1134   rx_len = vec_len (vum->rx_buffers[cpu_index]);        //vector might be null
1135   while (n_left > 0)
1136     {
1137       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1138
1139       while (n_left > 0 && n_left_to_next > 0)
1140         {
1141           vlib_buffer_t *b_head, *b_current;
1142           u32 bi_head, bi_current;
1143           u16 desc_chain_head, desc_current;
1144           u8 error = VHOST_USER_INPUT_FUNC_ERROR_NO_ERROR;
1145
1146           if (PREDICT_TRUE (n_left > 1))
1147             {
1148               u32 next_desc =
1149                 txvq->avail->ring[(txvq->last_avail_idx + 1) & qsz_mask];
1150               void *buffer_addr =
1151                 map_guest_mem (vui, txvq->desc[next_desc].addr,
1152                                &map_guest_hint_desc);
1153               if (PREDICT_TRUE (buffer_addr != 0))
1154                 CLIB_PREFETCH (buffer_addr, 64, STORE);
1155
1156               u32 bi = vum->rx_buffers[cpu_index][rx_len - 2];
1157               vlib_prefetch_buffer_with_index (vm, bi, STORE);
1158               CLIB_PREFETCH (vlib_get_buffer (vm, bi)->data, 128, STORE);
1159             }
1160
1161           desc_chain_head = desc_current =
1162             txvq->avail->ring[txvq->last_avail_idx & qsz_mask];
1163           bi_head = bi_current = vum->rx_buffers[cpu_index][--rx_len];
1164           b_head = b_current = vlib_get_buffer (vm, bi_head);
1165           vlib_buffer_chain_init (b_head);
1166
1167           uword offset;
1168           if (PREDICT_TRUE (vui->is_any_layout) ||
1169               (!(txvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT) &&
1170                !(txvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT)))
1171             {
1172               /* ANYLAYOUT or single buffer */
1173               offset = vui->virtio_net_hdr_sz;
1174             }
1175           else
1176             {
1177               /* CSR case without ANYLAYOUT, skip 1st buffer */
1178               offset = txvq->desc[desc_current].len;
1179             }
1180
1181           vring_desc_t *desc_table = txvq->desc;
1182           u32 desc_index = desc_current;
1183           map_guest_hint_p = &map_guest_hint_desc;
1184
1185           if (txvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT)
1186             {
1187               desc_table = map_guest_mem (vui, txvq->desc[desc_current].addr,
1188                                           &map_guest_hint_desc);
1189               desc_index = 0;
1190               map_guest_hint_p = &map_guest_hint_indirect;
1191               if (PREDICT_FALSE (desc_table == 0))
1192                 {
1193                   error = VHOST_USER_INPUT_FUNC_ERROR_MMAP_FAIL;
1194                   goto out;
1195                 }
1196             }
1197
1198           while (1)
1199             {
1200               void *buffer_addr =
1201                 map_guest_mem (vui, desc_table[desc_index].addr,
1202                                map_guest_hint_p);
1203               if (PREDICT_FALSE (buffer_addr == 0))
1204                 {
1205                   error = VHOST_USER_INPUT_FUNC_ERROR_MMAP_FAIL;
1206                   goto out;
1207                 }
1208
1209               if (PREDICT_TRUE
1210                   (desc_table[desc_index].flags & VIRTQ_DESC_F_NEXT))
1211                 {
1212                   CLIB_PREFETCH (&desc_table[desc_table[desc_index].next],
1213                                  sizeof (vring_desc_t), STORE);
1214                 }
1215
1216 #if VHOST_USER_COPY_TX_HDR == 1
1217               if (PREDICT_TRUE (offset))
1218                 clib_memcpy (b->pre_data, buffer_addr, sizeof (virtio_net_hdr_t));      /* 12 byte hdr is not used on tx */
1219 #endif
1220
1221               if (desc_table[desc_index].len > offset)
1222                 {
1223                   u16 len = desc_table[desc_index].len - offset;
1224                   u16 copied = vlib_buffer_chain_append_data_with_alloc (vm,
1225                                                                          VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX,
1226                                                                          b_head,
1227                                                                          &b_current,
1228                                                                          buffer_addr
1229                                                                          +
1230                                                                          offset,
1231                                                                          len);
1232                   if (copied != len)
1233                     {
1234                       error = VHOST_USER_INPUT_FUNC_ERROR_NO_BUFFER;
1235                       break;
1236                     }
1237                 }
1238               offset = 0;
1239
1240               /* if next flag is set, take next desc in the chain */
1241               if ((desc_table[desc_index].flags & VIRTQ_DESC_F_NEXT))
1242                 desc_index = desc_table[desc_index].next;
1243               else
1244                 goto out;
1245             }
1246         out:
1247
1248           /* consume the descriptor and return it as used */
1249           txvq->last_avail_idx++;
1250           txvq->used->ring[txvq->last_used_idx & qsz_mask].id =
1251             desc_chain_head;
1252           txvq->used->ring[txvq->last_used_idx & qsz_mask].len = 0;
1253           vhost_user_log_dirty_ring (vui, txvq,
1254                                      ring[txvq->last_used_idx & qsz_mask]);
1255           txvq->last_used_idx++;
1256
1257           //It is important to free RX as fast as possible such that the TX
1258           //process does not drop packets
1259           if ((txvq->last_used_idx & 0x3f) == 0)        // Every 64 packets
1260             txvq->used->idx = txvq->last_used_idx;
1261
1262           if (PREDICT_FALSE (b_head->current_length < 14 &&
1263                              error == VHOST_USER_INPUT_FUNC_ERROR_NO_ERROR))
1264             error = VHOST_USER_INPUT_FUNC_ERROR_UNDERSIZED_FRAME;
1265
1266           VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b_head);
1267
1268           vnet_buffer (b_head)->sw_if_index[VLIB_RX] = vui->sw_if_index;
1269           vnet_buffer (b_head)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1270           b_head->error = node->errors[error];
1271
1272           if (PREDICT_FALSE (n_trace > n_rx_packets))
1273             vec_add1 (vui->d_trace_buffers, bi_head);
1274
1275           if (PREDICT_FALSE (error))
1276             {
1277               drops++;
1278               next0 = VHOST_USER_RX_NEXT_DROP;
1279             }
1280           else
1281             {
1282               n_rx_bytes +=
1283                 b_head->current_length +
1284                 b_head->total_length_not_including_first_buffer;
1285               n_rx_packets++;
1286               next0 = VHOST_USER_RX_NEXT_ETHERNET_INPUT;
1287             }
1288
1289           to_next[0] = bi_head;
1290           to_next++;
1291           n_left_to_next--;
1292           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1293                                            to_next, n_left_to_next,
1294                                            bi_head, next0);
1295           n_left--;
1296         }
1297
1298       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1299
1300     }
1301
1302   if (PREDICT_TRUE (vum->rx_buffers[cpu_index] != 0))
1303     _vec_len (vum->rx_buffers[cpu_index]) = rx_len;
1304
1305   /* give buffers back to driver */
1306   CLIB_MEMORY_BARRIER ();
1307   txvq->used->idx = txvq->last_used_idx;
1308   vhost_user_log_dirty_ring (vui, txvq, idx);
1309
1310   if (PREDICT_FALSE (vec_len (vui->d_trace_buffers) > 0))
1311     {
1312       vhost_user_rx_trace (vm, node, vui, VHOST_NET_VRING_IDX_TX);
1313       vlib_set_trace_count (vm, node,
1314                             n_trace - vec_len (vui->d_trace_buffers));
1315     }
1316
1317   /* interrupt (call) handling */
1318   if ((txvq->callfd > -1) && !(txvq->avail->flags & 1))
1319     {
1320       txvq->n_since_last_int += n_rx_packets;
1321
1322       if (txvq->n_since_last_int > vum->coalesce_frames)
1323         vhost_user_send_call (vm, txvq);
1324     }
1325
1326   if (PREDICT_FALSE (drops))
1327     {
1328       vlib_increment_simple_counter
1329         (vnet_main.interface_main.sw_if_counters
1330          + VNET_INTERFACE_COUNTER_DROP, os_get_cpu_number (),
1331          vui->sw_if_index, drops);
1332     }
1333
1334   /* increase rx counters */
1335   vlib_increment_combined_counter
1336     (vnet_main.interface_main.combined_sw_if_counters
1337      + VNET_INTERFACE_COUNTER_RX,
1338      os_get_cpu_number (), vui->sw_if_index, n_rx_packets, n_rx_bytes);
1339
1340   return n_rx_packets;
1341 }
1342
1343 static uword
1344 vhost_user_input (vlib_main_t * vm,
1345                   vlib_node_runtime_t * node, vlib_frame_t * f)
1346 {
1347   vhost_user_main_t *vum = &vhost_user_main;
1348   u32 cpu_index = os_get_cpu_number ();
1349   vhost_user_intf_t *vui;
1350   uword n_rx_packets = 0;
1351   int i;
1352
1353   for (i = 0; i < vec_len (vum->vhost_user_interfaces); i++)
1354     {
1355       vui = vec_elt_at_index (vum->vhost_user_interfaces, i);
1356       if (vui->is_up)
1357         {
1358           if ((i % vum->input_cpu_count) ==
1359               (cpu_index - vum->input_cpu_first_index))
1360             n_rx_packets += vhost_user_if_input (vm, vum, vui, node);
1361         }
1362     }
1363   return n_rx_packets;
1364 }
1365
1366 /* *INDENT-OFF* */
1367 VLIB_REGISTER_NODE (vhost_user_input_node) = {
1368   .function = vhost_user_input,
1369   .type = VLIB_NODE_TYPE_INPUT,
1370   .name = "vhost-user-input",
1371
1372   /* Will be enabled if/when hardware is detected. */
1373   .state = VLIB_NODE_STATE_DISABLED,
1374
1375   .format_buffer = format_ethernet_header_with_length,
1376   .format_trace = format_vhost_user_input_trace,
1377
1378   .n_errors = VHOST_USER_INPUT_FUNC_N_ERROR,
1379   .error_strings = vhost_user_input_func_error_strings,
1380
1381   .n_next_nodes = VHOST_USER_RX_N_NEXT,
1382   .next_nodes = {
1383     [VHOST_USER_RX_NEXT_DROP] = "error-drop",
1384     [VHOST_USER_RX_NEXT_ETHERNET_INPUT] = "ethernet-input",
1385   },
1386 };
1387
1388 VLIB_NODE_FUNCTION_MULTIARCH (vhost_user_input_node, vhost_user_input)
1389 /* *INDENT-ON* */
1390
1391 static uword
1392 vhost_user_intfc_tx (vlib_main_t * vm,
1393                      vlib_node_runtime_t * node, vlib_frame_t * frame)
1394 {
1395   u32 *buffers = vlib_frame_args (frame);
1396   u32 n_left = 0;
1397   vhost_user_main_t *vum = &vhost_user_main;
1398   uword n_packets = 0;
1399   vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
1400   vhost_user_intf_t *vui =
1401     vec_elt_at_index (vum->vhost_user_interfaces, rd->dev_instance);
1402   vhost_user_vring_t *rxvq = &vui->vrings[VHOST_NET_VRING_IDX_RX];
1403   u16 qsz_mask;
1404   u8 error = VHOST_USER_TX_FUNC_ERROR_NONE;
1405
1406   n_left = n_packets = frame->n_vectors;
1407   u32 map_guest_hint_desc = 0;
1408   u32 map_guest_hint_indirect = 0;
1409   u32 *map_guest_hint_p = &map_guest_hint_desc;
1410
1411   if (PREDICT_FALSE (!vui->is_up))
1412     goto done2;
1413
1414   if (PREDICT_FALSE
1415       (!rxvq->desc || !rxvq->avail || vui->sock_errno != 0 || !rxvq->enabled))
1416     {
1417       error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
1418       goto done2;
1419     }
1420
1421   if (PREDICT_FALSE (vui->lockp != 0))
1422     {
1423       while (__sync_lock_test_and_set (vui->lockp, 1))
1424         ;
1425     }
1426
1427   /* only bit 0 of avail.flags is used so we don't want to deal with this
1428      interface if any other bit is set */
1429   if (PREDICT_FALSE (rxvq->avail->flags & 0xFFFE))
1430     {
1431       error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
1432       goto done2;
1433     }
1434
1435   if (PREDICT_FALSE ((rxvq->avail->idx == rxvq->last_avail_idx)))
1436     {
1437       error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1438       goto done2;
1439     }
1440
1441   qsz_mask = rxvq->qsz - 1;     /* qsz is always power of 2 */
1442
1443   while (n_left > 0)
1444     {
1445       vlib_buffer_t *b0, *current_b0;
1446       u16 desc_head, desc_index, desc_len;
1447       vring_desc_t *desc_table;
1448       void *buffer_addr;
1449       u32 buffer_len;
1450
1451       b0 = vlib_get_buffer (vm, buffers[0]);
1452       buffers++;
1453
1454       if (PREDICT_FALSE (rxvq->last_avail_idx == rxvq->avail->idx))
1455         {
1456           error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1457           goto done;
1458         }
1459
1460       desc_table = rxvq->desc;
1461       map_guest_hint_p = &map_guest_hint_desc;
1462       desc_head = desc_index =
1463         rxvq->avail->ring[rxvq->last_avail_idx & qsz_mask];
1464       if (rxvq->desc[desc_head].flags & VIRTQ_DESC_F_INDIRECT)
1465         {
1466           if (PREDICT_FALSE
1467               (rxvq->desc[desc_head].len < sizeof (vring_desc_t)))
1468             {
1469               error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
1470               goto done;
1471             }
1472           if (PREDICT_FALSE
1473               (!(desc_table =
1474                  map_guest_mem (vui, rxvq->desc[desc_index].addr,
1475                                 &map_guest_hint_desc))))
1476             {
1477               error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1478               goto done;
1479             }
1480           desc_index = 0;
1481           map_guest_hint_p = &map_guest_hint_indirect;
1482         }
1483
1484       desc_len = vui->virtio_net_hdr_sz;
1485
1486       if (PREDICT_FALSE
1487           (!(buffer_addr =
1488              map_guest_mem (vui, desc_table[desc_index].addr,
1489                             map_guest_hint_p))))
1490         {
1491           error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1492           goto done;
1493         }
1494       buffer_len = desc_table[desc_index].len;
1495
1496       CLIB_PREFETCH (buffer_addr,
1497                      clib_min (buffer_len, 2 * CLIB_CACHE_LINE_BYTES), STORE);
1498
1499       virtio_net_hdr_mrg_rxbuf_t *hdr =
1500         (virtio_net_hdr_mrg_rxbuf_t *) buffer_addr;
1501       hdr->hdr.flags = 0;
1502       hdr->hdr.gso_type = 0;
1503       if (vui->virtio_net_hdr_sz == 12)
1504         hdr->num_buffers = 1;
1505
1506       vhost_user_log_dirty_pages (vui, desc_table[desc_index].addr,
1507                                   vui->virtio_net_hdr_sz);
1508
1509       u16 bytes_left = b0->current_length;
1510       buffer_addr += vui->virtio_net_hdr_sz;
1511       buffer_len -= vui->virtio_net_hdr_sz;
1512       current_b0 = b0;
1513       while (1)
1514         {
1515           if (!bytes_left)
1516             {                   //Get new input
1517               if (current_b0->flags & VLIB_BUFFER_NEXT_PRESENT)
1518                 {
1519                   current_b0 = vlib_get_buffer (vm, current_b0->next_buffer);
1520                   bytes_left = current_b0->current_length;
1521                 }
1522               else
1523                 {
1524                   //End of packet
1525                   break;
1526                 }
1527             }
1528
1529           if (buffer_len == 0)
1530             {                   //Get new output
1531               if (desc_table[desc_index].flags & VIRTQ_DESC_F_NEXT)
1532                 {
1533                   //Next one is chained
1534                   desc_index = desc_table[desc_index].next;
1535                   if (PREDICT_FALSE
1536                       (!(buffer_addr =
1537                          map_guest_mem (vui, desc_table[desc_index].addr,
1538                                         map_guest_hint_p))))
1539                     {
1540                       rxvq->last_used_idx -= hdr->num_buffers - 1;
1541                       rxvq->last_avail_idx -= hdr->num_buffers - 1;
1542                       error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1543                       goto done;
1544                     }
1545                   buffer_len = desc_table[desc_index].len;
1546                 }
1547               else if (vui->virtio_net_hdr_sz == 12)    //MRG is available
1548                 {
1549                   //Move from available to used buffer
1550                   rxvq->used->ring[rxvq->last_used_idx & qsz_mask].id =
1551                     desc_head;
1552                   rxvq->used->ring[rxvq->last_used_idx & qsz_mask].len =
1553                     desc_len;
1554                   vhost_user_log_dirty_ring (vui, rxvq,
1555                                              ring[rxvq->last_used_idx &
1556                                                   qsz_mask]);
1557                   rxvq->last_avail_idx++;
1558                   rxvq->last_used_idx++;
1559                   hdr->num_buffers++;
1560
1561                   if (PREDICT_FALSE
1562                       (rxvq->last_avail_idx == rxvq->avail->idx))
1563                     {
1564                       //Dequeue queued descriptors for this packet
1565                       rxvq->last_used_idx -= hdr->num_buffers - 1;
1566                       rxvq->last_avail_idx -= hdr->num_buffers - 1;
1567                       error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1568                       goto done;
1569                     }
1570
1571                   desc_table = rxvq->desc;
1572                   map_guest_hint_p = &map_guest_hint_desc;
1573                   desc_head = desc_index =
1574                     rxvq->avail->ring[rxvq->last_avail_idx & qsz_mask];
1575                   if (PREDICT_FALSE
1576                       (rxvq->desc[desc_head].flags & VIRTQ_DESC_F_INDIRECT))
1577                     {
1578                       //It is seriously unlikely that a driver will put indirect descriptor
1579                       //after non-indirect descriptor.
1580                       if (PREDICT_FALSE
1581                           (rxvq->desc[desc_head].len < sizeof (vring_desc_t)))
1582                         {
1583                           error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
1584                           goto done;
1585                         }
1586                       if (PREDICT_FALSE
1587                           (!(desc_table =
1588                              map_guest_mem (vui,
1589                                             rxvq->desc[desc_index].addr,
1590                                             &map_guest_hint_desc))))
1591                         {
1592                           error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1593                           goto done;
1594                         }
1595                       desc_index = 0;
1596                       map_guest_hint_p = &map_guest_hint_indirect;
1597                     }
1598
1599                   if (PREDICT_FALSE
1600                       (!(buffer_addr =
1601                          map_guest_mem (vui, desc_table[desc_index].addr,
1602                                         map_guest_hint_p))))
1603                     {
1604                       error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1605                       goto done;
1606                     }
1607                   buffer_len = desc_table[desc_index].len;
1608                   CLIB_PREFETCH (buffer_addr,
1609                                  clib_min (buffer_len,
1610                                            2 * CLIB_CACHE_LINE_BYTES), STORE);
1611                 }
1612               else
1613                 {
1614                   error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOMRG;
1615                   goto done;
1616                 }
1617             }
1618
1619           u16 bytes_to_copy = bytes_left;
1620           bytes_to_copy =
1621             (bytes_to_copy > buffer_len) ? buffer_len : bytes_to_copy;
1622           clib_memcpy (buffer_addr,
1623                        vlib_buffer_get_current (current_b0) +
1624                        current_b0->current_length - bytes_left,
1625                        bytes_to_copy);
1626
1627           vhost_user_log_dirty_pages (vui,
1628                                       desc_table[desc_index].addr +
1629                                       desc_table[desc_index].len -
1630                                       bytes_left - bytes_to_copy,
1631                                       bytes_to_copy);
1632
1633           bytes_left -= bytes_to_copy;
1634           buffer_len -= bytes_to_copy;
1635           buffer_addr += bytes_to_copy;
1636           desc_len += bytes_to_copy;
1637         }
1638
1639       if (PREDICT_TRUE (n_left >= 2))
1640         {
1641           vlib_prefetch_buffer_with_index (vm, buffers[1], STORE);
1642           CLIB_PREFETCH (&n_left, sizeof (n_left), STORE);
1643         }
1644
1645       //Move from available to used ring
1646       rxvq->used->ring[rxvq->last_used_idx & qsz_mask].id = desc_head;
1647       rxvq->used->ring[rxvq->last_used_idx & qsz_mask].len = desc_len;
1648       vhost_user_log_dirty_ring (vui, rxvq,
1649                                  ring[rxvq->last_used_idx & qsz_mask]);
1650
1651       rxvq->last_avail_idx++;
1652       rxvq->last_used_idx++;
1653
1654       n_left--;                 //At the end for error counting when 'goto done' is invoked
1655     }
1656
1657 done:
1658   CLIB_MEMORY_BARRIER ();
1659   rxvq->used->idx = rxvq->last_used_idx;
1660   vhost_user_log_dirty_ring (vui, rxvq, idx);
1661
1662   /* interrupt (call) handling */
1663   if ((rxvq->callfd > -1) && !(rxvq->avail->flags & 1))
1664     {
1665       rxvq->n_since_last_int += n_packets - n_left;
1666
1667       if (rxvq->n_since_last_int > vum->coalesce_frames)
1668         vhost_user_send_call (vm, rxvq);
1669     }
1670
1671 done2:
1672
1673   if (PREDICT_FALSE (vui->lockp != 0))
1674     *vui->lockp = 0;
1675
1676   if (PREDICT_FALSE (n_left && error != VHOST_USER_TX_FUNC_ERROR_NONE))
1677     {
1678       vlib_error_count (vm, node->node_index, error, n_left);
1679       vlib_increment_simple_counter
1680         (vnet_main.interface_main.sw_if_counters
1681          + VNET_INTERFACE_COUNTER_DROP,
1682          os_get_cpu_number (), vui->sw_if_index, n_left);
1683     }
1684
1685   vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
1686   return frame->n_vectors;
1687 }
1688
1689 static clib_error_t *
1690 vhost_user_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
1691                                     u32 flags)
1692 {
1693   vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
1694   uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
1695   vhost_user_main_t *vum = &vhost_user_main;
1696   vhost_user_intf_t *vui =
1697     vec_elt_at_index (vum->vhost_user_interfaces, hif->dev_instance);
1698
1699   vui->admin_up = is_up;
1700
1701   if (is_up)
1702     vnet_hw_interface_set_flags (vnm, vui->hw_if_index,
1703                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
1704
1705   return /* no error */ 0;
1706 }
1707
1708 /* *INDENT-OFF* */
1709 VNET_DEVICE_CLASS (vhost_user_dev_class,static) = {
1710   .name = "vhost-user",
1711   .tx_function = vhost_user_intfc_tx,
1712   .tx_function_n_errors = VHOST_USER_TX_FUNC_N_ERROR,
1713   .tx_function_error_strings = vhost_user_tx_func_error_strings,
1714   .format_device_name = format_vhost_user_interface_name,
1715   .name_renumber = vhost_user_name_renumber,
1716   .admin_up_down_function = vhost_user_interface_admin_up_down,
1717   .no_flatten_output_chains = 1,
1718 };
1719
1720 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (vhost_user_dev_class,
1721                                    vhost_user_intfc_tx)
1722 /* *INDENT-ON* */
1723
1724 static uword
1725 vhost_user_process (vlib_main_t * vm,
1726                     vlib_node_runtime_t * rt, vlib_frame_t * f)
1727 {
1728   vhost_user_main_t *vum = &vhost_user_main;
1729   vhost_user_intf_t *vui;
1730   struct sockaddr_un sun;
1731   int sockfd;
1732   unix_file_t template = { 0 };
1733   f64 timeout = 3153600000.0 /* 100 years */ ;
1734   uword *event_data = 0;
1735
1736   sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
1737   sun.sun_family = AF_UNIX;
1738   template.read_function = vhost_user_socket_read;
1739   template.error_function = vhost_user_socket_error;
1740
1741
1742   if (sockfd < 0)
1743     return 0;
1744
1745   while (1)
1746     {
1747       vlib_process_wait_for_event_or_clock (vm, timeout);
1748       vlib_process_get_events (vm, &event_data);
1749       vec_reset_length (event_data);
1750
1751       timeout = 3.0;
1752
1753       vec_foreach (vui, vum->vhost_user_interfaces)
1754       {
1755
1756         if (vui->sock_is_server || !vui->active)
1757           continue;
1758
1759         if (vui->unix_fd == -1)
1760           {
1761             /* try to connect */
1762
1763             strncpy (sun.sun_path, (char *) vui->sock_filename,
1764                      sizeof (sun.sun_path) - 1);
1765
1766             if (connect
1767                 (sockfd, (struct sockaddr *) &sun,
1768                  sizeof (struct sockaddr_un)) == 0)
1769               {
1770                 vui->sock_errno = 0;
1771                 vui->unix_fd = sockfd;
1772                 template.file_descriptor = sockfd;
1773                 vui->unix_file_index = unix_file_add (&unix_main, &template);
1774                 hash_set (vum->vhost_user_interface_index_by_sock_fd, sockfd,
1775                           vui - vum->vhost_user_interfaces);
1776
1777                 sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
1778                 if (sockfd < 0)
1779                   return 0;
1780               }
1781             else
1782               {
1783                 vui->sock_errno = errno;
1784               }
1785           }
1786         else
1787           {
1788             /* check if socket is alive */
1789             int error = 0;
1790             socklen_t len = sizeof (error);
1791             int retval =
1792               getsockopt (vui->unix_fd, SOL_SOCKET, SO_ERROR, &error, &len);
1793
1794             if (retval)
1795               vhost_user_if_disconnect (vui);
1796           }
1797       }
1798     }
1799   return 0;
1800 }
1801
1802 /* *INDENT-OFF* */
1803 VLIB_REGISTER_NODE (vhost_user_process_node,static) = {
1804     .function = vhost_user_process,
1805     .type = VLIB_NODE_TYPE_PROCESS,
1806     .name = "vhost-user-process",
1807 };
1808 /* *INDENT-ON* */
1809
1810 int
1811 vhost_user_delete_if (vnet_main_t * vnm, vlib_main_t * vm, u32 sw_if_index)
1812 {
1813   vhost_user_main_t *vum = &vhost_user_main;
1814   vhost_user_intf_t *vui;
1815   uword *p = NULL;
1816   int rv = 0;
1817
1818   p = hash_get (vum->vhost_user_interface_index_by_sw_if_index, sw_if_index);
1819   if (p == 0)
1820     {
1821       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1822     }
1823   else
1824     {
1825       vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
1826     }
1827
1828   // interface is inactive
1829   vui->active = 0;
1830   // disconnect interface sockets
1831   vhost_user_if_disconnect (vui);
1832   // add to inactive interface list
1833   vec_add1 (vum->vhost_user_inactive_interfaces_index, p[0]);
1834
1835   // reset renumbered iface
1836   if (p[0] < vec_len (vum->show_dev_instance_by_real_dev_instance))
1837     vum->show_dev_instance_by_real_dev_instance[p[0]] = ~0;
1838
1839   ethernet_delete_interface (vnm, vui->hw_if_index);
1840   DBG_SOCK ("deleted (deactivated) vhost-user interface instance %d", p[0]);
1841
1842   return rv;
1843 }
1844
1845 // init server socket on specified sock_filename
1846 static int
1847 vhost_user_init_server_sock (const char *sock_filename, int *sockfd)
1848 {
1849   int rv = 0;
1850   struct sockaddr_un un = { };
1851   int fd;
1852   /* create listening socket */
1853   fd = socket (AF_UNIX, SOCK_STREAM, 0);
1854
1855   if (fd < 0)
1856     {
1857       return VNET_API_ERROR_SYSCALL_ERROR_1;
1858     }
1859
1860   un.sun_family = AF_UNIX;
1861   strncpy ((char *) un.sun_path, (char *) sock_filename,
1862            sizeof (un.sun_path) - 1);
1863
1864   /* remove if exists */
1865   unlink ((char *) sock_filename);
1866
1867   if (bind (fd, (struct sockaddr *) &un, sizeof (un)) == -1)
1868     {
1869       rv = VNET_API_ERROR_SYSCALL_ERROR_2;
1870       goto error;
1871     }
1872
1873   if (listen (fd, 1) == -1)
1874     {
1875       rv = VNET_API_ERROR_SYSCALL_ERROR_3;
1876       goto error;
1877     }
1878
1879   unix_file_t template = { 0 };
1880   template.read_function = vhost_user_socksvr_accept_ready;
1881   template.file_descriptor = fd;
1882   unix_file_add (&unix_main, &template);
1883   *sockfd = fd;
1884   return rv;
1885
1886 error:
1887   close (fd);
1888   return rv;
1889 }
1890
1891 // get new vhost_user_intf_t from inactive interfaces or create new one
1892 static vhost_user_intf_t *
1893 vhost_user_vui_new ()
1894 {
1895   vhost_user_main_t *vum = &vhost_user_main;
1896   vhost_user_intf_t *vui = NULL;
1897   int inactive_cnt = vec_len (vum->vhost_user_inactive_interfaces_index);
1898   // if there are any inactive ifaces
1899   if (inactive_cnt > 0)
1900     {
1901       // take last
1902       u32 vui_idx =
1903         vum->vhost_user_inactive_interfaces_index[inactive_cnt - 1];
1904       if (vec_len (vum->vhost_user_interfaces) > vui_idx)
1905         {
1906           vui = vec_elt_at_index (vum->vhost_user_interfaces, vui_idx);
1907           DBG_SOCK ("reusing inactive vhost-user interface index %d",
1908                     vui_idx);
1909         }
1910       // "remove" from inactive list
1911       _vec_len (vum->vhost_user_inactive_interfaces_index) -= 1;
1912     }
1913
1914   // vui was not retrieved from inactive ifaces - create new
1915   if (!vui)
1916     vec_add2 (vum->vhost_user_interfaces, vui, 1);
1917   return vui;
1918 }
1919
1920 // create ethernet interface for vhost user intf
1921 static void
1922 vhost_user_create_ethernet (vnet_main_t * vnm, vlib_main_t * vm,
1923                             vhost_user_intf_t * vui, u8 * hwaddress)
1924 {
1925   vhost_user_main_t *vum = &vhost_user_main;
1926   u8 hwaddr[6];
1927   clib_error_t *error;
1928
1929   /* create hw and sw interface */
1930   if (hwaddress)
1931     {
1932       clib_memcpy (hwaddr, hwaddress, 6);
1933     }
1934   else
1935     {
1936       f64 now = vlib_time_now (vm);
1937       u32 rnd;
1938       rnd = (u32) (now * 1e6);
1939       rnd = random_u32 (&rnd);
1940
1941       clib_memcpy (hwaddr + 2, &rnd, sizeof (rnd));
1942       hwaddr[0] = 2;
1943       hwaddr[1] = 0xfe;
1944     }
1945
1946   error = ethernet_register_interface
1947     (vnm,
1948      vhost_user_dev_class.index,
1949      vui - vum->vhost_user_interfaces /* device instance */ ,
1950      hwaddr /* ethernet address */ ,
1951      &vui->hw_if_index, 0 /* flag change */ );
1952   if (error)
1953     clib_error_report (error);
1954
1955   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, vui->hw_if_index);
1956   hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = 9000;
1957 }
1958
1959 // initialize vui with specified attributes
1960 static void
1961 vhost_user_vui_init (vnet_main_t * vnm,
1962                      vhost_user_intf_t * vui, int sockfd,
1963                      const char *sock_filename,
1964                      u8 is_server, u64 feature_mask, u32 * sw_if_index)
1965 {
1966   vnet_sw_interface_t *sw;
1967   sw = vnet_get_hw_sw_interface (vnm, vui->hw_if_index);
1968   vlib_thread_main_t *tm = vlib_get_thread_main ();
1969   int q;
1970
1971   vui->unix_fd = sockfd;
1972   vui->sw_if_index = sw->sw_if_index;
1973   vui->num_vrings = 2;
1974   vui->sock_is_server = is_server;
1975   strncpy (vui->sock_filename, sock_filename,
1976            ARRAY_LEN (vui->sock_filename) - 1);
1977   vui->sock_errno = 0;
1978   vui->is_up = 0;
1979   vui->feature_mask = feature_mask;
1980   vui->active = 1;
1981   vui->unix_file_index = ~0;
1982   vui->log_base_addr = 0;
1983
1984   for (q = 0; q < 2; q++)
1985     {
1986       vui->vrings[q].enabled = 0;
1987       vui->vrings[q].callfd = -1;
1988       vui->vrings[q].kickfd = -1;
1989     }
1990
1991   vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
1992
1993   if (sw_if_index)
1994     *sw_if_index = vui->sw_if_index;
1995
1996   if (tm->n_vlib_mains > 1)
1997     {
1998       vui->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
1999                                            CLIB_CACHE_LINE_BYTES);
2000       memset ((void *) vui->lockp, 0, CLIB_CACHE_LINE_BYTES);
2001     }
2002 }
2003
2004 // register vui and start polling on it
2005 static void
2006 vhost_user_vui_register (vlib_main_t * vm, vhost_user_intf_t * vui)
2007 {
2008   vhost_user_main_t *vum = &vhost_user_main;
2009   int cpu_index;
2010   vlib_thread_main_t *tm = vlib_get_thread_main ();
2011
2012   hash_set (vum->vhost_user_interface_index_by_listener_fd, vui->unix_fd,
2013             vui - vum->vhost_user_interfaces);
2014   hash_set (vum->vhost_user_interface_index_by_sw_if_index, vui->sw_if_index,
2015             vui - vum->vhost_user_interfaces);
2016
2017   /* start polling */
2018   cpu_index = vum->input_cpu_first_index +
2019     (vui - vum->vhost_user_interfaces) % vum->input_cpu_count;
2020
2021   if (tm->n_vlib_mains == 1)
2022     vlib_node_set_state (vm, vhost_user_input_node.index,
2023                          VLIB_NODE_STATE_POLLING);
2024   else
2025     vlib_node_set_state (vlib_mains[cpu_index], vhost_user_input_node.index,
2026                          VLIB_NODE_STATE_POLLING);
2027
2028   /* tell process to start polling for sockets */
2029   vlib_process_signal_event (vm, vhost_user_process_node.index, 0, 0);
2030 }
2031
2032 int
2033 vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
2034                       const char *sock_filename,
2035                       u8 is_server,
2036                       u32 * sw_if_index,
2037                       u64 feature_mask,
2038                       u8 renumber, u32 custom_dev_instance, u8 * hwaddr)
2039 {
2040   vhost_user_intf_t *vui = NULL;
2041   u32 sw_if_idx = ~0;
2042   int sockfd = -1;
2043   int rv = 0;
2044
2045   if (is_server)
2046     {
2047       if ((rv = vhost_user_init_server_sock (sock_filename, &sockfd)) != 0)
2048         {
2049           return rv;
2050         }
2051     }
2052
2053   vui = vhost_user_vui_new ();
2054   ASSERT (vui != NULL);
2055
2056   vhost_user_create_ethernet (vnm, vm, vui, hwaddr);
2057   vhost_user_vui_init (vnm, vui, sockfd, sock_filename, is_server,
2058                        feature_mask, &sw_if_idx);
2059
2060   if (renumber)
2061     {
2062       vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
2063     }
2064
2065   vhost_user_vui_register (vm, vui);
2066
2067   if (sw_if_index)
2068     *sw_if_index = sw_if_idx;
2069
2070   return rv;
2071 }
2072
2073 int
2074 vhost_user_modify_if (vnet_main_t * vnm, vlib_main_t * vm,
2075                       const char *sock_filename,
2076                       u8 is_server,
2077                       u32 sw_if_index,
2078                       u64 feature_mask, u8 renumber, u32 custom_dev_instance)
2079 {
2080   vhost_user_main_t *vum = &vhost_user_main;
2081   vhost_user_intf_t *vui = NULL;
2082   u32 sw_if_idx = ~0;
2083   int sockfd = -1;
2084   int rv = 0;
2085   uword *p = NULL;
2086
2087   p = hash_get (vum->vhost_user_interface_index_by_sw_if_index, sw_if_index);
2088   if (p == 0)
2089     {
2090       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
2091     }
2092   else
2093     {
2094       vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
2095     }
2096
2097   // interface is inactive
2098   vui->active = 0;
2099   // disconnect interface sockets
2100   vhost_user_if_disconnect (vui);
2101
2102   if (is_server)
2103     {
2104       if ((rv = vhost_user_init_server_sock (sock_filename, &sockfd)) != 0)
2105         {
2106           return rv;
2107         }
2108     }
2109
2110   vhost_user_vui_init (vnm, vui, sockfd, sock_filename, is_server,
2111                        feature_mask, &sw_if_idx);
2112
2113   if (renumber)
2114     {
2115       vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
2116     }
2117
2118   vhost_user_vui_register (vm, vui);
2119
2120   return rv;
2121 }
2122
2123 clib_error_t *
2124 vhost_user_connect_command_fn (vlib_main_t * vm,
2125                                unformat_input_t * input,
2126                                vlib_cli_command_t * cmd)
2127 {
2128   unformat_input_t _line_input, *line_input = &_line_input;
2129   u8 *sock_filename = NULL;
2130   u32 sw_if_index;
2131   u8 is_server = 0;
2132   u64 feature_mask = (u64) ~ 0;
2133   u8 renumber = 0;
2134   u32 custom_dev_instance = ~0;
2135   u8 hwaddr[6];
2136   u8 *hw = NULL;
2137
2138   /* Get a line of input. */
2139   if (!unformat_user (input, unformat_line_input, line_input))
2140     return 0;
2141
2142   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2143     {
2144       if (unformat (line_input, "socket %s", &sock_filename))
2145         ;
2146       else if (unformat (line_input, "server"))
2147         is_server = 1;
2148       else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
2149         ;
2150       else
2151         if (unformat
2152             (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
2153         hw = hwaddr;
2154       else if (unformat (line_input, "renumber %d", &custom_dev_instance))
2155         {
2156           renumber = 1;
2157         }
2158       else
2159         return clib_error_return (0, "unknown input `%U'",
2160                                   format_unformat_error, input);
2161     }
2162   unformat_free (line_input);
2163
2164   vnet_main_t *vnm = vnet_get_main ();
2165
2166   int rv;
2167   if ((rv = vhost_user_create_if (vnm, vm, (char *) sock_filename,
2168                                   is_server, &sw_if_index, feature_mask,
2169                                   renumber, custom_dev_instance, hw)))
2170     {
2171       vec_free (sock_filename);
2172       return clib_error_return (0, "vhost_user_create_if returned %d", rv);
2173     }
2174
2175   vec_free (sock_filename);
2176   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
2177                    sw_if_index);
2178   return 0;
2179 }
2180
2181 clib_error_t *
2182 vhost_user_delete_command_fn (vlib_main_t * vm,
2183                               unformat_input_t * input,
2184                               vlib_cli_command_t * cmd)
2185 {
2186   unformat_input_t _line_input, *line_input = &_line_input;
2187   u32 sw_if_index = ~0;
2188
2189   /* Get a line of input. */
2190   if (!unformat_user (input, unformat_line_input, line_input))
2191     return 0;
2192
2193   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2194     {
2195       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
2196         ;
2197       else
2198         return clib_error_return (0, "unknown input `%U'",
2199                                   format_unformat_error, input);
2200     }
2201   unformat_free (line_input);
2202
2203   vnet_main_t *vnm = vnet_get_main ();
2204
2205   vhost_user_delete_if (vnm, vm, sw_if_index);
2206
2207   return 0;
2208 }
2209
2210 int
2211 vhost_user_dump_ifs (vnet_main_t * vnm, vlib_main_t * vm,
2212                      vhost_user_intf_details_t ** out_vuids)
2213 {
2214   int rv = 0;
2215   vhost_user_main_t *vum = &vhost_user_main;
2216   vhost_user_intf_t *vui;
2217   vhost_user_intf_details_t *r_vuids = NULL;
2218   vhost_user_intf_details_t *vuid = NULL;
2219   u32 *hw_if_indices = 0;
2220   vnet_hw_interface_t *hi;
2221   u8 *s = NULL;
2222   int i;
2223
2224   if (!out_vuids)
2225     return -1;
2226
2227   vec_foreach (vui, vum->vhost_user_interfaces)
2228   {
2229     if (vui->active)
2230       vec_add1 (hw_if_indices, vui->hw_if_index);
2231   }
2232
2233   for (i = 0; i < vec_len (hw_if_indices); i++)
2234     {
2235       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
2236       vui = vec_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
2237
2238       vec_add2 (r_vuids, vuid, 1);
2239       vuid->sw_if_index = vui->sw_if_index;
2240       vuid->virtio_net_hdr_sz = vui->virtio_net_hdr_sz;
2241       vuid->features = vui->features;
2242       vuid->is_server = vui->sock_is_server;
2243       vuid->num_regions = vui->nregions;
2244       vuid->sock_errno = vui->sock_errno;
2245       strncpy ((char *) vuid->sock_filename, (char *) vui->sock_filename,
2246                ARRAY_LEN (vuid->sock_filename) - 1);
2247
2248       s = format (s, "%v%c", hi->name, 0);
2249
2250       strncpy ((char *) vuid->if_name, (char *) s,
2251                ARRAY_LEN (vuid->if_name) - 1);
2252       _vec_len (s) = 0;
2253     }
2254
2255   vec_free (s);
2256   vec_free (hw_if_indices);
2257
2258   *out_vuids = r_vuids;
2259
2260   return rv;
2261 }
2262
2263 clib_error_t *
2264 show_vhost_user_command_fn (vlib_main_t * vm,
2265                             unformat_input_t * input,
2266                             vlib_cli_command_t * cmd)
2267 {
2268   clib_error_t *error = 0;
2269   vnet_main_t *vnm = vnet_get_main ();
2270   vhost_user_main_t *vum = &vhost_user_main;
2271   vhost_user_intf_t *vui;
2272   u32 hw_if_index, *hw_if_indices = 0;
2273   vnet_hw_interface_t *hi;
2274   int i, j, q;
2275   int show_descr = 0;
2276   struct feat_struct
2277   {
2278     u8 bit;
2279     char *str;
2280   };
2281   struct feat_struct *feat_entry;
2282
2283   static struct feat_struct feat_array[] = {
2284 #define _(s,b) { .str = #s, .bit = b, },
2285     foreach_virtio_net_feature
2286 #undef _
2287     {.str = NULL}
2288   };
2289
2290   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2291     {
2292       if (unformat
2293           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
2294         {
2295           vec_add1 (hw_if_indices, hw_if_index);
2296           vlib_cli_output (vm, "add %d", hw_if_index);
2297         }
2298       else if (unformat (input, "descriptors") || unformat (input, "desc"))
2299         show_descr = 1;
2300       else
2301         {
2302           error = clib_error_return (0, "unknown input `%U'",
2303                                      format_unformat_error, input);
2304           goto done;
2305         }
2306     }
2307   if (vec_len (hw_if_indices) == 0)
2308     {
2309       vec_foreach (vui, vum->vhost_user_interfaces)
2310       {
2311         if (vui->active)
2312           vec_add1 (hw_if_indices, vui->hw_if_index);
2313       }
2314     }
2315   vlib_cli_output (vm, "Virtio vhost-user interfaces");
2316   vlib_cli_output (vm, "Global:\n  coalesce frames %d time %e\n\n",
2317                    vum->coalesce_frames, vum->coalesce_time);
2318
2319   for (i = 0; i < vec_len (hw_if_indices); i++)
2320     {
2321       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
2322       vui = vec_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
2323       vlib_cli_output (vm, "Interface: %s (ifindex %d)",
2324                        hi->name, hw_if_indices[i]);
2325
2326       vlib_cli_output (vm, "virtio_net_hdr_sz %d\n features (0x%llx): \n",
2327                        vui->virtio_net_hdr_sz, vui->features);
2328
2329       feat_entry = (struct feat_struct *) &feat_array;
2330       while (feat_entry->str)
2331         {
2332           if (vui->features & (1 << feat_entry->bit))
2333             vlib_cli_output (vm, "   %s (%d)", feat_entry->str,
2334                              feat_entry->bit);
2335           feat_entry++;
2336         }
2337
2338       vlib_cli_output (vm, "\n");
2339
2340
2341       vlib_cli_output (vm, " socket filename %s type %s errno \"%s\"\n\n",
2342                        vui->sock_filename,
2343                        vui->sock_is_server ? "server" : "client",
2344                        strerror (vui->sock_errno));
2345
2346       vlib_cli_output (vm, " Memory regions (total %d)\n", vui->nregions);
2347
2348       if (vui->nregions)
2349         {
2350           vlib_cli_output (vm,
2351                            " region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr\n");
2352           vlib_cli_output (vm,
2353                            " ====== ===== ================== ================== ================== ================== ==================\n");
2354         }
2355       for (j = 0; j < vui->nregions; j++)
2356         {
2357           vlib_cli_output (vm,
2358                            "  %d     %-5d 0x%016lx 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
2359                            j, vui->region_mmap_fd[j],
2360                            vui->regions[j].guest_phys_addr,
2361                            vui->regions[j].memory_size,
2362                            vui->regions[j].userspace_addr,
2363                            vui->regions[j].mmap_offset,
2364                            pointer_to_uword (vui->region_mmap_addr[j]));
2365         }
2366       for (q = 0; q < vui->num_vrings; q++)
2367         {
2368           vlib_cli_output (vm, "\n Virtqueue %d\n", q);
2369
2370           vlib_cli_output (vm,
2371                            "  qsz %d last_avail_idx %d last_used_idx %d\n",
2372                            vui->vrings[q].qsz, vui->vrings[q].last_avail_idx,
2373                            vui->vrings[q].last_used_idx);
2374
2375           if (vui->vrings[q].avail && vui->vrings[q].used)
2376             vlib_cli_output (vm,
2377                              "  avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
2378                              vui->vrings[q].avail->flags,
2379                              vui->vrings[q].avail->idx,
2380                              vui->vrings[q].used->flags,
2381                              vui->vrings[q].used->idx);
2382
2383           vlib_cli_output (vm, "  kickfd %d callfd %d errfd %d\n",
2384                            vui->vrings[q].kickfd,
2385                            vui->vrings[q].callfd, vui->vrings[q].errfd);
2386
2387           if (show_descr)
2388             {
2389               vlib_cli_output (vm, "\n  descriptor table:\n");
2390               vlib_cli_output (vm,
2391                                "   id          addr         len  flags  next      user_addr\n");
2392               vlib_cli_output (vm,
2393                                "  ===== ================== ===== ====== ===== ==================\n");
2394               for (j = 0; j < vui->vrings[q].qsz; j++)
2395                 {
2396                   u32 mem_hint = 0;
2397                   vlib_cli_output (vm,
2398                                    "  %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
2399                                    j, vui->vrings[q].desc[j].addr,
2400                                    vui->vrings[q].desc[j].len,
2401                                    vui->vrings[q].desc[j].flags,
2402                                    vui->vrings[q].desc[j].next,
2403                                    pointer_to_uword (map_guest_mem
2404                                                      (vui,
2405                                                       vui->vrings[q].desc[j].
2406                                                       addr, &mem_hint)));
2407                 }
2408             }
2409         }
2410       vlib_cli_output (vm, "\n");
2411     }
2412 done:
2413   vec_free (hw_if_indices);
2414   return error;
2415 }
2416
2417 /*
2418  * CLI functions
2419  */
2420
2421 #if DPDK == 0
2422 /* *INDENT-OFF* */
2423 VLIB_CLI_COMMAND (vhost_user_connect_command, static) = {
2424     .path = "create vhost-user",
2425     .short_help = "create vhost-user socket <socket-filename> [server] [feature-mask <hex>] [renumber <dev_instance>]",
2426     .function = vhost_user_connect_command_fn,
2427 };
2428
2429 VLIB_CLI_COMMAND (vhost_user_delete_command, static) = {
2430     .path = "delete vhost-user",
2431     .short_help = "delete vhost-user sw_if_index <nn>",
2432     .function = vhost_user_delete_command_fn,
2433 };
2434
2435 VLIB_CLI_COMMAND (show_vhost_user_command, static) = {
2436     .path = "show vhost-user",
2437     .short_help = "show vhost-user interface",
2438     .function = show_vhost_user_command_fn,
2439 };
2440 /* *INDENT-ON* */
2441 #endif
2442
2443 static clib_error_t *
2444 vhost_user_config (vlib_main_t * vm, unformat_input_t * input)
2445 {
2446   vhost_user_main_t *vum = &vhost_user_main;
2447
2448   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2449     {
2450       if (unformat (input, "coalesce-frames %d", &vum->coalesce_frames))
2451         ;
2452       else if (unformat (input, "coalesce-time %f", &vum->coalesce_time))
2453         ;
2454       else if (unformat (input, "dont-dump-memory"))
2455         vum->dont_dump_vhost_user_memory = 1;
2456       else
2457         return clib_error_return (0, "unknown input `%U'",
2458                                   format_unformat_error, input);
2459     }
2460
2461   return 0;
2462 }
2463
2464 /* vhost-user { ... } configuration. */
2465 VLIB_CONFIG_FUNCTION (vhost_user_config, "vhost-user");
2466
2467 void
2468 vhost_user_unmap_all (void)
2469 {
2470   vhost_user_main_t *vum = &vhost_user_main;
2471   vhost_user_intf_t *vui;
2472
2473   if (vum->dont_dump_vhost_user_memory)
2474     {
2475       vec_foreach (vui, vum->vhost_user_interfaces)
2476       {
2477         unmap_all_mem_regions (vui);
2478       }
2479     }
2480 }
2481
2482 /*
2483  * fd.io coding-style-patch-verification: ON
2484  *
2485  * Local Variables:
2486  * eval: (c-set-style "gnu")
2487  * End:
2488  */