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