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