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