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