51b0c409d2ae9a8b73fd3fe59d889087d4b40e50
[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 + offsetof(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   dpdk_main_t *dm = &dpdk_main;
1214   vhost_user_intf_t *vui;
1215   uword n_rx_packets = 0;
1216   u32 cpu_index = os_get_cpu_number ();
1217   int i;
1218
1219   for (i = 0; i < vec_len (vum->vhost_user_interfaces); i++)
1220     {
1221       vui = vec_elt_at_index (vum->vhost_user_interfaces, i);
1222       if (vui->is_up &&
1223           (i % dm->input_cpu_count) ==
1224           (cpu_index - dm->input_cpu_first_index))
1225         n_rx_packets += vhost_user_if_input (vm, vum, vui, node);
1226     }
1227   return n_rx_packets;
1228 }
1229
1230 /* *INDENT-OFF* */
1231 VLIB_REGISTER_NODE (vhost_user_input_node) = {
1232   .function = vhost_user_input,
1233   .type = VLIB_NODE_TYPE_INPUT,
1234   .name = "vhost-user-input",
1235
1236   /* Will be enabled if/when hardware is detected. */
1237   .state = VLIB_NODE_STATE_DISABLED,
1238
1239   .format_buffer = format_ethernet_header_with_length,
1240   .format_trace = format_vhost_user_input_trace,
1241
1242   .n_errors = VHOST_USER_INPUT_FUNC_N_ERROR,
1243   .error_strings = vhost_user_input_func_error_strings,
1244
1245   .n_next_nodes = VHOST_USER_RX_N_NEXT,
1246   .next_nodes = {
1247     [VHOST_USER_RX_NEXT_DROP] = "error-drop",
1248     [VHOST_USER_RX_NEXT_ETHERNET_INPUT] = "ethernet-input",
1249   },
1250 };
1251
1252 VLIB_NODE_FUNCTION_MULTIARCH (vhost_user_input_node, vhost_user_input)
1253 /* *INDENT-ON* */
1254
1255 static uword
1256 vhost_user_intfc_tx (vlib_main_t * vm,
1257                      vlib_node_runtime_t * node, vlib_frame_t * frame)
1258 {
1259   u32 *buffers = vlib_frame_args (frame);
1260   u32 n_left = 0;
1261   u16 used_index;
1262   vhost_user_main_t *vum = &vhost_user_main;
1263   uword n_packets = 0;
1264   vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
1265   vhost_user_intf_t *vui =
1266     vec_elt_at_index (vum->vhost_user_interfaces, rd->dev_instance);
1267   vhost_user_vring_t *rxvq = &vui->vrings[VHOST_NET_VRING_IDX_RX];
1268   u16 qsz_mask;
1269   u8 error = VHOST_USER_TX_FUNC_ERROR_NONE;
1270
1271   if (PREDICT_FALSE (!vui->is_up))
1272     goto done2;
1273
1274   if (PREDICT_FALSE
1275       (!rxvq->desc || !rxvq->avail || vui->sock_errno != 0 || !rxvq->enabled))
1276     {
1277       error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
1278       goto done2;
1279     }
1280
1281   if (PREDICT_FALSE (vui->lockp != 0))
1282     {
1283       while (__sync_lock_test_and_set (vui->lockp, 1))
1284         ;
1285     }
1286
1287   /* only bit 0 of avail.flags is used so we don't want to deal with this
1288      interface if any other bit is set */
1289   if (PREDICT_FALSE (rxvq->avail->flags & 0xFFFE))
1290     {
1291       error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
1292       goto done2;
1293     }
1294
1295   if (PREDICT_FALSE ((rxvq->avail->idx == rxvq->last_avail_idx)))
1296     {
1297       error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1298       goto done2;
1299     }
1300
1301   n_left = n_packets = frame->n_vectors;
1302   used_index = rxvq->used->idx;
1303   qsz_mask = rxvq->qsz - 1;     /* qsz is always power of 2 */
1304
1305   while (n_left > 0)
1306     {
1307       vlib_buffer_t *b0, *current_b0;
1308       u16 desc_chain_head, desc_current, desc_len;
1309       void *buffer_addr;
1310       uword offset;
1311
1312       if (n_left >= 2)
1313         vlib_prefetch_buffer_with_index (vm, buffers[1], LOAD);
1314
1315       b0 = vlib_get_buffer (vm, buffers[0]);
1316       buffers++;
1317       n_left--;
1318
1319       if (PREDICT_FALSE (rxvq->last_avail_idx == rxvq->avail->idx))
1320         {
1321           error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1322           goto done;
1323         }
1324
1325       desc_current = desc_chain_head =
1326         rxvq->avail->ring[rxvq->last_avail_idx & qsz_mask];
1327       offset = vui->virtio_net_hdr_sz;
1328       desc_len = offset;
1329       if (PREDICT_FALSE
1330           (!(buffer_addr =
1331              map_guest_mem (vui, rxvq->desc[desc_current].addr))))
1332         {
1333           error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1334           goto done;
1335         }
1336       CLIB_PREFETCH (buffer_addr, clib_min (rxvq->desc[desc_current].len,
1337                                             4 * CLIB_CACHE_LINE_BYTES),
1338                      STORE);
1339
1340       virtio_net_hdr_mrg_rxbuf_t *hdr =
1341         (virtio_net_hdr_mrg_rxbuf_t *) buffer_addr;
1342       hdr->hdr.flags = 0;
1343       hdr->hdr.gso_type = 0;
1344
1345       vhost_user_log_dirty_pages (vui, rxvq->desc[desc_current].addr,
1346                                   vui->virtio_net_hdr_sz);
1347
1348       if (vui->virtio_net_hdr_sz == 12)
1349         hdr->num_buffers = 1;
1350
1351       u16 bytes_left = b0->current_length;
1352       buffer_addr += offset;
1353       current_b0 = b0;
1354
1355       //FIXME: This was in the code but I don't think it is valid
1356       /*if (PREDICT_FALSE(!vui->is_any_layout && (rxvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT))) {
1357          rxvq->desc[desc_current].len = vui->virtio_net_hdr_sz;
1358          } */
1359
1360       while (1)
1361         {
1362           if (!bytes_left)
1363             {                   //Get new input
1364               if (current_b0->flags & VLIB_BUFFER_NEXT_PRESENT)
1365                 {
1366                   current_b0 = vlib_get_buffer (vm, current_b0->next_buffer);
1367                   bytes_left = current_b0->current_length;
1368                 }
1369               else
1370                 {
1371                   //End of packet
1372                   break;
1373                 }
1374             }
1375
1376           if (rxvq->desc[desc_current].len <= offset)
1377             {                   //Get new output
1378               if (rxvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT)
1379                 {
1380                   offset = 0;
1381                   desc_current = rxvq->desc[desc_current].next;
1382                   if (PREDICT_FALSE
1383                       (!(buffer_addr =
1384                          map_guest_mem (vui, rxvq->desc[desc_current].addr))))
1385                     {
1386                       used_index -= hdr->num_buffers - 1;
1387                       rxvq->last_avail_idx -= hdr->num_buffers - 1;
1388                       error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1389                       goto done;
1390                     }
1391                 }
1392               else if (vui->virtio_net_hdr_sz == 12)
1393                 {               //MRG is available
1394
1395                   //Move from available to used buffer
1396                   rxvq->used->ring[used_index & qsz_mask].id =
1397                     desc_chain_head;
1398                   rxvq->used->ring[used_index & qsz_mask].len = desc_len;
1399                   vhost_user_log_dirty_ring (vui, rxvq,
1400                                              ring[used_index & qsz_mask]);
1401                   rxvq->last_avail_idx++;
1402                   used_index++;
1403                   hdr->num_buffers++;
1404
1405                   if (PREDICT_FALSE
1406                       (rxvq->last_avail_idx == rxvq->avail->idx))
1407                     {
1408                       //Dequeue queued descriptors for this packet
1409                       used_index -= hdr->num_buffers - 1;
1410                       rxvq->last_avail_idx -= hdr->num_buffers - 1;
1411                       error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1412                       goto done;
1413                     }
1414
1415                   //Look at next one
1416                   desc_chain_head =
1417                     rxvq->avail->ring[rxvq->last_avail_idx & qsz_mask];
1418                   desc_current = desc_chain_head;
1419                   desc_len = 0;
1420                   offset = 0;
1421                   if (PREDICT_FALSE
1422                       (!(buffer_addr =
1423                          map_guest_mem (vui, rxvq->desc[desc_current].addr))))
1424                     {
1425                       //Dequeue queued descriptors for this packet
1426                       used_index -= hdr->num_buffers - 1;
1427                       rxvq->last_avail_idx -= hdr->num_buffers - 1;
1428                       error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1429                       goto done;
1430                     }
1431                 }
1432               else
1433                 {
1434                   error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1435                   goto done;
1436                 }
1437             }
1438
1439           u16 bytes_to_copy =
1440             bytes_left >
1441             (rxvq->desc[desc_current].len -
1442              offset) ? (rxvq->desc[desc_current].len - offset) : bytes_left;
1443           clib_memcpy (buffer_addr,
1444                        vlib_buffer_get_current (current_b0) +
1445                        current_b0->current_length - bytes_left,
1446                        bytes_to_copy);
1447
1448           vhost_user_log_dirty_pages (vui,
1449                                       rxvq->desc[desc_current].addr + offset,
1450                                       bytes_to_copy);
1451           bytes_left -= bytes_to_copy;
1452           offset += bytes_to_copy;
1453           buffer_addr += bytes_to_copy;
1454           desc_len += bytes_to_copy;
1455         }
1456
1457       //Move from available to used ring
1458       rxvq->used->ring[used_index & qsz_mask].id = desc_chain_head;
1459       rxvq->used->ring[used_index & qsz_mask].len = desc_len;
1460       vhost_user_log_dirty_ring (vui, rxvq, ring[used_index & qsz_mask]);
1461
1462       rxvq->last_avail_idx++;
1463       used_index++;
1464     }
1465
1466 done:
1467   CLIB_MEMORY_BARRIER ();
1468   rxvq->used->idx = used_index;
1469   vhost_user_log_dirty_ring (vui, rxvq, idx);
1470
1471   /* interrupt (call) handling */
1472   if ((rxvq->callfd > 0) && !(rxvq->avail->flags & 1))
1473     {
1474       rxvq->n_since_last_int += n_packets - n_left;
1475
1476       if (rxvq->n_since_last_int > vum->coalesce_frames)
1477         vhost_user_send_call (vm, rxvq);
1478     }
1479
1480 done2:
1481
1482   if (PREDICT_FALSE (vui->lockp != 0))
1483     *vui->lockp = 0;
1484
1485   if (PREDICT_FALSE (n_left && error != VHOST_USER_TX_FUNC_ERROR_NONE))
1486     {
1487       vlib_error_count (vm, node->node_index, error, n_left);
1488       vlib_increment_simple_counter
1489         (vnet_main.interface_main.sw_if_counters
1490          + VNET_INTERFACE_COUNTER_DROP,
1491          os_get_cpu_number (), vui->sw_if_index, n_left);
1492     }
1493
1494   vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
1495   return frame->n_vectors;
1496 }
1497
1498 static clib_error_t *
1499 vhost_user_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
1500                                     u32 flags)
1501 {
1502   vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
1503   uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
1504   vhost_user_main_t *vum = &vhost_user_main;
1505   vhost_user_intf_t *vui =
1506     vec_elt_at_index (vum->vhost_user_interfaces, hif->dev_instance);
1507
1508   vui->admin_up = is_up;
1509
1510   if (is_up)
1511     vnet_hw_interface_set_flags (vnm, vui->hw_if_index,
1512                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
1513
1514   return /* no error */ 0;
1515 }
1516
1517 /* *INDENT-OFF* */
1518 VNET_DEVICE_CLASS (vhost_user_dev_class,static) = {
1519   .name = "vhost-user",
1520   .tx_function = vhost_user_intfc_tx,
1521   .tx_function_n_errors = VHOST_USER_TX_FUNC_N_ERROR,
1522   .tx_function_error_strings = vhost_user_tx_func_error_strings,
1523   .format_device_name = format_vhost_user_interface_name,
1524   .name_renumber = vhost_user_name_renumber,
1525   .admin_up_down_function = vhost_user_interface_admin_up_down,
1526   .no_flatten_output_chains = 1,
1527 };
1528
1529 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (vhost_user_dev_class,
1530                                    vhost_user_intfc_tx)
1531 /* *INDENT-ON* */
1532
1533 static uword
1534 vhost_user_process (vlib_main_t * vm,
1535                     vlib_node_runtime_t * rt, vlib_frame_t * f)
1536 {
1537   vhost_user_main_t *vum = &vhost_user_main;
1538   vhost_user_intf_t *vui;
1539   struct sockaddr_un sun;
1540   int sockfd;
1541   unix_file_t template = { 0 };
1542   f64 timeout = 3153600000.0 /* 100 years */ ;
1543   uword *event_data = 0;
1544
1545   sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
1546   sun.sun_family = AF_UNIX;
1547   template.read_function = vhost_user_socket_read;
1548   template.error_function = vhost_user_socket_error;
1549
1550
1551   if (sockfd < 0)
1552     return 0;
1553
1554   while (1)
1555     {
1556       vlib_process_wait_for_event_or_clock (vm, timeout);
1557       vlib_process_get_events (vm, &event_data);
1558       vec_reset_length (event_data);
1559
1560       timeout = 3.0;
1561
1562       vec_foreach (vui, vum->vhost_user_interfaces)
1563       {
1564
1565         if (vui->sock_is_server || !vui->active)
1566           continue;
1567
1568         if (vui->unix_fd == -1)
1569           {
1570             /* try to connect */
1571
1572             strncpy (sun.sun_path, (char *) vui->sock_filename,
1573                      sizeof (sun.sun_path) - 1);
1574
1575             if (connect
1576                 (sockfd, (struct sockaddr *) &sun,
1577                  sizeof (struct sockaddr_un)) == 0)
1578               {
1579                 vui->sock_errno = 0;
1580                 vui->unix_fd = sockfd;
1581                 template.file_descriptor = sockfd;
1582                 vui->unix_file_index = unix_file_add (&unix_main, &template);
1583                 hash_set (vum->vhost_user_interface_index_by_sock_fd, sockfd,
1584                           vui - vum->vhost_user_interfaces);
1585
1586                 sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
1587                 if (sockfd < 0)
1588                   return 0;
1589               }
1590             else
1591               {
1592                 vui->sock_errno = errno;
1593               }
1594           }
1595         else
1596           {
1597             /* check if socket is alive */
1598             int error = 0;
1599             socklen_t len = sizeof (error);
1600             int retval =
1601               getsockopt (vui->unix_fd, SOL_SOCKET, SO_ERROR, &error, &len);
1602
1603             if (retval)
1604               vhost_user_if_disconnect (vui);
1605           }
1606       }
1607     }
1608   return 0;
1609 }
1610
1611 /* *INDENT-OFF* */
1612 VLIB_REGISTER_NODE (vhost_user_process_node,static) = {
1613     .function = vhost_user_process,
1614     .type = VLIB_NODE_TYPE_PROCESS,
1615     .name = "vhost-user-process",
1616 };
1617 /* *INDENT-ON* */
1618
1619 int
1620 vhost_user_delete_if (vnet_main_t * vnm, vlib_main_t * vm, u32 sw_if_index)
1621 {
1622   vhost_user_main_t *vum = &vhost_user_main;
1623   vhost_user_intf_t *vui;
1624   uword *p = NULL;
1625   int rv = 0;
1626
1627   p = hash_get (vum->vhost_user_interface_index_by_sw_if_index, sw_if_index);
1628   if (p == 0)
1629     {
1630       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1631     }
1632   else
1633     {
1634       vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
1635     }
1636
1637   // interface is inactive
1638   vui->active = 0;
1639   // disconnect interface sockets
1640   vhost_user_if_disconnect (vui);
1641   // add to inactive interface list
1642   vec_add1 (vum->vhost_user_inactive_interfaces_index, p[0]);
1643
1644   // reset renumbered iface
1645   if (p[0] < vec_len (vum->show_dev_instance_by_real_dev_instance))
1646     vum->show_dev_instance_by_real_dev_instance[p[0]] = ~0;
1647
1648   ethernet_delete_interface (vnm, vui->hw_if_index);
1649   DBG_SOCK ("deleted (deactivated) vhost-user interface instance %d", p[0]);
1650
1651   return rv;
1652 }
1653
1654 // init server socket on specified sock_filename
1655 static int
1656 vhost_user_init_server_sock (const char *sock_filename, int *sockfd)
1657 {
1658   int rv = 0;
1659   struct sockaddr_un un = { };
1660   int fd;
1661   /* create listening socket */
1662   fd = socket (AF_UNIX, SOCK_STREAM, 0);
1663
1664   if (fd < 0)
1665     {
1666       return VNET_API_ERROR_SYSCALL_ERROR_1;
1667     }
1668
1669   un.sun_family = AF_UNIX;
1670   strncpy ((char *) un.sun_path, (char *) sock_filename,
1671            sizeof (un.sun_path) - 1);
1672
1673   /* remove if exists */
1674   unlink ((char *) sock_filename);
1675
1676   if (bind (fd, (struct sockaddr *) &un, sizeof (un)) == -1)
1677     {
1678       rv = VNET_API_ERROR_SYSCALL_ERROR_2;
1679       goto error;
1680     }
1681
1682   if (listen (fd, 1) == -1)
1683     {
1684       rv = VNET_API_ERROR_SYSCALL_ERROR_3;
1685       goto error;
1686     }
1687
1688   unix_file_t template = { 0 };
1689   template.read_function = vhost_user_socksvr_accept_ready;
1690   template.file_descriptor = fd;
1691   unix_file_add (&unix_main, &template);
1692   *sockfd = fd;
1693   return rv;
1694
1695 error:
1696   close (fd);
1697   return rv;
1698 }
1699
1700 // get new vhost_user_intf_t from inactive interfaces or create new one
1701 static vhost_user_intf_t *
1702 vhost_user_vui_new ()
1703 {
1704   vhost_user_main_t *vum = &vhost_user_main;
1705   vhost_user_intf_t *vui = NULL;
1706   int inactive_cnt = vec_len (vum->vhost_user_inactive_interfaces_index);
1707   // if there are any inactive ifaces
1708   if (inactive_cnt > 0)
1709     {
1710       // take last
1711       u32 vui_idx =
1712         vum->vhost_user_inactive_interfaces_index[inactive_cnt - 1];
1713       if (vec_len (vum->vhost_user_interfaces) > vui_idx)
1714         {
1715           vui = vec_elt_at_index (vum->vhost_user_interfaces, vui_idx);
1716           DBG_SOCK ("reusing inactive vhost-user interface index %d",
1717                     vui_idx);
1718         }
1719       // "remove" from inactive list
1720       _vec_len (vum->vhost_user_inactive_interfaces_index) -= 1;
1721     }
1722
1723   // vui was not retrieved from inactive ifaces - create new
1724   if (!vui)
1725     vec_add2 (vum->vhost_user_interfaces, vui, 1);
1726   return vui;
1727 }
1728
1729 // create ethernet interface for vhost user intf
1730 static void
1731 vhost_user_create_ethernet (vnet_main_t * vnm, vlib_main_t * vm,
1732                             vhost_user_intf_t * vui, u8 * hwaddress)
1733 {
1734   vhost_user_main_t *vum = &vhost_user_main;
1735   u8 hwaddr[6];
1736   clib_error_t *error;
1737
1738   /* create hw and sw interface */
1739   if (hwaddress)
1740     {
1741       clib_memcpy (hwaddr, hwaddress, 6);
1742     }
1743   else
1744     {
1745       f64 now = vlib_time_now (vm);
1746       u32 rnd;
1747       rnd = (u32) (now * 1e6);
1748       rnd = random_u32 (&rnd);
1749
1750       clib_memcpy (hwaddr + 2, &rnd, sizeof (rnd));
1751       hwaddr[0] = 2;
1752       hwaddr[1] = 0xfe;
1753     }
1754
1755   error = ethernet_register_interface
1756     (vnm,
1757      vhost_user_dev_class.index,
1758      vui - vum->vhost_user_interfaces /* device instance */ ,
1759      hwaddr /* ethernet address */ ,
1760      &vui->hw_if_index, 0 /* flag change */ );
1761   if (error)
1762     clib_error_report (error);
1763
1764   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, vui->hw_if_index);
1765   hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = 9000;
1766 }
1767
1768 // initialize vui with specified attributes
1769 static void
1770 vhost_user_vui_init (vnet_main_t * vnm,
1771                      vhost_user_intf_t * vui, int sockfd,
1772                      const char *sock_filename,
1773                      u8 is_server, u64 feature_mask, u32 * sw_if_index)
1774 {
1775   vnet_sw_interface_t *sw;
1776   sw = vnet_get_hw_sw_interface (vnm, vui->hw_if_index);
1777   vlib_thread_main_t *tm = vlib_get_thread_main ();
1778   int q;
1779
1780   vui->unix_fd = sockfd;
1781   vui->sw_if_index = sw->sw_if_index;
1782   vui->num_vrings = 2;
1783   vui->sock_is_server = is_server;
1784   strncpy (vui->sock_filename, sock_filename,
1785            ARRAY_LEN (vui->sock_filename) - 1);
1786   vui->sock_errno = 0;
1787   vui->is_up = 0;
1788   vui->feature_mask = feature_mask;
1789   vui->active = 1;
1790   vui->unix_file_index = ~0;
1791   vui->log_base_addr = 0;
1792
1793   for (q = 0; q < 2; q++)
1794     {
1795       vui->vrings[q].enabled = 0;
1796     }
1797
1798   vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
1799
1800   if (sw_if_index)
1801     *sw_if_index = vui->sw_if_index;
1802
1803   if (tm->n_vlib_mains > 1)
1804     {
1805       vui->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
1806                                            CLIB_CACHE_LINE_BYTES);
1807       memset ((void *) vui->lockp, 0, CLIB_CACHE_LINE_BYTES);
1808     }
1809 }
1810
1811 // register vui and start polling on it
1812 static void
1813 vhost_user_vui_register (vlib_main_t * vm, vhost_user_intf_t * vui)
1814 {
1815   vhost_user_main_t *vum = &vhost_user_main;
1816   dpdk_main_t *dm = &dpdk_main;
1817   int cpu_index;
1818   vlib_thread_main_t *tm = vlib_get_thread_main ();
1819
1820   hash_set (vum->vhost_user_interface_index_by_listener_fd, vui->unix_fd,
1821             vui - vum->vhost_user_interfaces);
1822   hash_set (vum->vhost_user_interface_index_by_sw_if_index, vui->sw_if_index,
1823             vui - vum->vhost_user_interfaces);
1824
1825   /* start polling */
1826   cpu_index = dm->input_cpu_first_index +
1827     (vui - vum->vhost_user_interfaces) % dm->input_cpu_count;
1828
1829   if (tm->n_vlib_mains == 1)
1830     vlib_node_set_state (vm, vhost_user_input_node.index,
1831                          VLIB_NODE_STATE_POLLING);
1832   else
1833     vlib_node_set_state (vlib_mains[cpu_index], vhost_user_input_node.index,
1834                          VLIB_NODE_STATE_POLLING);
1835
1836   /* tell process to start polling for sockets */
1837   vlib_process_signal_event (vm, vhost_user_process_node.index, 0, 0);
1838 }
1839
1840 int
1841 vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
1842                       const char *sock_filename,
1843                       u8 is_server,
1844                       u32 * sw_if_index,
1845                       u64 feature_mask,
1846                       u8 renumber, u32 custom_dev_instance, u8 * hwaddr)
1847 {
1848   vhost_user_intf_t *vui = NULL;
1849   u32 sw_if_idx = ~0;
1850   int sockfd = -1;
1851   int rv = 0;
1852
1853   if (is_server)
1854     {
1855       if ((rv = vhost_user_init_server_sock (sock_filename, &sockfd)) != 0)
1856         {
1857           return rv;
1858         }
1859     }
1860
1861   vui = vhost_user_vui_new ();
1862   ASSERT (vui != NULL);
1863
1864   vhost_user_create_ethernet (vnm, vm, vui, hwaddr);
1865   vhost_user_vui_init (vnm, vui, sockfd, sock_filename, is_server,
1866                        feature_mask, &sw_if_idx);
1867
1868   if (renumber)
1869     {
1870       vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
1871     }
1872
1873   vhost_user_vui_register (vm, vui);
1874
1875   if (sw_if_index)
1876     *sw_if_index = sw_if_idx;
1877
1878   return rv;
1879 }
1880
1881 int
1882 vhost_user_modify_if (vnet_main_t * vnm, vlib_main_t * vm,
1883                       const char *sock_filename,
1884                       u8 is_server,
1885                       u32 sw_if_index,
1886                       u64 feature_mask, u8 renumber, u32 custom_dev_instance)
1887 {
1888   vhost_user_main_t *vum = &vhost_user_main;
1889   vhost_user_intf_t *vui = NULL;
1890   u32 sw_if_idx = ~0;
1891   int sockfd = -1;
1892   int rv = 0;
1893   uword *p = NULL;
1894
1895   p = hash_get (vum->vhost_user_interface_index_by_sw_if_index, sw_if_index);
1896   if (p == 0)
1897     {
1898       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1899     }
1900   else
1901     {
1902       vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
1903     }
1904
1905   // interface is inactive
1906   vui->active = 0;
1907   // disconnect interface sockets
1908   vhost_user_if_disconnect (vui);
1909
1910   if (is_server)
1911     {
1912       if ((rv = vhost_user_init_server_sock (sock_filename, &sockfd)) != 0)
1913         {
1914           return rv;
1915         }
1916     }
1917
1918   vhost_user_vui_init (vnm, vui, sockfd, sock_filename, is_server,
1919                        feature_mask, &sw_if_idx);
1920
1921   if (renumber)
1922     {
1923       vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
1924     }
1925
1926   vhost_user_vui_register (vm, vui);
1927
1928   return rv;
1929 }
1930
1931 clib_error_t *
1932 vhost_user_connect_command_fn (vlib_main_t * vm,
1933                                unformat_input_t * input,
1934                                vlib_cli_command_t * cmd)
1935 {
1936   unformat_input_t _line_input, *line_input = &_line_input;
1937   u8 *sock_filename = NULL;
1938   u32 sw_if_index;
1939   u8 is_server = 0;
1940   u64 feature_mask = (u64) ~ 0;
1941   u8 renumber = 0;
1942   u32 custom_dev_instance = ~0;
1943   u8 hwaddr[6];
1944   u8 *hw = NULL;
1945
1946   /* Get a line of input. */
1947   if (!unformat_user (input, unformat_line_input, line_input))
1948     return 0;
1949
1950   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1951     {
1952       if (unformat (line_input, "socket %s", &sock_filename))
1953         ;
1954       else if (unformat (line_input, "server"))
1955         is_server = 1;
1956       else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
1957         ;
1958       else
1959         if (unformat
1960             (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
1961         hw = hwaddr;
1962       else if (unformat (line_input, "renumber %d", &custom_dev_instance))
1963         {
1964           renumber = 1;
1965         }
1966       else
1967         return clib_error_return (0, "unknown input `%U'",
1968                                   format_unformat_error, input);
1969     }
1970   unformat_free (line_input);
1971
1972   vnet_main_t *vnm = vnet_get_main ();
1973
1974   int rv;
1975   if ((rv = vhost_user_create_if (vnm, vm, (char *) sock_filename,
1976                                   is_server, &sw_if_index, feature_mask,
1977                                   renumber, custom_dev_instance, hw)))
1978     {
1979       vec_free (sock_filename);
1980       return clib_error_return (0, "vhost_user_create_if returned %d", rv);
1981     }
1982
1983   vec_free (sock_filename);
1984   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
1985                    sw_if_index);
1986   return 0;
1987 }
1988
1989 clib_error_t *
1990 vhost_user_delete_command_fn (vlib_main_t * vm,
1991                               unformat_input_t * input,
1992                               vlib_cli_command_t * cmd)
1993 {
1994   unformat_input_t _line_input, *line_input = &_line_input;
1995   u32 sw_if_index = ~0;
1996
1997   /* Get a line of input. */
1998   if (!unformat_user (input, unformat_line_input, line_input))
1999     return 0;
2000
2001   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2002     {
2003       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
2004         ;
2005       else
2006         return clib_error_return (0, "unknown input `%U'",
2007                                   format_unformat_error, input);
2008     }
2009   unformat_free (line_input);
2010
2011   vnet_main_t *vnm = vnet_get_main ();
2012
2013   vhost_user_delete_if (vnm, vm, sw_if_index);
2014
2015   return 0;
2016 }
2017
2018 int
2019 vhost_user_dump_ifs (vnet_main_t * vnm, vlib_main_t * vm,
2020                      vhost_user_intf_details_t ** out_vuids)
2021 {
2022   int rv = 0;
2023   vhost_user_main_t *vum = &vhost_user_main;
2024   vhost_user_intf_t *vui;
2025   vhost_user_intf_details_t *r_vuids = NULL;
2026   vhost_user_intf_details_t *vuid = NULL;
2027   u32 *hw_if_indices = 0;
2028   vnet_hw_interface_t *hi;
2029   u8 *s = NULL;
2030   int i;
2031
2032   if (!out_vuids)
2033     return -1;
2034
2035   vec_foreach (vui, vum->vhost_user_interfaces)
2036   {
2037     if (vui->active)
2038       vec_add1 (hw_if_indices, vui->hw_if_index);
2039   }
2040
2041   for (i = 0; i < vec_len (hw_if_indices); i++)
2042     {
2043       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
2044       vui = vec_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
2045
2046       vec_add2 (r_vuids, vuid, 1);
2047       vuid->sw_if_index = vui->sw_if_index;
2048       vuid->virtio_net_hdr_sz = vui->virtio_net_hdr_sz;
2049       vuid->features = vui->features;
2050       vuid->is_server = vui->sock_is_server;
2051       vuid->num_regions = vui->nregions;
2052       vuid->sock_errno = vui->sock_errno;
2053       strncpy ((char *) vuid->sock_filename, (char *) vui->sock_filename,
2054                ARRAY_LEN (vuid->sock_filename) - 1);
2055
2056       s = format (s, "%v%c", hi->name, 0);
2057
2058       strncpy ((char *) vuid->if_name, (char *) s,
2059                ARRAY_LEN (vuid->if_name) - 1);
2060       _vec_len (s) = 0;
2061     }
2062
2063   vec_free (s);
2064   vec_free (hw_if_indices);
2065
2066   *out_vuids = r_vuids;
2067
2068   return rv;
2069 }
2070
2071 clib_error_t *
2072 show_vhost_user_command_fn (vlib_main_t * vm,
2073                             unformat_input_t * input,
2074                             vlib_cli_command_t * cmd)
2075 {
2076   clib_error_t *error = 0;
2077   vnet_main_t *vnm = vnet_get_main ();
2078   vhost_user_main_t *vum = &vhost_user_main;
2079   vhost_user_intf_t *vui;
2080   u32 hw_if_index, *hw_if_indices = 0;
2081   vnet_hw_interface_t *hi;
2082   int i, j, q;
2083   int show_descr = 0;
2084   struct feat_struct
2085   {
2086     u8 bit;
2087     char *str;
2088   };
2089   struct feat_struct *feat_entry;
2090
2091   static struct feat_struct feat_array[] = {
2092 #define _(s,b) { .str = #s, .bit = b, },
2093     foreach_virtio_net_feature
2094 #undef _
2095     {.str = NULL}
2096   };
2097
2098   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2099     {
2100       if (unformat
2101           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
2102         {
2103           vec_add1 (hw_if_indices, hw_if_index);
2104           vlib_cli_output (vm, "add %d", hw_if_index);
2105         }
2106       else if (unformat (input, "descriptors") || unformat (input, "desc"))
2107         show_descr = 1;
2108       else
2109         {
2110           error = clib_error_return (0, "unknown input `%U'",
2111                                      format_unformat_error, input);
2112           goto done;
2113         }
2114     }
2115   if (vec_len (hw_if_indices) == 0)
2116     {
2117       vec_foreach (vui, vum->vhost_user_interfaces)
2118       {
2119         if (vui->active)
2120           vec_add1 (hw_if_indices, vui->hw_if_index);
2121       }
2122     }
2123   vlib_cli_output (vm, "Virtio vhost-user interfaces");
2124   vlib_cli_output (vm, "Global:\n  coalesce frames %d time %e\n\n",
2125                    vum->coalesce_frames, vum->coalesce_time);
2126
2127   for (i = 0; i < vec_len (hw_if_indices); i++)
2128     {
2129       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
2130       vui = vec_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
2131       vlib_cli_output (vm, "Interface: %s (ifindex %d)",
2132                        hi->name, hw_if_indices[i]);
2133
2134       vlib_cli_output (vm, "virtio_net_hdr_sz %d\n features (0x%llx): \n",
2135                        vui->virtio_net_hdr_sz, vui->features);
2136
2137       feat_entry = (struct feat_struct *) &feat_array;
2138       while (feat_entry->str)
2139         {
2140           if (vui->features & (1 << feat_entry->bit))
2141             vlib_cli_output (vm, "   %s (%d)", feat_entry->str,
2142                              feat_entry->bit);
2143           feat_entry++;
2144         }
2145
2146       vlib_cli_output (vm, "\n");
2147
2148
2149       vlib_cli_output (vm, " socket filename %s type %s errno \"%s\"\n\n",
2150                        vui->sock_filename,
2151                        vui->sock_is_server ? "server" : "client",
2152                        strerror (vui->sock_errno));
2153
2154       vlib_cli_output (vm, " Memory regions (total %d)\n", vui->nregions);
2155
2156       if (vui->nregions)
2157         {
2158           vlib_cli_output (vm,
2159                            " region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr\n");
2160           vlib_cli_output (vm,
2161                            " ====== ===== ================== ================== ================== ================== ==================\n");
2162         }
2163       for (j = 0; j < vui->nregions; j++)
2164         {
2165           vlib_cli_output (vm,
2166                            "  %d     %-5d 0x%016lx 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
2167                            j, vui->region_mmap_fd[j],
2168                            vui->regions[j].guest_phys_addr,
2169                            vui->regions[j].memory_size,
2170                            vui->regions[j].userspace_addr,
2171                            vui->regions[j].mmap_offset,
2172                            pointer_to_uword (vui->region_mmap_addr[j]));
2173         }
2174       for (q = 0; q < vui->num_vrings; q++)
2175         {
2176           vlib_cli_output (vm, "\n Virtqueue %d\n", q);
2177
2178           vlib_cli_output (vm,
2179                            "  qsz %d last_avail_idx %d last_used_idx %d\n",
2180                            vui->vrings[q].qsz, vui->vrings[q].last_avail_idx,
2181                            vui->vrings[q].last_used_idx);
2182
2183           if (vui->vrings[q].avail && vui->vrings[q].used)
2184             vlib_cli_output (vm,
2185                              "  avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
2186                              vui->vrings[q].avail->flags,
2187                              vui->vrings[q].avail->idx,
2188                              vui->vrings[q].used->flags,
2189                              vui->vrings[q].used->idx);
2190
2191           vlib_cli_output (vm, "  kickfd %d callfd %d errfd %d\n",
2192                            vui->vrings[q].kickfd,
2193                            vui->vrings[q].callfd, vui->vrings[q].errfd);
2194
2195           if (show_descr)
2196             {
2197               vlib_cli_output (vm, "\n  descriptor table:\n");
2198               vlib_cli_output (vm,
2199                                "   id          addr         len  flags  next      user_addr\n");
2200               vlib_cli_output (vm,
2201                                "  ===== ================== ===== ====== ===== ==================\n");
2202               for (j = 0; j < vui->vrings[q].qsz; j++)
2203                 {
2204                   vlib_cli_output (vm,
2205                                    "  %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
2206                                    j, vui->vrings[q].desc[j].addr,
2207                                    vui->vrings[q].desc[j].len,
2208                                    vui->vrings[q].desc[j].flags,
2209                                    vui->vrings[q].desc[j].next,
2210                                    pointer_to_uword (map_guest_mem
2211                                                      (vui,
2212                                                       vui->vrings[q].
2213                                                       desc[j].addr)));
2214                 }
2215             }
2216         }
2217       vlib_cli_output (vm, "\n");
2218     }
2219 done:
2220   vec_free (hw_if_indices);
2221   return error;
2222 }
2223
2224 static clib_error_t *
2225 vhost_user_config (vlib_main_t * vm, unformat_input_t * input)
2226 {
2227   vhost_user_main_t *vum = &vhost_user_main;
2228
2229   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2230     {
2231       if (unformat (input, "coalesce-frames %d", &vum->coalesce_frames))
2232         ;
2233       else if (unformat (input, "coalesce-time %f", &vum->coalesce_time))
2234         ;
2235       else if (unformat (input, "dont-dump-memory"))
2236         vum->dont_dump_vhost_user_memory = 1;
2237       else
2238         return clib_error_return (0, "unknown input `%U'",
2239                                   format_unformat_error, input);
2240     }
2241
2242   return 0;
2243 }
2244
2245 /* vhost-user { ... } configuration. */
2246 VLIB_CONFIG_FUNCTION (vhost_user_config, "vhost-user");
2247
2248 void
2249 vhost_user_unmap_all (void)
2250 {
2251   vhost_user_main_t *vum = &vhost_user_main;
2252   vhost_user_intf_t *vui;
2253
2254   if (vum->dont_dump_vhost_user_memory)
2255     {
2256       vec_foreach (vui, vum->vhost_user_interfaces)
2257       {
2258         unmap_all_mem_regions (vui);
2259       }
2260     }
2261 }
2262
2263 /*
2264  * fd.io coding-style-patch-verification: ON
2265  *
2266  * Local Variables:
2267  * eval: (c-set-style "gnu")
2268  * End:
2269  */