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