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