vhost: VPP stalls with vhost performing control plane actions
[vpp.git] / src / vnet / devices / virtio / vhost_user.c
1 /*
2  *------------------------------------------------------------------
3  * vhost.c - vhost-user
4  *
5  * Copyright (c) 2014-2018 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 #include <vnet/devices/devices.h>
40 #include <vnet/feature/feature.h>
41
42 #include <vnet/devices/virtio/vhost_user.h>
43 #include <vnet/devices/virtio/vhost_user_inline.h>
44
45 /**
46  * @file
47  * @brief vHost User Device Driver.
48  *
49  * This file contains the source code for vHost User interface.
50  */
51
52
53 vlib_node_registration_t vhost_user_send_interrupt_node;
54
55 /* *INDENT-OFF* */
56 vhost_user_main_t vhost_user_main = {
57   .mtu_bytes = 1518,
58 };
59
60 VNET_HW_INTERFACE_CLASS (vhost_interface_class, static) = {
61   .name = "vhost-user",
62 };
63 /* *INDENT-ON* */
64
65 static long
66 get_huge_page_size (int fd)
67 {
68   struct statfs s;
69   fstatfs (fd, &s);
70   return s.f_bsize;
71 }
72
73 static void
74 unmap_all_mem_regions (vhost_user_intf_t * vui)
75 {
76   int i, r, q;
77   vhost_user_vring_t *vq;
78
79   for (i = 0; i < vui->nregions; i++)
80     {
81       if (vui->region_mmap_addr[i] != MAP_FAILED)
82         {
83
84           long page_sz = get_huge_page_size (vui->region_mmap_fd[i]);
85
86           ssize_t map_sz = (vui->regions[i].memory_size +
87                             vui->regions[i].mmap_offset +
88                             page_sz - 1) & ~(page_sz - 1);
89
90           r =
91             munmap (vui->region_mmap_addr[i] - vui->regions[i].mmap_offset,
92                     map_sz);
93
94           vu_log_debug (vui, "unmap memory region %d addr 0x%lx len 0x%lx "
95                         "page_sz 0x%x", i, vui->region_mmap_addr[i], map_sz,
96                         page_sz);
97
98           vui->region_mmap_addr[i] = MAP_FAILED;
99
100           if (r == -1)
101             {
102               vu_log_err (vui, "failed to unmap memory region (errno %d)",
103                           errno);
104             }
105           close (vui->region_mmap_fd[i]);
106         }
107     }
108   vui->nregions = 0;
109
110   for (q = 0; q < VHOST_VRING_MAX_N; q++)
111     {
112       vq = &vui->vrings[q];
113       vq->avail = 0;
114       vq->used = 0;
115       vq->desc = 0;
116     }
117 }
118
119 static_always_inline void
120 vhost_user_tx_thread_placement (vhost_user_intf_t * vui)
121 {
122   //Let's try to assign one queue to each thread
123   u32 qid;
124   u32 thread_index = 0;
125
126   vui->use_tx_spinlock = 0;
127   while (1)
128     {
129       for (qid = 0; qid < VHOST_VRING_MAX_N / 2; qid++)
130         {
131           vhost_user_vring_t *rxvq = &vui->vrings[VHOST_VRING_IDX_RX (qid)];
132           if (!rxvq->started || !rxvq->enabled)
133             continue;
134
135           vui->per_cpu_tx_qid[thread_index] = qid;
136           thread_index++;
137           if (thread_index == vlib_get_thread_main ()->n_vlib_mains)
138             return;
139         }
140       //We need to loop, meaning the spinlock has to be used
141       vui->use_tx_spinlock = 1;
142       if (thread_index == 0)
143         {
144           //Could not find a single valid one
145           for (thread_index = 0;
146                thread_index < vlib_get_thread_main ()->n_vlib_mains;
147                thread_index++)
148             {
149               vui->per_cpu_tx_qid[thread_index] = 0;
150             }
151           return;
152         }
153     }
154 }
155
156 /**
157  * @brief Unassign existing interface/queue to thread mappings and re-assign
158  * new interface/queue to thread mappings
159  */
160 static_always_inline void
161 vhost_user_rx_thread_placement (vhost_user_intf_t * vui, u32 qid)
162 {
163   vhost_user_vring_t *txvq = &vui->vrings[qid];
164   vnet_main_t *vnm = vnet_get_main ();
165   int rv;
166   u32 q = qid >> 1;
167
168   ASSERT ((qid & 1) == 1);      // should be odd
169   // Assign new queue mappings for the interface
170   vnet_hw_interface_set_input_node (vnm, vui->hw_if_index,
171                                     vhost_user_input_node.index);
172   vnet_hw_interface_assign_rx_thread (vnm, vui->hw_if_index, q, ~0);
173   if (txvq->mode == VNET_HW_INTERFACE_RX_MODE_UNKNOWN)
174     /* Set polling as the default */
175     txvq->mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
176   txvq->qid = q;
177   rv = vnet_hw_interface_set_rx_mode (vnm, vui->hw_if_index, q, txvq->mode);
178   if (rv)
179     vu_log_warn (vui, "unable to set rx mode for interface %d, "
180                  "queue %d: rc=%d", vui->hw_if_index, q, rv);
181 }
182
183 /** @brief Returns whether at least one TX and one RX vring are enabled */
184 static_always_inline int
185 vhost_user_intf_ready (vhost_user_intf_t * vui)
186 {
187   int i, found[2] = { };        //RX + TX
188
189   for (i = 0; i < VHOST_VRING_MAX_N; i++)
190     if (vui->vrings[i].started && vui->vrings[i].enabled)
191       found[i & 1] = 1;
192
193   return found[0] && found[1];
194 }
195
196 static_always_inline void
197 vhost_user_update_iface_state (vhost_user_intf_t * vui)
198 {
199   /* if we have pointers to descriptor table, go up */
200   int is_ready = vhost_user_intf_ready (vui);
201   if (is_ready != vui->is_ready)
202     {
203       vu_log_debug (vui, "interface %d %s", vui->sw_if_index,
204                     is_ready ? "ready" : "down");
205       if (vui->admin_up)
206         vnet_hw_interface_set_flags (vnet_get_main (), vui->hw_if_index,
207                                      is_ready ? VNET_HW_INTERFACE_FLAG_LINK_UP
208                                      : 0);
209       vui->is_ready = is_ready;
210     }
211 }
212
213 static void
214 vhost_user_set_interrupt_pending (vhost_user_intf_t * vui, u32 ifq)
215 {
216   u32 qid;
217   vnet_main_t *vnm = vnet_get_main ();
218
219   qid = ifq & 0xff;
220   if ((qid & 1) == 0)
221     /* Only care about the odd number, or TX, virtqueue */
222     return;
223
224   if (vhost_user_intf_ready (vui))
225     // qid >> 1 is to convert virtqueue number to vring queue index
226     vnet_device_input_set_interrupt_pending (vnm, vui->hw_if_index, qid >> 1);
227 }
228
229 static clib_error_t *
230 vhost_user_callfd_read_ready (clib_file_t * uf)
231 {
232   __attribute__ ((unused)) int n;
233   u8 buff[8];
234
235   n = read (uf->file_descriptor, ((char *) &buff), 8);
236
237   return 0;
238 }
239
240 static_always_inline void
241 vhost_user_thread_placement (vhost_user_intf_t * vui, u32 qid)
242 {
243   if (qid & 1)                  // RX is odd, TX is even
244     {
245       if (vui->vrings[qid].qid == -1)
246         vhost_user_rx_thread_placement (vui, qid);
247     }
248   else
249     vhost_user_tx_thread_placement (vui);
250 }
251
252 static clib_error_t *
253 vhost_user_kickfd_read_ready (clib_file_t * uf)
254 {
255   __attribute__ ((unused)) int n;
256   u8 buff[8];
257   vhost_user_intf_t *vui =
258     pool_elt_at_index (vhost_user_main.vhost_user_interfaces,
259                        uf->private_data >> 8);
260   u32 qid = uf->private_data & 0xff;
261
262   n = read (uf->file_descriptor, ((char *) &buff), 8);
263   vu_log_debug (vui, "if %d KICK queue %d", uf->private_data >> 8, qid);
264   if (!vui->vrings[qid].started ||
265       (vhost_user_intf_ready (vui) != vui->is_ready))
266     {
267       if (vui->vrings[qid].started == 0)
268         {
269           vui->vrings[qid].started = 1;
270           vhost_user_thread_placement (vui, qid);
271           vhost_user_update_iface_state (vui);
272         }
273     }
274
275   vhost_user_set_interrupt_pending (vui, uf->private_data);
276   return 0;
277 }
278
279 static_always_inline void
280 vhost_user_vring_init (vhost_user_intf_t * vui, u32 qid)
281 {
282   vhost_user_vring_t *vring = &vui->vrings[qid];
283   clib_memset (vring, 0, sizeof (*vring));
284   vring->kickfd_idx = ~0;
285   vring->callfd_idx = ~0;
286   vring->errfd = -1;
287   vring->qid = -1;
288
289   /*
290    * We have a bug with some qemu 2.5, and this may be a fix.
291    * Feel like interpretation holy text, but this is from vhost-user.txt.
292    * "
293    * One queue pair is enabled initially. More queues are enabled
294    * dynamically, by sending message VHOST_USER_SET_VRING_ENABLE.
295    * "
296    * Don't know who's right, but this is what DPDK does.
297    */
298   if (qid == 0 || qid == 1)
299     vring->enabled = 1;
300 }
301
302 static_always_inline void
303 vhost_user_vring_close (vhost_user_intf_t * vui, u32 qid)
304 {
305   vhost_user_vring_t *vring = &vui->vrings[qid];
306
307   if (vring->kickfd_idx != ~0)
308     {
309       clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
310                                            vring->kickfd_idx);
311       clib_file_del (&file_main, uf);
312       vring->kickfd_idx = ~0;
313     }
314   if (vring->callfd_idx != ~0)
315     {
316       clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
317                                            vring->callfd_idx);
318       clib_file_del (&file_main, uf);
319       vring->callfd_idx = ~0;
320     }
321   if (vring->errfd != -1)
322     {
323       close (vring->errfd);
324       vring->errfd = -1;
325     }
326
327   // save the qid so that we don't need to unassign and assign_rx_thread
328   // when the interface comes back up. They are expensive calls.
329   u16 q = vui->vrings[qid].qid;
330   vhost_user_vring_init (vui, qid);
331   vui->vrings[qid].qid = q;
332 }
333
334 static_always_inline void
335 vhost_user_if_disconnect (vhost_user_intf_t * vui)
336 {
337   vnet_main_t *vnm = vnet_get_main ();
338   int q;
339
340   vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
341
342   if (vui->clib_file_index != ~0)
343     {
344       clib_file_del (&file_main, file_main.file_pool + vui->clib_file_index);
345       vui->clib_file_index = ~0;
346     }
347
348   vui->is_ready = 0;
349
350   for (q = 0; q < VHOST_VRING_MAX_N; q++)
351     vhost_user_vring_close (vui, q);
352
353   unmap_all_mem_regions (vui);
354   vu_log_debug (vui, "interface ifindex %d disconnected", vui->sw_if_index);
355 }
356
357 static clib_error_t *
358 vhost_user_socket_read (clib_file_t * uf)
359 {
360   int n, i, j;
361   int fd, number_of_fds = 0;
362   int fds[VHOST_MEMORY_MAX_NREGIONS];
363   vhost_user_msg_t msg;
364   struct msghdr mh;
365   struct iovec iov[1];
366   vhost_user_main_t *vum = &vhost_user_main;
367   vhost_user_intf_t *vui;
368   struct cmsghdr *cmsg;
369   u8 q;
370   clib_file_t template = { 0 };
371   vnet_main_t *vnm = vnet_get_main ();
372   vlib_main_t *vm = vlib_get_main ();
373
374   vui = pool_elt_at_index (vum->vhost_user_interfaces, uf->private_data);
375
376   char control[CMSG_SPACE (VHOST_MEMORY_MAX_NREGIONS * sizeof (int))];
377
378   clib_memset (&mh, 0, sizeof (mh));
379   clib_memset (control, 0, sizeof (control));
380
381   for (i = 0; i < VHOST_MEMORY_MAX_NREGIONS; i++)
382     fds[i] = -1;
383
384   /* set the payload */
385   iov[0].iov_base = (void *) &msg;
386   iov[0].iov_len = VHOST_USER_MSG_HDR_SZ;
387
388   mh.msg_iov = iov;
389   mh.msg_iovlen = 1;
390   mh.msg_control = control;
391   mh.msg_controllen = sizeof (control);
392
393   n = recvmsg (uf->file_descriptor, &mh, 0);
394
395   if (n != VHOST_USER_MSG_HDR_SZ)
396     {
397       if (n == -1)
398         {
399           vu_log_debug (vui, "recvmsg returned error %d %s", errno,
400                         strerror (errno));
401         }
402       else
403         {
404           vu_log_debug (vui, "n (%d) != VHOST_USER_MSG_HDR_SZ (%d)",
405                         n, VHOST_USER_MSG_HDR_SZ);
406         }
407       goto close_socket;
408     }
409
410   if (mh.msg_flags & MSG_CTRUNC)
411     {
412       vu_log_debug (vui, "MSG_CTRUNC is set");
413       goto close_socket;
414     }
415
416   cmsg = CMSG_FIRSTHDR (&mh);
417
418   if (cmsg && (cmsg->cmsg_len > 0) && (cmsg->cmsg_level == SOL_SOCKET) &&
419       (cmsg->cmsg_type == SCM_RIGHTS) &&
420       (cmsg->cmsg_len - CMSG_LEN (0) <=
421        VHOST_MEMORY_MAX_NREGIONS * sizeof (int)))
422     {
423       number_of_fds = (cmsg->cmsg_len - CMSG_LEN (0)) / sizeof (int);
424       clib_memcpy_fast (fds, CMSG_DATA (cmsg), number_of_fds * sizeof (int));
425     }
426
427   /* version 1, no reply bit set */
428   if ((msg.flags & 7) != 1)
429     {
430       vu_log_debug (vui, "malformed message received. closing socket");
431       goto close_socket;
432     }
433
434   {
435     int rv;
436     rv =
437       read (uf->file_descriptor, ((char *) &msg) + VHOST_USER_MSG_HDR_SZ,
438             msg.size);
439     if (rv < 0)
440       {
441         vu_log_debug (vui, "read failed %s", strerror (errno));
442         goto close_socket;
443       }
444     else if (rv != msg.size)
445       {
446         vu_log_debug (vui, "message too short (read %dB should be %dB)", rv,
447                       msg.size);
448         goto close_socket;
449       }
450   }
451
452   switch (msg.request)
453     {
454     case VHOST_USER_GET_FEATURES:
455       msg.flags |= 4;
456       msg.u64 = (1ULL << FEAT_VIRTIO_NET_F_MRG_RXBUF) |
457         (1ULL << FEAT_VIRTIO_NET_F_CTRL_VQ) |
458         (1ULL << FEAT_VIRTIO_F_ANY_LAYOUT) |
459         (1ULL << FEAT_VIRTIO_F_INDIRECT_DESC) |
460         (1ULL << FEAT_VHOST_F_LOG_ALL) |
461         (1ULL << FEAT_VIRTIO_NET_F_GUEST_ANNOUNCE) |
462         (1ULL << FEAT_VIRTIO_NET_F_MQ) |
463         (1ULL << FEAT_VHOST_USER_F_PROTOCOL_FEATURES) |
464         (1ULL << FEAT_VIRTIO_F_VERSION_1);
465       msg.u64 &= vui->feature_mask;
466       msg.size = sizeof (msg.u64);
467       vu_log_debug (vui, "if %d msg VHOST_USER_GET_FEATURES - reply "
468                     "0x%016llx", vui->hw_if_index, msg.u64);
469       n =
470         send (uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
471       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
472         {
473           vu_log_debug (vui, "could not send message response");
474           goto close_socket;
475         }
476       break;
477
478     case VHOST_USER_SET_FEATURES:
479       vu_log_debug (vui, "if %d msg VHOST_USER_SET_FEATURES features "
480                     "0x%016llx", vui->hw_if_index, msg.u64);
481
482       vui->features = msg.u64;
483
484       if (vui->features &
485           ((1 << FEAT_VIRTIO_NET_F_MRG_RXBUF) |
486            (1ULL << FEAT_VIRTIO_F_VERSION_1)))
487         vui->virtio_net_hdr_sz = 12;
488       else
489         vui->virtio_net_hdr_sz = 10;
490
491       vui->is_any_layout =
492         (vui->features & (1 << FEAT_VIRTIO_F_ANY_LAYOUT)) ? 1 : 0;
493
494       ASSERT (vui->virtio_net_hdr_sz < VLIB_BUFFER_PRE_DATA_SIZE);
495       vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
496       vui->is_ready = 0;
497       break;
498
499     case VHOST_USER_SET_MEM_TABLE:
500       vu_log_debug (vui, "if %d msg VHOST_USER_SET_MEM_TABLE nregions %d",
501                     vui->hw_if_index, msg.memory.nregions);
502
503       if ((msg.memory.nregions < 1) ||
504           (msg.memory.nregions > VHOST_MEMORY_MAX_NREGIONS))
505         {
506           vu_log_debug (vui, "number of mem regions must be between 1 and %i",
507                         VHOST_MEMORY_MAX_NREGIONS);
508           goto close_socket;
509         }
510
511       if (msg.memory.nregions != number_of_fds)
512         {
513           vu_log_debug (vui, "each memory region must have FD");
514           goto close_socket;
515         }
516
517       /* Do the mmap without barrier sync */
518       void *region_mmap_addr[VHOST_MEMORY_MAX_NREGIONS];
519       for (i = 0; i < msg.memory.nregions; i++)
520         {
521           long page_sz = get_huge_page_size (fds[i]);
522
523           /* align size to page */
524           ssize_t map_sz = (msg.memory.regions[i].memory_size +
525                             msg.memory.regions[i].mmap_offset +
526                             page_sz - 1) & ~(page_sz - 1);
527
528           region_mmap_addr[i] = mmap (0, map_sz, PROT_READ | PROT_WRITE,
529                                       MAP_SHARED, fds[i], 0);
530           if (region_mmap_addr[i] == MAP_FAILED)
531             {
532               vu_log_err (vui, "failed to map memory. errno is %d", errno);
533               for (j = 0; j < i; j++)
534                 munmap (region_mmap_addr[j], map_sz);
535               goto close_socket;
536             }
537           vu_log_debug (vui, "map memory region %d addr 0 len 0x%lx fd %d "
538                         "mapped 0x%lx page_sz 0x%x", i, map_sz, fds[i],
539                         region_mmap_addr[i], page_sz);
540         }
541
542       vlib_worker_thread_barrier_sync (vm);
543       unmap_all_mem_regions (vui);
544       for (i = 0; i < msg.memory.nregions; i++)
545         {
546           clib_memcpy_fast (&(vui->regions[i]), &msg.memory.regions[i],
547                             sizeof (vhost_user_memory_region_t));
548
549           vui->region_mmap_addr[i] = region_mmap_addr[i];
550           vui->region_guest_addr_lo[i] = vui->regions[i].guest_phys_addr;
551           vui->region_guest_addr_hi[i] = vui->regions[i].guest_phys_addr +
552             vui->regions[i].memory_size;
553
554           vui->region_mmap_addr[i] += vui->regions[i].mmap_offset;
555           vui->region_mmap_fd[i] = fds[i];
556
557           vui->nregions++;
558         }
559       vlib_worker_thread_barrier_release (vm);
560       break;
561
562     case VHOST_USER_SET_VRING_NUM:
563       vu_log_debug (vui, "if %d msg VHOST_USER_SET_VRING_NUM idx %d num %d",
564                     vui->hw_if_index, msg.state.index, msg.state.num);
565
566       if ((msg.state.num > 32768) ||    /* maximum ring size is 32768 */
567           (msg.state.num == 0) ||       /* it cannot be zero */
568           ((msg.state.num - 1) & msg.state.num))        /* must be power of 2 */
569         goto close_socket;
570       vui->vrings[msg.state.index].qsz_mask = msg.state.num - 1;
571       break;
572
573     case VHOST_USER_SET_VRING_ADDR:
574       vu_log_debug (vui, "if %d msg VHOST_USER_SET_VRING_ADDR idx %d",
575                     vui->hw_if_index, msg.state.index);
576
577       if (msg.state.index >= VHOST_VRING_MAX_N)
578         {
579           vu_log_debug (vui, "invalid vring index VHOST_USER_SET_VRING_ADDR:"
580                         " %d >= %d", msg.state.index, VHOST_VRING_MAX_N);
581           goto close_socket;
582         }
583
584       if (msg.size < sizeof (msg.addr))
585         {
586           vu_log_debug (vui, "vhost message is too short (%d < %d)",
587                         msg.size, sizeof (msg.addr));
588           goto close_socket;
589         }
590
591       vring_desc_t *desc = map_user_mem (vui, msg.addr.desc_user_addr);
592       vring_used_t *used = map_user_mem (vui, msg.addr.used_user_addr);
593       vring_avail_t *avail = map_user_mem (vui, msg.addr.avail_user_addr);
594
595       if ((desc == NULL) || (used == NULL) || (avail == NULL))
596         {
597           vu_log_debug (vui, "failed to map user memory for hw_if_index %d",
598                         vui->hw_if_index);
599           goto close_socket;
600         }
601
602       vlib_worker_thread_barrier_sync (vm);
603       vui->vrings[msg.state.index].desc = desc;
604       vui->vrings[msg.state.index].used = used;
605       vui->vrings[msg.state.index].avail = avail;
606
607       vui->vrings[msg.state.index].log_guest_addr = msg.addr.log_guest_addr;
608       vui->vrings[msg.state.index].log_used =
609         (msg.addr.flags & (1 << VHOST_VRING_F_LOG)) ? 1 : 0;
610
611       /* Spec says: If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated,
612          the ring is initialized in an enabled state. */
613       if (!(vui->features & (1 << FEAT_VHOST_USER_F_PROTOCOL_FEATURES)))
614         vui->vrings[msg.state.index].enabled = 1;
615
616       vui->vrings[msg.state.index].last_used_idx =
617         vui->vrings[msg.state.index].last_avail_idx =
618         vui->vrings[msg.state.index].used->idx;
619
620       /* tell driver that we don't want interrupts */
621       vui->vrings[msg.state.index].used->flags = VRING_USED_F_NO_NOTIFY;
622       vlib_worker_thread_barrier_release (vm);
623       vhost_user_update_iface_state (vui);
624       break;
625
626     case VHOST_USER_SET_OWNER:
627       vu_log_debug (vui, "if %d msg VHOST_USER_SET_OWNER", vui->hw_if_index);
628       break;
629
630     case VHOST_USER_RESET_OWNER:
631       vu_log_debug (vui, "if %d msg VHOST_USER_RESET_OWNER",
632                     vui->hw_if_index);
633       break;
634
635     case VHOST_USER_SET_VRING_CALL:
636       vu_log_debug (vui, "if %d msg VHOST_USER_SET_VRING_CALL %d",
637                     vui->hw_if_index, msg.u64);
638
639       q = (u8) (msg.u64 & 0xFF);
640
641       /* if there is old fd, delete and close it */
642       if (vui->vrings[q].callfd_idx != ~0)
643         {
644           clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
645                                                vui->vrings[q].callfd_idx);
646           clib_file_del (&file_main, uf);
647           vui->vrings[q].callfd_idx = ~0;
648         }
649
650       if (!(msg.u64 & VHOST_USER_VRING_NOFD_MASK))
651         {
652           if (number_of_fds != 1)
653             {
654               vu_log_debug (vui, "More than one fd received !");
655               goto close_socket;
656             }
657
658           template.read_function = vhost_user_callfd_read_ready;
659           template.file_descriptor = fds[0];
660           template.private_data =
661             ((vui - vhost_user_main.vhost_user_interfaces) << 8) + q;
662           vui->vrings[q].callfd_idx = clib_file_add (&file_main, &template);
663         }
664       else
665         vui->vrings[q].callfd_idx = ~0;
666       break;
667
668     case VHOST_USER_SET_VRING_KICK:
669       vu_log_debug (vui, "if %d msg VHOST_USER_SET_VRING_KICK %d",
670                     vui->hw_if_index, msg.u64);
671
672       q = (u8) (msg.u64 & 0xFF);
673
674       if (vui->vrings[q].kickfd_idx != ~0)
675         {
676           clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
677                                                vui->vrings[q].kickfd_idx);
678           clib_file_del (&file_main, uf);
679           vui->vrings[q].kickfd_idx = ~0;
680         }
681
682       if (!(msg.u64 & VHOST_USER_VRING_NOFD_MASK))
683         {
684           if (number_of_fds != 1)
685             {
686               vu_log_debug (vui, "More than one fd received !");
687               goto close_socket;
688             }
689
690           template.read_function = vhost_user_kickfd_read_ready;
691           template.file_descriptor = fds[0];
692           template.private_data =
693             (((uword) (vui - vhost_user_main.vhost_user_interfaces)) << 8) +
694             q;
695           vui->vrings[q].kickfd_idx = clib_file_add (&file_main, &template);
696         }
697       else
698         {
699           //When no kickfd is set, the queue is initialized as started
700           vui->vrings[q].kickfd_idx = ~0;
701           vui->vrings[q].started = 1;
702           vhost_user_thread_placement (vui, q);
703         }
704       vhost_user_update_iface_state (vui);
705       break;
706
707     case VHOST_USER_SET_VRING_ERR:
708       vu_log_debug (vui, "if %d msg VHOST_USER_SET_VRING_ERR %d",
709                     vui->hw_if_index, msg.u64);
710
711       q = (u8) (msg.u64 & 0xFF);
712
713       if (vui->vrings[q].errfd != -1)
714         close (vui->vrings[q].errfd);
715
716       if (!(msg.u64 & VHOST_USER_VRING_NOFD_MASK))
717         {
718           if (number_of_fds != 1)
719             goto close_socket;
720
721           vui->vrings[q].errfd = fds[0];
722         }
723       else
724         vui->vrings[q].errfd = -1;
725       break;
726
727     case VHOST_USER_SET_VRING_BASE:
728       vu_log_debug (vui, "if %d msg VHOST_USER_SET_VRING_BASE idx %d num %d",
729                     vui->hw_if_index, msg.state.index, msg.state.num);
730       vlib_worker_thread_barrier_sync (vm);
731       vui->vrings[msg.state.index].last_avail_idx = msg.state.num;
732       vlib_worker_thread_barrier_release (vm);
733       break;
734
735     case VHOST_USER_GET_VRING_BASE:
736       if (msg.state.index >= VHOST_VRING_MAX_N)
737         {
738           vu_log_debug (vui, "invalid vring index VHOST_USER_GET_VRING_BASE:"
739                         " %d >= %d", msg.state.index, VHOST_VRING_MAX_N);
740           goto close_socket;
741         }
742
743       /* protection is needed to prevent rx/tx from changing last_avail_idx */
744       vlib_worker_thread_barrier_sync (vm);
745       /*
746        * Copy last_avail_idx from the vring before closing it because
747        * closing the vring also initializes the vring last_avail_idx
748        */
749       msg.state.num = vui->vrings[msg.state.index].last_avail_idx;
750       msg.flags |= 4;
751       msg.size = sizeof (msg.state);
752
753       /*
754        * Spec says: Client must [...] stop ring upon receiving
755        * VHOST_USER_GET_VRING_BASE
756        */
757       vhost_user_vring_close (vui, msg.state.index);
758       vlib_worker_thread_barrier_release (vm);
759       vu_log_debug (vui, "if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
760                     vui->hw_if_index, msg.state.index, msg.state.num);
761       n =
762         send (uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
763       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
764         {
765           vu_log_debug (vui, "could not send message response");
766           goto close_socket;
767         }
768       vhost_user_update_iface_state (vui);
769       break;
770
771     case VHOST_USER_NONE:
772       vu_log_debug (vui, "if %d msg VHOST_USER_NONE", vui->hw_if_index);
773       break;
774
775     case VHOST_USER_SET_LOG_BASE:
776       vu_log_debug (vui, "if %d msg VHOST_USER_SET_LOG_BASE",
777                     vui->hw_if_index);
778
779       if (msg.size != sizeof (msg.log))
780         {
781           vu_log_debug (vui, "invalid msg size for VHOST_USER_SET_LOG_BASE:"
782                         " %d instead of %d", msg.size, sizeof (msg.log));
783           goto close_socket;
784         }
785
786       if (!(vui->protocol_features & (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD)))
787         {
788           vu_log_debug (vui, "VHOST_USER_PROTOCOL_F_LOG_SHMFD not set but "
789                         "VHOST_USER_SET_LOG_BASE received");
790           goto close_socket;
791         }
792
793       fd = fds[0];
794       /* align size to page */
795       long page_sz = get_huge_page_size (fd);
796       ssize_t map_sz =
797         (msg.log.size + msg.log.offset + page_sz - 1) & ~(page_sz - 1);
798
799       void *log_base_addr = mmap (0, map_sz, PROT_READ | PROT_WRITE,
800                                   MAP_SHARED, fd, 0);
801
802       vu_log_debug (vui, "map log region addr 0 len 0x%lx off 0x%lx fd %d "
803                     "mapped 0x%lx", map_sz, msg.log.offset, fd,
804                     log_base_addr);
805
806       if (log_base_addr == MAP_FAILED)
807         {
808           vu_log_err (vui, "failed to map memory. errno is %d", errno);
809           goto close_socket;
810         }
811
812       vlib_worker_thread_barrier_sync (vm);
813       vui->log_base_addr = log_base_addr;
814       vui->log_base_addr += msg.log.offset;
815       vui->log_size = msg.log.size;
816       vlib_worker_thread_barrier_release (vm);
817
818       msg.flags |= 4;
819       msg.size = sizeof (msg.u64);
820       n =
821         send (uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
822       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
823         {
824           vu_log_debug (vui, "could not send message response");
825           goto close_socket;
826         }
827       break;
828
829     case VHOST_USER_SET_LOG_FD:
830       vu_log_debug (vui, "if %d msg VHOST_USER_SET_LOG_FD", vui->hw_if_index);
831       break;
832
833     case VHOST_USER_GET_PROTOCOL_FEATURES:
834       msg.flags |= 4;
835       msg.u64 = (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD) |
836         (1 << VHOST_USER_PROTOCOL_F_MQ);
837       msg.size = sizeof (msg.u64);
838       vu_log_debug (vui, "if %d msg VHOST_USER_GET_PROTOCOL_FEATURES - "
839                     "reply 0x%016llx", vui->hw_if_index, msg.u64);
840       n =
841         send (uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
842       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
843         {
844           vu_log_debug (vui, "could not send message response");
845           goto close_socket;
846         }
847       break;
848
849     case VHOST_USER_SET_PROTOCOL_FEATURES:
850       vu_log_debug (vui, "if %d msg VHOST_USER_SET_PROTOCOL_FEATURES "
851                     "features 0x%016llx", vui->hw_if_index, msg.u64);
852       vui->protocol_features = msg.u64;
853       break;
854
855     case VHOST_USER_GET_QUEUE_NUM:
856       msg.flags |= 4;
857       msg.u64 = VHOST_VRING_MAX_N;
858       msg.size = sizeof (msg.u64);
859       vu_log_debug (vui, "if %d msg VHOST_USER_GET_QUEUE_NUM - reply %d",
860                     vui->hw_if_index, msg.u64);
861       n =
862         send (uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
863       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
864         {
865           vu_log_debug (vui, "could not send message response");
866           goto close_socket;
867         }
868       break;
869
870     case VHOST_USER_SET_VRING_ENABLE:
871       vu_log_debug (vui, "if %d VHOST_USER_SET_VRING_ENABLE: %s queue %d",
872                     vui->hw_if_index, msg.state.num ? "enable" : "disable",
873                     msg.state.index);
874       if (msg.state.index >= VHOST_VRING_MAX_N)
875         {
876           vu_log_debug (vui, "invalid vring idx VHOST_USER_SET_VRING_ENABLE:"
877                         " %d >= %d", msg.state.index, VHOST_VRING_MAX_N);
878           goto close_socket;
879         }
880
881       vui->vrings[msg.state.index].enabled = msg.state.num;
882       vhost_user_thread_placement (vui, msg.state.index);
883       vhost_user_update_iface_state (vui);
884       break;
885
886     default:
887       vu_log_debug (vui, "unknown vhost-user message %d received. "
888                     "closing socket", msg.request);
889       goto close_socket;
890     }
891
892   return 0;
893
894 close_socket:
895   vlib_worker_thread_barrier_sync (vm);
896   vhost_user_if_disconnect (vui);
897   vlib_worker_thread_barrier_release (vm);
898   vhost_user_update_iface_state (vui);
899   return 0;
900 }
901
902 static clib_error_t *
903 vhost_user_socket_error (clib_file_t * uf)
904 {
905   vlib_main_t *vm = vlib_get_main ();
906   vhost_user_main_t *vum = &vhost_user_main;
907   vhost_user_intf_t *vui =
908     pool_elt_at_index (vum->vhost_user_interfaces, uf->private_data);
909
910   vu_log_debug (vui, "socket error on if %d", vui->sw_if_index);
911   vlib_worker_thread_barrier_sync (vm);
912   vhost_user_if_disconnect (vui);
913   vlib_worker_thread_barrier_release (vm);
914   return 0;
915 }
916
917 static clib_error_t *
918 vhost_user_socksvr_accept_ready (clib_file_t * uf)
919 {
920   int client_fd, client_len;
921   struct sockaddr_un client;
922   clib_file_t template = { 0 };
923   vhost_user_main_t *vum = &vhost_user_main;
924   vhost_user_intf_t *vui;
925
926   vui = pool_elt_at_index (vum->vhost_user_interfaces, uf->private_data);
927
928   client_len = sizeof (client);
929   client_fd = accept (uf->file_descriptor,
930                       (struct sockaddr *) &client,
931                       (socklen_t *) & client_len);
932
933   if (client_fd < 0)
934     return clib_error_return_unix (0, "accept");
935
936   if (vui->clib_file_index != ~0)
937     {
938       vu_log_debug (vui, "Close client socket for vhost interface %d, fd %d",
939                     vui->sw_if_index, UNIX_GET_FD (vui->clib_file_index));
940       clib_file_del (&file_main, file_main.file_pool + vui->clib_file_index);
941     }
942
943   vu_log_debug (vui, "New client socket for vhost interface %d, fd %d",
944                 vui->sw_if_index, client_fd);
945   template.read_function = vhost_user_socket_read;
946   template.error_function = vhost_user_socket_error;
947   template.file_descriptor = client_fd;
948   template.private_data = vui - vhost_user_main.vhost_user_interfaces;
949   vui->clib_file_index = clib_file_add (&file_main, &template);
950   return 0;
951 }
952
953 static clib_error_t *
954 vhost_user_init (vlib_main_t * vm)
955 {
956   clib_error_t *error;
957   vhost_user_main_t *vum = &vhost_user_main;
958   vlib_thread_main_t *tm = vlib_get_thread_main ();
959
960   error = vlib_call_init_function (vm, ip4_init);
961   if (error)
962     return error;
963
964   vum->log_default = vlib_log_register_class ("vhost-user", 0);
965
966   vum->coalesce_frames = 32;
967   vum->coalesce_time = 1e-3;
968
969   vec_validate (vum->cpus, tm->n_vlib_mains - 1);
970
971   vhost_cpu_t *cpu;
972   vec_foreach (cpu, vum->cpus)
973   {
974     /* This is actually not necessary as validate already zeroes it
975      * Just keeping the loop here for later because I am lazy. */
976     cpu->rx_buffers_len = 0;
977   }
978
979   vum->random = random_default_seed ();
980
981   mhash_init_c_string (&vum->if_index_by_sock_name, sizeof (uword));
982
983   return 0;
984 }
985
986 VLIB_INIT_FUNCTION (vhost_user_init);
987
988 static uword
989 vhost_user_send_interrupt_process (vlib_main_t * vm,
990                                    vlib_node_runtime_t * rt, vlib_frame_t * f)
991 {
992   vhost_user_intf_t *vui;
993   f64 timeout = 3153600000.0 /* 100 years */ ;
994   uword event_type, *event_data = 0;
995   vhost_user_main_t *vum = &vhost_user_main;
996   u16 qid;
997   f64 now, poll_time_remaining;
998   f64 next_timeout;
999   u8 stop_timer = 0;
1000
1001   while (1)
1002     {
1003       poll_time_remaining =
1004         vlib_process_wait_for_event_or_clock (vm, timeout);
1005       event_type = vlib_process_get_events (vm, &event_data);
1006       vec_reset_length (event_data);
1007
1008       /*
1009        * Use the remaining timeout if it is less than coalesce time to avoid
1010        * resetting the existing timer in the middle of expiration
1011        */
1012       timeout = poll_time_remaining;
1013       if (vlib_process_suspend_time_is_zero (timeout) ||
1014           (timeout > vum->coalesce_time))
1015         timeout = vum->coalesce_time;
1016
1017       now = vlib_time_now (vm);
1018       switch (event_type)
1019         {
1020         case VHOST_USER_EVENT_STOP_TIMER:
1021           stop_timer = 1;
1022           break;
1023
1024         case VHOST_USER_EVENT_START_TIMER:
1025           stop_timer = 0;
1026           if (!vlib_process_suspend_time_is_zero (poll_time_remaining))
1027             break;
1028           /* fall through */
1029
1030         case ~0:
1031           /* *INDENT-OFF* */
1032           pool_foreach (vui, vum->vhost_user_interfaces, {
1033               next_timeout = timeout;
1034               for (qid = 0; qid < VHOST_VRING_MAX_N / 2; qid += 2)
1035                 {
1036                   vhost_user_vring_t *rxvq = &vui->vrings[qid];
1037                   vhost_user_vring_t *txvq = &vui->vrings[qid + 1];
1038
1039                   if (txvq->qid == -1)
1040                     continue;
1041                   if (txvq->n_since_last_int)
1042                     {
1043                       if (now >= txvq->int_deadline)
1044                         vhost_user_send_call (vm, txvq);
1045                       else
1046                         next_timeout = txvq->int_deadline - now;
1047                     }
1048
1049                   if (rxvq->n_since_last_int)
1050                     {
1051                       if (now >= rxvq->int_deadline)
1052                         vhost_user_send_call (vm, rxvq);
1053                       else
1054                         next_timeout = rxvq->int_deadline - now;
1055                     }
1056
1057                   if ((next_timeout < timeout) && (next_timeout > 0.0))
1058                     timeout = next_timeout;
1059                 }
1060           });
1061           /* *INDENT-ON* */
1062           break;
1063
1064         default:
1065           clib_warning ("BUG: unhandled event type %d", event_type);
1066           break;
1067         }
1068       /* No less than 1 millisecond */
1069       if (timeout < 1e-3)
1070         timeout = 1e-3;
1071       if (stop_timer)
1072         timeout = 3153600000.0;
1073     }
1074   return 0;
1075 }
1076
1077 /* *INDENT-OFF* */
1078 VLIB_REGISTER_NODE (vhost_user_send_interrupt_node) = {
1079     .function = vhost_user_send_interrupt_process,
1080     .type = VLIB_NODE_TYPE_PROCESS,
1081     .name = "vhost-user-send-interrupt-process",
1082 };
1083 /* *INDENT-ON* */
1084
1085 static uword
1086 vhost_user_process (vlib_main_t * vm,
1087                     vlib_node_runtime_t * rt, vlib_frame_t * f)
1088 {
1089   vhost_user_main_t *vum = &vhost_user_main;
1090   vhost_user_intf_t *vui;
1091   struct sockaddr_un sun;
1092   int sockfd;
1093   clib_file_t template = { 0 };
1094   f64 timeout = 3153600000.0 /* 100 years */ ;
1095   uword *event_data = 0;
1096
1097   sockfd = -1;
1098   sun.sun_family = AF_UNIX;
1099   template.read_function = vhost_user_socket_read;
1100   template.error_function = vhost_user_socket_error;
1101
1102   while (1)
1103     {
1104       vlib_process_wait_for_event_or_clock (vm, timeout);
1105       vlib_process_get_events (vm, &event_data);
1106       vec_reset_length (event_data);
1107
1108       timeout = 3.0;
1109
1110       /* *INDENT-OFF* */
1111       pool_foreach (vui, vum->vhost_user_interfaces, {
1112
1113           if (vui->unix_server_index == ~0) { //Nothing to do for server sockets
1114               if (vui->clib_file_index == ~0)
1115                 {
1116                   if ((sockfd < 0) &&
1117                       ((sockfd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0))
1118                     {
1119                       /*
1120                        * 1st time error or new error for this interface,
1121                        * spit out the message and record the error
1122                        */
1123                       if (!vui->sock_errno || (vui->sock_errno != errno))
1124                         {
1125                           clib_unix_warning
1126                             ("Error: Could not open unix socket for %s",
1127                              vui->sock_filename);
1128                           vui->sock_errno = errno;
1129                         }
1130                       continue;
1131                     }
1132
1133                   /* try to connect */
1134                   strncpy (sun.sun_path, (char *) vui->sock_filename,
1135                            sizeof (sun.sun_path) - 1);
1136
1137                   /* Avoid hanging VPP if the other end does not accept */
1138                   if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0)
1139                       clib_unix_warning ("fcntl");
1140
1141                   if (connect (sockfd, (struct sockaddr *) &sun,
1142                                sizeof (struct sockaddr_un)) == 0)
1143                     {
1144                       /* Set the socket to blocking as it was before */
1145                       if (fcntl(sockfd, F_SETFL, 0) < 0)
1146                         clib_unix_warning ("fcntl2");
1147
1148                       vui->sock_errno = 0;
1149                       template.file_descriptor = sockfd;
1150                       template.private_data =
1151                           vui - vhost_user_main.vhost_user_interfaces;
1152                       vui->clib_file_index = clib_file_add (&file_main, &template);
1153
1154                       /* This sockfd is considered consumed */
1155                       sockfd = -1;
1156                     }
1157                   else
1158                     {
1159                       vui->sock_errno = errno;
1160                     }
1161                 }
1162               else
1163                 {
1164                   /* check if socket is alive */
1165                   int error = 0;
1166                   socklen_t len = sizeof (error);
1167                   int fd = UNIX_GET_FD(vui->clib_file_index);
1168                   int retval =
1169                       getsockopt (fd, SOL_SOCKET, SO_ERROR, &error, &len);
1170
1171                   if (retval)
1172                     {
1173                       vu_log_debug (vui, "getsockopt returned %d", retval);
1174                       vhost_user_if_disconnect (vui);
1175                     }
1176                 }
1177           }
1178       });
1179       /* *INDENT-ON* */
1180     }
1181   return 0;
1182 }
1183
1184 /* *INDENT-OFF* */
1185 VLIB_REGISTER_NODE (vhost_user_process_node,static) = {
1186     .function = vhost_user_process,
1187     .type = VLIB_NODE_TYPE_PROCESS,
1188     .name = "vhost-user-process",
1189 };
1190 /* *INDENT-ON* */
1191
1192 /**
1193  * Disables and reset interface structure.
1194  * It can then be either init again, or removed from used interfaces.
1195  */
1196 static void
1197 vhost_user_term_if (vhost_user_intf_t * vui)
1198 {
1199   int q;
1200   vhost_user_main_t *vum = &vhost_user_main;
1201
1202   // disconnect interface sockets
1203   vhost_user_if_disconnect (vui);
1204   vhost_user_update_iface_state (vui);
1205
1206   for (q = 0; q < VHOST_VRING_MAX_N; q++)
1207     {
1208       // Remove existing queue mapping for the interface
1209       if (q & 1)
1210         {
1211           int rv;
1212           vnet_main_t *vnm = vnet_get_main ();
1213           vhost_user_vring_t *txvq = &vui->vrings[q];
1214
1215           if (txvq->qid != -1)
1216             {
1217               rv = vnet_hw_interface_unassign_rx_thread (vnm,
1218                                                          vui->hw_if_index,
1219                                                          q >> 1);
1220               if (rv)
1221                 vu_log_warn (vui, "unable to unassign interface %d, "
1222                              "queue %d: rc=%d", vui->hw_if_index, q >> 1, rv);
1223             }
1224         }
1225
1226       clib_mem_free ((void *) vui->vring_locks[q]);
1227     }
1228
1229   if (vui->unix_server_index != ~0)
1230     {
1231       //Close server socket
1232       clib_file_t *uf = pool_elt_at_index (file_main.file_pool,
1233                                            vui->unix_server_index);
1234       clib_file_del (&file_main, uf);
1235       vui->unix_server_index = ~0;
1236       unlink (vui->sock_filename);
1237     }
1238
1239   mhash_unset (&vum->if_index_by_sock_name, vui->sock_filename,
1240                &vui->if_index);
1241 }
1242
1243 int
1244 vhost_user_delete_if (vnet_main_t * vnm, vlib_main_t * vm, u32 sw_if_index)
1245 {
1246   vhost_user_main_t *vum = &vhost_user_main;
1247   vhost_user_intf_t *vui;
1248   int rv = 0;
1249   vnet_hw_interface_t *hwif;
1250   u16 qid;
1251
1252   if (!(hwif = vnet_get_sup_hw_interface (vnm, sw_if_index)) ||
1253       hwif->dev_class_index != vhost_user_device_class.index)
1254     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1255
1256   vui = pool_elt_at_index (vum->vhost_user_interfaces, hwif->dev_instance);
1257
1258   vu_log_debug (vui, "Deleting vhost-user interface %s (instance %d)",
1259                 hwif->name, hwif->dev_instance);
1260
1261   for (qid = 1; qid < VHOST_VRING_MAX_N / 2; qid += 2)
1262     {
1263       vhost_user_vring_t *txvq = &vui->vrings[qid];
1264
1265       if (txvq->qid == -1)
1266         continue;
1267       if ((vum->ifq_count > 0) &&
1268           ((txvq->mode == VNET_HW_INTERFACE_RX_MODE_INTERRUPT) ||
1269            (txvq->mode == VNET_HW_INTERFACE_RX_MODE_ADAPTIVE)))
1270         {
1271           vum->ifq_count--;
1272           // Stop the timer if there is no more interrupt interface/queue
1273           if ((vum->ifq_count == 0) &&
1274               (vum->coalesce_time > 0.0) && (vum->coalesce_frames > 0))
1275             {
1276               vlib_process_signal_event (vm,
1277                                          vhost_user_send_interrupt_node.index,
1278                                          VHOST_USER_EVENT_STOP_TIMER, 0);
1279               break;
1280             }
1281         }
1282     }
1283
1284   // Disable and reset interface
1285   vhost_user_term_if (vui);
1286
1287   // Reset renumbered iface
1288   if (hwif->dev_instance <
1289       vec_len (vum->show_dev_instance_by_real_dev_instance))
1290     vum->show_dev_instance_by_real_dev_instance[hwif->dev_instance] = ~0;
1291
1292   // Delete ethernet interface
1293   ethernet_delete_interface (vnm, vui->hw_if_index);
1294
1295   // Back to pool
1296   pool_put (vum->vhost_user_interfaces, vui);
1297
1298   return rv;
1299 }
1300
1301 static clib_error_t *
1302 vhost_user_exit (vlib_main_t * vm)
1303 {
1304   vnet_main_t *vnm = vnet_get_main ();
1305   vhost_user_main_t *vum = &vhost_user_main;
1306   vhost_user_intf_t *vui;
1307
1308   vlib_worker_thread_barrier_sync (vlib_get_main ());
1309   /* *INDENT-OFF* */
1310   pool_foreach (vui, vum->vhost_user_interfaces, {
1311       vhost_user_delete_if (vnm, vm, vui->sw_if_index);
1312   });
1313   /* *INDENT-ON* */
1314   vlib_worker_thread_barrier_release (vlib_get_main ());
1315   return 0;
1316 }
1317
1318 VLIB_MAIN_LOOP_EXIT_FUNCTION (vhost_user_exit);
1319
1320 /**
1321  * Open server unix socket on specified sock_filename.
1322  */
1323 static int
1324 vhost_user_init_server_sock (const char *sock_filename, int *sock_fd)
1325 {
1326   int rv = 0;
1327   struct sockaddr_un un = { };
1328   int fd;
1329   /* create listening socket */
1330   if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
1331     return VNET_API_ERROR_SYSCALL_ERROR_1;
1332
1333   un.sun_family = AF_UNIX;
1334   strncpy ((char *) un.sun_path, (char *) sock_filename,
1335            sizeof (un.sun_path) - 1);
1336
1337   /* remove if exists */
1338   unlink ((char *) sock_filename);
1339
1340   if (bind (fd, (struct sockaddr *) &un, sizeof (un)) == -1)
1341     {
1342       rv = VNET_API_ERROR_SYSCALL_ERROR_2;
1343       goto error;
1344     }
1345
1346   if (listen (fd, 1) == -1)
1347     {
1348       rv = VNET_API_ERROR_SYSCALL_ERROR_3;
1349       goto error;
1350     }
1351
1352   *sock_fd = fd;
1353   return 0;
1354
1355 error:
1356   close (fd);
1357   return rv;
1358 }
1359
1360 /**
1361  * Create ethernet interface for vhost user interface.
1362  */
1363 static void
1364 vhost_user_create_ethernet (vnet_main_t * vnm, vlib_main_t * vm,
1365                             vhost_user_intf_t * vui, u8 * hwaddress)
1366 {
1367   vhost_user_main_t *vum = &vhost_user_main;
1368   u8 hwaddr[6];
1369   clib_error_t *error;
1370
1371   /* create hw and sw interface */
1372   if (hwaddress)
1373     {
1374       clib_memcpy (hwaddr, hwaddress, 6);
1375     }
1376   else
1377     {
1378       random_u32 (&vum->random);
1379       clib_memcpy (hwaddr + 2, &vum->random, sizeof (vum->random));
1380       hwaddr[0] = 2;
1381       hwaddr[1] = 0xfe;
1382     }
1383
1384   error = ethernet_register_interface
1385     (vnm,
1386      vhost_user_device_class.index,
1387      vui - vum->vhost_user_interfaces /* device instance */ ,
1388      hwaddr /* ethernet address */ ,
1389      &vui->hw_if_index, 0 /* flag change */ );
1390
1391   if (error)
1392     clib_error_report (error);
1393 }
1394
1395 /*
1396  *  Initialize vui with specified attributes
1397  */
1398 static void
1399 vhost_user_vui_init (vnet_main_t * vnm,
1400                      vhost_user_intf_t * vui,
1401                      int server_sock_fd,
1402                      const char *sock_filename,
1403                      u64 feature_mask, u32 * sw_if_index)
1404 {
1405   vnet_sw_interface_t *sw;
1406   int q;
1407   vhost_user_main_t *vum = &vhost_user_main;
1408   vnet_hw_interface_t *hw;
1409
1410   hw = vnet_get_hw_interface (vnm, vui->hw_if_index);
1411   sw = vnet_get_hw_sw_interface (vnm, vui->hw_if_index);
1412   if (server_sock_fd != -1)
1413     {
1414       clib_file_t template = { 0 };
1415       template.read_function = vhost_user_socksvr_accept_ready;
1416       template.file_descriptor = server_sock_fd;
1417       template.private_data = vui - vum->vhost_user_interfaces; //hw index
1418       vui->unix_server_index = clib_file_add (&file_main, &template);
1419     }
1420   else
1421     {
1422       vui->unix_server_index = ~0;
1423     }
1424
1425   vui->sw_if_index = sw->sw_if_index;
1426   strncpy (vui->sock_filename, sock_filename,
1427            ARRAY_LEN (vui->sock_filename) - 1);
1428   vui->sock_errno = 0;
1429   vui->is_ready = 0;
1430   vui->feature_mask = feature_mask;
1431   vui->clib_file_index = ~0;
1432   vui->log_base_addr = 0;
1433   vui->if_index = vui - vum->vhost_user_interfaces;
1434   mhash_set_mem (&vum->if_index_by_sock_name, vui->sock_filename,
1435                  &vui->if_index, 0);
1436
1437   for (q = 0; q < VHOST_VRING_MAX_N; q++)
1438     vhost_user_vring_init (vui, q);
1439
1440   hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE;
1441   vnet_hw_interface_set_flags (vnm, vui->hw_if_index, 0);
1442
1443   if (sw_if_index)
1444     *sw_if_index = vui->sw_if_index;
1445
1446   for (q = 0; q < VHOST_VRING_MAX_N; q++)
1447     {
1448       vui->vring_locks[q] = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
1449                                                     CLIB_CACHE_LINE_BYTES);
1450       clib_memset ((void *) vui->vring_locks[q], 0, CLIB_CACHE_LINE_BYTES);
1451     }
1452
1453   vec_validate (vui->per_cpu_tx_qid,
1454                 vlib_get_thread_main ()->n_vlib_mains - 1);
1455   vhost_user_tx_thread_placement (vui);
1456 }
1457
1458 int
1459 vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
1460                       const char *sock_filename,
1461                       u8 is_server,
1462                       u32 * sw_if_index,
1463                       u64 feature_mask,
1464                       u8 renumber, u32 custom_dev_instance, u8 * hwaddr)
1465 {
1466   vhost_user_intf_t *vui = NULL;
1467   u32 sw_if_idx = ~0;
1468   int rv = 0;
1469   int server_sock_fd = -1;
1470   vhost_user_main_t *vum = &vhost_user_main;
1471   uword *if_index;
1472
1473   if (sock_filename == NULL || !(strlen (sock_filename) > 0))
1474     {
1475       return VNET_API_ERROR_INVALID_ARGUMENT;
1476     }
1477
1478   if_index = mhash_get (&vum->if_index_by_sock_name, (void *) sock_filename);
1479   if (if_index)
1480     {
1481       if (sw_if_index)
1482         {
1483           vui = &vum->vhost_user_interfaces[*if_index];
1484           *sw_if_index = vui->sw_if_index;
1485         }
1486       return VNET_API_ERROR_IF_ALREADY_EXISTS;
1487     }
1488
1489   if (is_server)
1490     {
1491       if ((rv =
1492            vhost_user_init_server_sock (sock_filename, &server_sock_fd)) != 0)
1493         {
1494           return rv;
1495         }
1496     }
1497
1498   /* Protect the uninitialized vui from being dispatched by rx/tx */
1499   vlib_worker_thread_barrier_sync (vm);
1500   pool_get (vhost_user_main.vhost_user_interfaces, vui);
1501   vhost_user_create_ethernet (vnm, vm, vui, hwaddr);
1502   vlib_worker_thread_barrier_release (vm);
1503
1504   vhost_user_vui_init (vnm, vui, server_sock_fd, sock_filename,
1505                        feature_mask, &sw_if_idx);
1506   vnet_sw_interface_set_mtu (vnm, vui->sw_if_index, 9000);
1507   vhost_user_rx_thread_placement (vui, 1);
1508
1509   if (renumber)
1510     vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
1511
1512   if (sw_if_index)
1513     *sw_if_index = sw_if_idx;
1514
1515   // Process node must connect
1516   vlib_process_signal_event (vm, vhost_user_process_node.index, 0, 0);
1517
1518   return rv;
1519 }
1520
1521 int
1522 vhost_user_modify_if (vnet_main_t * vnm, vlib_main_t * vm,
1523                       const char *sock_filename,
1524                       u8 is_server,
1525                       u32 sw_if_index,
1526                       u64 feature_mask, u8 renumber, u32 custom_dev_instance)
1527 {
1528   vhost_user_main_t *vum = &vhost_user_main;
1529   vhost_user_intf_t *vui = NULL;
1530   u32 sw_if_idx = ~0;
1531   int server_sock_fd = -1;
1532   int rv = 0;
1533   vnet_hw_interface_t *hwif;
1534   uword *if_index;
1535
1536   if (!(hwif = vnet_get_sup_hw_interface (vnm, sw_if_index)) ||
1537       hwif->dev_class_index != vhost_user_device_class.index)
1538     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1539
1540   if (sock_filename == NULL || !(strlen (sock_filename) > 0))
1541     return VNET_API_ERROR_INVALID_ARGUMENT;
1542
1543   vui = vec_elt_at_index (vum->vhost_user_interfaces, hwif->dev_instance);
1544
1545   /*
1546    * Disallow changing the interface to have the same path name
1547    * as other interface
1548    */
1549   if_index = mhash_get (&vum->if_index_by_sock_name, (void *) sock_filename);
1550   if (if_index && (*if_index != vui->if_index))
1551     return VNET_API_ERROR_IF_ALREADY_EXISTS;
1552
1553   // First try to open server socket
1554   if (is_server)
1555     if ((rv = vhost_user_init_server_sock (sock_filename,
1556                                            &server_sock_fd)) != 0)
1557       return rv;
1558
1559   vhost_user_term_if (vui);
1560   vhost_user_vui_init (vnm, vui, server_sock_fd,
1561                        sock_filename, feature_mask, &sw_if_idx);
1562
1563   if (renumber)
1564     vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
1565
1566   // Process node must connect
1567   vlib_process_signal_event (vm, vhost_user_process_node.index, 0, 0);
1568
1569   return rv;
1570 }
1571
1572 clib_error_t *
1573 vhost_user_connect_command_fn (vlib_main_t * vm,
1574                                unformat_input_t * input,
1575                                vlib_cli_command_t * cmd)
1576 {
1577   unformat_input_t _line_input, *line_input = &_line_input;
1578   u8 *sock_filename = NULL;
1579   u32 sw_if_index;
1580   u8 is_server = 0;
1581   u64 feature_mask = (u64) ~ (0ULL);
1582   u8 renumber = 0;
1583   u32 custom_dev_instance = ~0;
1584   u8 hwaddr[6];
1585   u8 *hw = NULL;
1586   clib_error_t *error = NULL;
1587
1588   /* Get a line of input. */
1589   if (!unformat_user (input, unformat_line_input, line_input))
1590     return 0;
1591
1592   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1593     {
1594       if (unformat (line_input, "socket %s", &sock_filename))
1595         ;
1596       else if (unformat (line_input, "server"))
1597         is_server = 1;
1598       else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
1599         ;
1600       else
1601         if (unformat
1602             (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
1603         hw = hwaddr;
1604       else if (unformat (line_input, "renumber %d", &custom_dev_instance))
1605         {
1606           renumber = 1;
1607         }
1608       else
1609         {
1610           error = clib_error_return (0, "unknown input `%U'",
1611                                      format_unformat_error, line_input);
1612           goto done;
1613         }
1614     }
1615
1616   vnet_main_t *vnm = vnet_get_main ();
1617
1618   int rv;
1619   if ((rv = vhost_user_create_if (vnm, vm, (char *) sock_filename,
1620                                   is_server, &sw_if_index, feature_mask,
1621                                   renumber, custom_dev_instance, hw)))
1622     {
1623       error = clib_error_return (0, "vhost_user_create_if returned %d", rv);
1624       goto done;
1625     }
1626
1627   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
1628                    sw_if_index);
1629
1630 done:
1631   vec_free (sock_filename);
1632   unformat_free (line_input);
1633
1634   return error;
1635 }
1636
1637 clib_error_t *
1638 vhost_user_delete_command_fn (vlib_main_t * vm,
1639                               unformat_input_t * input,
1640                               vlib_cli_command_t * cmd)
1641 {
1642   unformat_input_t _line_input, *line_input = &_line_input;
1643   u32 sw_if_index = ~0;
1644   vnet_main_t *vnm = vnet_get_main ();
1645   clib_error_t *error = NULL;
1646
1647   /* Get a line of input. */
1648   if (!unformat_user (input, unformat_line_input, line_input))
1649     return 0;
1650
1651   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1652     {
1653       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
1654         ;
1655       else if (unformat
1656                (line_input, "%U", unformat_vnet_sw_interface, vnm,
1657                 &sw_if_index))
1658         {
1659           vnet_hw_interface_t *hwif =
1660             vnet_get_sup_hw_interface (vnm, sw_if_index);
1661           if (hwif == NULL ||
1662               vhost_user_device_class.index != hwif->dev_class_index)
1663             {
1664               error = clib_error_return (0, "Not a vhost interface");
1665               goto done;
1666             }
1667         }
1668       else
1669         {
1670           error = clib_error_return (0, "unknown input `%U'",
1671                                      format_unformat_error, line_input);
1672           goto done;
1673         }
1674     }
1675
1676   vhost_user_delete_if (vnm, vm, sw_if_index);
1677
1678 done:
1679   unformat_free (line_input);
1680
1681   return error;
1682 }
1683
1684 int
1685 vhost_user_dump_ifs (vnet_main_t * vnm, vlib_main_t * vm,
1686                      vhost_user_intf_details_t ** out_vuids)
1687 {
1688   int rv = 0;
1689   vhost_user_main_t *vum = &vhost_user_main;
1690   vhost_user_intf_t *vui;
1691   vhost_user_intf_details_t *r_vuids = NULL;
1692   vhost_user_intf_details_t *vuid = NULL;
1693   u32 *hw_if_indices = 0;
1694   vnet_hw_interface_t *hi;
1695   u8 *s = NULL;
1696   int i;
1697
1698   if (!out_vuids)
1699     return -1;
1700
1701   pool_foreach (vui, vum->vhost_user_interfaces,
1702                 vec_add1 (hw_if_indices, vui->hw_if_index);
1703     );
1704
1705   for (i = 0; i < vec_len (hw_if_indices); i++)
1706     {
1707       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
1708       vui = pool_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
1709
1710       vec_add2 (r_vuids, vuid, 1);
1711       vuid->sw_if_index = vui->sw_if_index;
1712       vuid->virtio_net_hdr_sz = vui->virtio_net_hdr_sz;
1713       vuid->features = vui->features;
1714       vuid->num_regions = vui->nregions;
1715       vuid->is_server = vui->unix_server_index != ~0;
1716       vuid->sock_errno = vui->sock_errno;
1717       strncpy ((char *) vuid->sock_filename, (char *) vui->sock_filename,
1718                sizeof (vuid->sock_filename));
1719       vuid->sock_filename[ARRAY_LEN (vuid->sock_filename) - 1] = '\0';
1720       s = format (s, "%v%c", hi->name, 0);
1721
1722       strncpy ((char *) vuid->if_name, (char *) s,
1723                ARRAY_LEN (vuid->if_name) - 1);
1724       _vec_len (s) = 0;
1725     }
1726
1727   vec_free (s);
1728   vec_free (hw_if_indices);
1729
1730   *out_vuids = r_vuids;
1731
1732   return rv;
1733 }
1734
1735 clib_error_t *
1736 show_vhost_user_command_fn (vlib_main_t * vm,
1737                             unformat_input_t * input,
1738                             vlib_cli_command_t * cmd)
1739 {
1740   clib_error_t *error = 0;
1741   vnet_main_t *vnm = vnet_get_main ();
1742   vhost_user_main_t *vum = &vhost_user_main;
1743   vhost_user_intf_t *vui;
1744   u32 hw_if_index, *hw_if_indices = 0;
1745   vnet_hw_interface_t *hi;
1746   u16 qid;
1747   u32 ci;
1748   int i, j, q;
1749   int show_descr = 0;
1750   struct feat_struct
1751   {
1752     u8 bit;
1753     char *str;
1754   };
1755   struct feat_struct *feat_entry;
1756
1757   static struct feat_struct feat_array[] = {
1758 #define _(s,b) { .str = #s, .bit = b, },
1759     foreach_virtio_net_feature
1760 #undef _
1761     {.str = NULL}
1762   };
1763
1764 #define foreach_protocol_feature \
1765   _(VHOST_USER_PROTOCOL_F_MQ) \
1766   _(VHOST_USER_PROTOCOL_F_LOG_SHMFD)
1767
1768   static struct feat_struct proto_feat_array[] = {
1769 #define _(s) { .str = #s, .bit = s},
1770     foreach_protocol_feature
1771 #undef _
1772     {.str = NULL}
1773   };
1774
1775   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1776     {
1777       if (unformat
1778           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1779         {
1780           hi = vnet_get_hw_interface (vnm, hw_if_index);
1781           if (vhost_user_device_class.index != hi->dev_class_index)
1782             {
1783               error = clib_error_return (0, "unknown input `%U'",
1784                                          format_unformat_error, input);
1785               goto done;
1786             }
1787           vec_add1 (hw_if_indices, hw_if_index);
1788         }
1789       else if (unformat (input, "descriptors") || unformat (input, "desc"))
1790         show_descr = 1;
1791       else
1792         {
1793           error = clib_error_return (0, "unknown input `%U'",
1794                                      format_unformat_error, input);
1795           goto done;
1796         }
1797     }
1798   if (vec_len (hw_if_indices) == 0)
1799     {
1800       pool_foreach (vui, vum->vhost_user_interfaces,
1801                     vec_add1 (hw_if_indices, vui->hw_if_index);
1802         );
1803     }
1804   vlib_cli_output (vm, "Virtio vhost-user interfaces");
1805   vlib_cli_output (vm, "Global:\n  coalesce frames %d time %e",
1806                    vum->coalesce_frames, vum->coalesce_time);
1807   vlib_cli_output (vm, "  number of rx virtqueues in interrupt mode: %d",
1808                    vum->ifq_count);
1809
1810   for (i = 0; i < vec_len (hw_if_indices); i++)
1811     {
1812       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
1813       vui = pool_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
1814       vlib_cli_output (vm, "Interface: %U (ifindex %d)",
1815                        format_vnet_hw_if_index_name, vnm, hw_if_indices[i],
1816                        hw_if_indices[i]);
1817
1818       vlib_cli_output (vm, "virtio_net_hdr_sz %d\n"
1819                        " features mask (0x%llx): \n"
1820                        " features (0x%llx): \n",
1821                        vui->virtio_net_hdr_sz, vui->feature_mask,
1822                        vui->features);
1823
1824       feat_entry = (struct feat_struct *) &feat_array;
1825       while (feat_entry->str)
1826         {
1827           if (vui->features & (1ULL << feat_entry->bit))
1828             vlib_cli_output (vm, "   %s (%d)", feat_entry->str,
1829                              feat_entry->bit);
1830           feat_entry++;
1831         }
1832
1833       vlib_cli_output (vm, "  protocol features (0x%llx)",
1834                        vui->protocol_features);
1835       feat_entry = (struct feat_struct *) &proto_feat_array;
1836       while (feat_entry->str)
1837         {
1838           if (vui->protocol_features & (1ULL << feat_entry->bit))
1839             vlib_cli_output (vm, "   %s (%d)", feat_entry->str,
1840                              feat_entry->bit);
1841           feat_entry++;
1842         }
1843
1844       vlib_cli_output (vm, "\n");
1845
1846       vlib_cli_output (vm, " socket filename %s type %s errno \"%s\"\n\n",
1847                        vui->sock_filename,
1848                        (vui->unix_server_index != ~0) ? "server" : "client",
1849                        strerror (vui->sock_errno));
1850
1851       vlib_cli_output (vm, " rx placement: ");
1852
1853       for (qid = 1; qid < VHOST_VRING_MAX_N / 2; qid += 2)
1854         {
1855           vnet_main_t *vnm = vnet_get_main ();
1856           uword thread_index;
1857           vnet_hw_interface_rx_mode mode;
1858           vhost_user_vring_t *txvq = &vui->vrings[qid];
1859
1860           if (txvq->qid == -1)
1861             continue;
1862           thread_index =
1863             vnet_get_device_input_thread_index (vnm, vui->hw_if_index,
1864                                                 qid >> 1);
1865           vnet_hw_interface_get_rx_mode (vnm, vui->hw_if_index, qid >> 1,
1866                                          &mode);
1867           vlib_cli_output (vm, "   thread %d on vring %d, %U\n",
1868                            thread_index, qid,
1869                            format_vnet_hw_interface_rx_mode, mode);
1870         }
1871
1872       vlib_cli_output (vm, " tx placement: %s\n",
1873                        vui->use_tx_spinlock ? "spin-lock" : "lock-free");
1874
1875       vec_foreach_index (ci, vui->per_cpu_tx_qid)
1876       {
1877         vlib_cli_output (vm, "   thread %d on vring %d\n", ci,
1878                          VHOST_VRING_IDX_RX (vui->per_cpu_tx_qid[ci]));
1879       }
1880
1881       vlib_cli_output (vm, "\n");
1882
1883       vlib_cli_output (vm, " Memory regions (total %d)\n", vui->nregions);
1884
1885       if (vui->nregions)
1886         {
1887           vlib_cli_output (vm,
1888                            " region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr\n");
1889           vlib_cli_output (vm,
1890                            " ====== ===== ================== ================== ================== ================== ==================\n");
1891         }
1892       for (j = 0; j < vui->nregions; j++)
1893         {
1894           vlib_cli_output (vm,
1895                            "  %d     %-5d 0x%016lx 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
1896                            j, vui->region_mmap_fd[j],
1897                            vui->regions[j].guest_phys_addr,
1898                            vui->regions[j].memory_size,
1899                            vui->regions[j].userspace_addr,
1900                            vui->regions[j].mmap_offset,
1901                            pointer_to_uword (vui->region_mmap_addr[j]));
1902         }
1903       for (q = 0; q < VHOST_VRING_MAX_N; q++)
1904         {
1905           if (!vui->vrings[q].started)
1906             continue;
1907
1908           vlib_cli_output (vm, "\n Virtqueue %d (%s%s)\n", q,
1909                            (q & 1) ? "RX" : "TX",
1910                            vui->vrings[q].enabled ? "" : " disabled");
1911
1912           vlib_cli_output (vm,
1913                            "  qsz %d last_avail_idx %d last_used_idx %d\n",
1914                            vui->vrings[q].qsz_mask + 1,
1915                            vui->vrings[q].last_avail_idx,
1916                            vui->vrings[q].last_used_idx);
1917
1918           if (vui->vrings[q].avail && vui->vrings[q].used)
1919             vlib_cli_output (vm,
1920                              "  avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
1921                              vui->vrings[q].avail->flags,
1922                              vui->vrings[q].avail->idx,
1923                              vui->vrings[q].used->flags,
1924                              vui->vrings[q].used->idx);
1925
1926           int kickfd = UNIX_GET_FD (vui->vrings[q].kickfd_idx);
1927           int callfd = UNIX_GET_FD (vui->vrings[q].callfd_idx);
1928           vlib_cli_output (vm, "  kickfd %d callfd %d errfd %d\n",
1929                            kickfd, callfd, vui->vrings[q].errfd);
1930
1931           if (show_descr)
1932             {
1933               vlib_cli_output (vm, "\n  descriptor table:\n");
1934               vlib_cli_output (vm,
1935                                "   id          addr         len  flags  next      user_addr\n");
1936               vlib_cli_output (vm,
1937                                "  ===== ================== ===== ====== ===== ==================\n");
1938               for (j = 0; j < vui->vrings[q].qsz_mask + 1; j++)
1939                 {
1940                   u32 mem_hint = 0;
1941                   vlib_cli_output (vm,
1942                                    "  %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
1943                                    j, vui->vrings[q].desc[j].addr,
1944                                    vui->vrings[q].desc[j].len,
1945                                    vui->vrings[q].desc[j].flags,
1946                                    vui->vrings[q].desc[j].next,
1947                                    pointer_to_uword (map_guest_mem
1948                                                      (vui,
1949                                                       vui->vrings[q].desc[j].
1950                                                       addr, &mem_hint)));
1951                 }
1952             }
1953         }
1954       vlib_cli_output (vm, "\n");
1955     }
1956 done:
1957   vec_free (hw_if_indices);
1958   return error;
1959 }
1960
1961 /*
1962  * CLI functions
1963  */
1964
1965 /*?
1966  * Create a vHost User interface. Once created, a new virtual interface
1967  * will exist with the name '<em>VirtualEthernet0/0/x</em>', where '<em>x</em>'
1968  * is the next free index.
1969  *
1970  * There are several parameters associated with a vHost interface:
1971  *
1972  * - <b>socket <socket-filename></b> - Name of the linux socket used by hypervisor
1973  * and VPP to manage the vHost interface. If in '<em>server</em>' mode, VPP will
1974  * create the socket if it does not already exist. If in '<em>client</em>' mode,
1975  * hypervisor will create the socket if it does not already exist. The VPP code
1976  * is indifferent to the file location. However, if SELinux is enabled, then the
1977  * socket needs to be created in '<em>/var/run/vpp/</em>'.
1978  *
1979  * - <b>server</b> - Optional flag to indicate that VPP should be the server for
1980  * the linux socket. If not provided, VPP will be the client. In '<em>server</em>'
1981  *  mode, the VM can be reset without tearing down the vHost Interface. In
1982  * '<em>client</em>' mode, VPP can be reset without bringing down the VM and
1983  * tearing down the vHost Interface.
1984  *
1985  * - <b>feature-mask <hex></b> - Optional virtio/vhost feature set negotiated at
1986  * startup. <b>This is intended for degugging only.</b> It is recommended that this
1987  * parameter not be used except by experienced users. By default, all supported
1988  * features will be advertised. Otherwise, provide the set of features desired.
1989  *   - 0x000008000 (15) - VIRTIO_NET_F_MRG_RXBUF
1990  *   - 0x000020000 (17) - VIRTIO_NET_F_CTRL_VQ
1991  *   - 0x000200000 (21) - VIRTIO_NET_F_GUEST_ANNOUNCE
1992  *   - 0x000400000 (22) - VIRTIO_NET_F_MQ
1993  *   - 0x004000000 (26) - VHOST_F_LOG_ALL
1994  *   - 0x008000000 (27) - VIRTIO_F_ANY_LAYOUT
1995  *   - 0x010000000 (28) - VIRTIO_F_INDIRECT_DESC
1996  *   - 0x040000000 (30) - VHOST_USER_F_PROTOCOL_FEATURES
1997  *   - 0x100000000 (32) - VIRTIO_F_VERSION_1
1998  *
1999  * - <b>hwaddr <mac-addr></b> - Optional ethernet address, can be in either
2000  * X:X:X:X:X:X unix or X.X.X cisco format.
2001  *
2002  * - <b>renumber <dev_instance></b> - Optional parameter which allows the instance
2003  * in the name to be specified. If instance already exists, name will be used
2004  * anyway and multiple instances will have the same name. Use with caution.
2005  *
2006  * @cliexpar
2007  * Example of how to create a vhost interface with VPP as the client and all features enabled:
2008  * @cliexstart{create vhost-user socket /var/run/vpp/vhost1.sock}
2009  * VirtualEthernet0/0/0
2010  * @cliexend
2011  * Example of how to create a vhost interface with VPP as the server and with just
2012  * multiple queues enabled:
2013  * @cliexstart{create vhost-user socket /var/run/vpp/vhost2.sock server feature-mask 0x40400000}
2014  * VirtualEthernet0/0/1
2015  * @cliexend
2016  * Once the vHost interface is created, enable the interface using:
2017  * @cliexcmd{set interface state VirtualEthernet0/0/0 up}
2018 ?*/
2019 /* *INDENT-OFF* */
2020 VLIB_CLI_COMMAND (vhost_user_connect_command, static) = {
2021     .path = "create vhost-user",
2022     .short_help = "create vhost-user socket <socket-filename> [server] "
2023     "[feature-mask <hex>] [hwaddr <mac-addr>] [renumber <dev_instance>] ",
2024     .function = vhost_user_connect_command_fn,
2025     .is_mp_safe = 1,
2026 };
2027 /* *INDENT-ON* */
2028
2029 /*?
2030  * Delete a vHost User interface using the interface name or the
2031  * software interface index. Use the '<em>show interface</em>'
2032  * command to determine the software interface index. On deletion,
2033  * the linux socket will not be deleted.
2034  *
2035  * @cliexpar
2036  * Example of how to delete a vhost interface by name:
2037  * @cliexcmd{delete vhost-user VirtualEthernet0/0/1}
2038  * Example of how to delete a vhost interface by software interface index:
2039  * @cliexcmd{delete vhost-user sw_if_index 1}
2040 ?*/
2041 /* *INDENT-OFF* */
2042 VLIB_CLI_COMMAND (vhost_user_delete_command, static) = {
2043     .path = "delete vhost-user",
2044     .short_help = "delete vhost-user {<interface> | sw_if_index <sw_idx>}",
2045     .function = vhost_user_delete_command_fn,
2046 };
2047
2048 /*?
2049  * Display the attributes of a single vHost User interface (provide interface
2050  * name), multiple vHost User interfaces (provide a list of interface names seperated
2051  * by spaces) or all Vhost User interfaces (omit an interface name to display all
2052  * vHost interfaces).
2053  *
2054  * @cliexpar
2055  * @parblock
2056  * Example of how to display a vhost interface:
2057  * @cliexstart{show vhost-user VirtualEthernet0/0/0}
2058  * Virtio vhost-user interfaces
2059  * Global:
2060  *   coalesce frames 32 time 1e-3
2061  * Interface: VirtualEthernet0/0/0 (ifindex 1)
2062  * virtio_net_hdr_sz 12
2063  *  features mask (0xffffffffffffffff):
2064  *  features (0x50408000):
2065  *    VIRTIO_NET_F_MRG_RXBUF (15)
2066  *    VIRTIO_NET_F_MQ (22)
2067  *    VIRTIO_F_INDIRECT_DESC (28)
2068  *    VHOST_USER_F_PROTOCOL_FEATURES (30)
2069  *   protocol features (0x3)
2070  *    VHOST_USER_PROTOCOL_F_MQ (0)
2071  *    VHOST_USER_PROTOCOL_F_LOG_SHMFD (1)
2072  *
2073  *  socket filename /var/run/vpp/vhost1.sock type client errno "Success"
2074  *
2075  * rx placement:
2076  *    thread 1 on vring 1
2077  *    thread 1 on vring 5
2078  *    thread 2 on vring 3
2079  *    thread 2 on vring 7
2080  *  tx placement: spin-lock
2081  *    thread 0 on vring 0
2082  *    thread 1 on vring 2
2083  *    thread 2 on vring 0
2084  *
2085  * Memory regions (total 2)
2086  * region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr
2087  * ====== ===== ================== ================== ================== ================== ==================
2088  *   0     60    0x0000000000000000 0x00000000000a0000 0x00002aaaaac00000 0x0000000000000000 0x00002aab2b400000
2089  *   1     61    0x00000000000c0000 0x000000003ff40000 0x00002aaaaacc0000 0x00000000000c0000 0x00002aababcc0000
2090  *
2091  *  Virtqueue 0 (TX)
2092  *   qsz 256 last_avail_idx 0 last_used_idx 0
2093  *   avail.flags 1 avail.idx 128 used.flags 1 used.idx 0
2094  *   kickfd 62 callfd 64 errfd -1
2095  *
2096  *  Virtqueue 1 (RX)
2097  *   qsz 256 last_avail_idx 0 last_used_idx 0
2098  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
2099  *   kickfd 65 callfd 66 errfd -1
2100  *
2101  *  Virtqueue 2 (TX)
2102  *   qsz 256 last_avail_idx 0 last_used_idx 0
2103  *   avail.flags 1 avail.idx 128 used.flags 1 used.idx 0
2104  *   kickfd 63 callfd 70 errfd -1
2105  *
2106  *  Virtqueue 3 (RX)
2107  *   qsz 256 last_avail_idx 0 last_used_idx 0
2108  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
2109  *   kickfd 72 callfd 74 errfd -1
2110  *
2111  *  Virtqueue 4 (TX disabled)
2112  *   qsz 256 last_avail_idx 0 last_used_idx 0
2113  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
2114  *   kickfd 76 callfd 78 errfd -1
2115  *
2116  *  Virtqueue 5 (RX disabled)
2117  *   qsz 256 last_avail_idx 0 last_used_idx 0
2118  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
2119  *   kickfd 80 callfd 82 errfd -1
2120  *
2121  *  Virtqueue 6 (TX disabled)
2122  *   qsz 256 last_avail_idx 0 last_used_idx 0
2123  *  avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
2124  *   kickfd 84 callfd 86 errfd -1
2125  *
2126  *  Virtqueue 7 (RX disabled)
2127  *   qsz 256 last_avail_idx 0 last_used_idx 0
2128  *   avail.flags 1 avail.idx 0 used.flags 1 used.idx 0
2129  *   kickfd 88 callfd 90 errfd -1
2130  *
2131  * @cliexend
2132  *
2133  * The optional '<em>descriptors</em>' parameter will display the same output as
2134  * the previous example but will include the descriptor table for each queue.
2135  * The output is truncated below:
2136  * @cliexstart{show vhost-user VirtualEthernet0/0/0 descriptors}
2137  * Virtio vhost-user interfaces
2138  * Global:
2139  *   coalesce frames 32 time 1e-3
2140  * Interface: VirtualEthernet0/0/0 (ifindex 1)
2141  * virtio_net_hdr_sz 12
2142  *  features mask (0xffffffffffffffff):
2143  *  features (0x50408000):
2144  *    VIRTIO_NET_F_MRG_RXBUF (15)
2145  *    VIRTIO_NET_F_MQ (22)
2146  * :
2147  *  Virtqueue 0 (TX)
2148  *   qsz 256 last_avail_idx 0 last_used_idx 0
2149  *   avail.flags 1 avail.idx 128 used.flags 1 used.idx 0
2150  *   kickfd 62 callfd 64 errfd -1
2151  *
2152  *   descriptor table:
2153  *    id          addr         len  flags  next      user_addr
2154  *   ===== ================== ===== ====== ===== ==================
2155  *   0     0x0000000010b6e974 2060  0x0002 1     0x00002aabbc76e974
2156  *   1     0x0000000010b6e034 2060  0x0002 2     0x00002aabbc76e034
2157  *   2     0x0000000010b6d6f4 2060  0x0002 3     0x00002aabbc76d6f4
2158  *   3     0x0000000010b6cdb4 2060  0x0002 4     0x00002aabbc76cdb4
2159  *   4     0x0000000010b6c474 2060  0x0002 5     0x00002aabbc76c474
2160  *   5     0x0000000010b6bb34 2060  0x0002 6     0x00002aabbc76bb34
2161  *   6     0x0000000010b6b1f4 2060  0x0002 7     0x00002aabbc76b1f4
2162  *   7     0x0000000010b6a8b4 2060  0x0002 8     0x00002aabbc76a8b4
2163  *   8     0x0000000010b69f74 2060  0x0002 9     0x00002aabbc769f74
2164  *   9     0x0000000010b69634 2060  0x0002 10    0x00002aabbc769634
2165  *   10    0x0000000010b68cf4 2060  0x0002 11    0x00002aabbc768cf4
2166  * :
2167  *   249   0x0000000000000000 0     0x0000 250   0x00002aab2b400000
2168  *   250   0x0000000000000000 0     0x0000 251   0x00002aab2b400000
2169  *   251   0x0000000000000000 0     0x0000 252   0x00002aab2b400000
2170  *   252   0x0000000000000000 0     0x0000 253   0x00002aab2b400000
2171  *   253   0x0000000000000000 0     0x0000 254   0x00002aab2b400000
2172  *   254   0x0000000000000000 0     0x0000 255   0x00002aab2b400000
2173  *   255   0x0000000000000000 0     0x0000 32768 0x00002aab2b400000
2174  *
2175  *  Virtqueue 1 (RX)
2176  *   qsz 256 last_avail_idx 0 last_used_idx 0
2177  * :
2178  * @cliexend
2179  * @endparblock
2180 ?*/
2181 /* *INDENT-OFF* */
2182 VLIB_CLI_COMMAND (show_vhost_user_command, static) = {
2183     .path = "show vhost-user",
2184     .short_help = "show vhost-user [<interface> [<interface> [..]]] [descriptors]",
2185     .function = show_vhost_user_command_fn,
2186 };
2187 /* *INDENT-ON* */
2188
2189
2190 static clib_error_t *
2191 vhost_user_config (vlib_main_t * vm, unformat_input_t * input)
2192 {
2193   vhost_user_main_t *vum = &vhost_user_main;
2194
2195   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2196     {
2197       if (unformat (input, "coalesce-frames %d", &vum->coalesce_frames))
2198         ;
2199       else if (unformat (input, "coalesce-time %f", &vum->coalesce_time))
2200         ;
2201       else if (unformat (input, "dont-dump-memory"))
2202         vum->dont_dump_vhost_user_memory = 1;
2203       else
2204         return clib_error_return (0, "unknown input `%U'",
2205                                   format_unformat_error, input);
2206     }
2207
2208   return 0;
2209 }
2210
2211 /* vhost-user { ... } configuration. */
2212 VLIB_CONFIG_FUNCTION (vhost_user_config, "vhost-user");
2213
2214 void
2215 vhost_user_unmap_all (void)
2216 {
2217   vhost_user_main_t *vum = &vhost_user_main;
2218   vhost_user_intf_t *vui;
2219
2220   if (vum->dont_dump_vhost_user_memory)
2221     {
2222       pool_foreach (vui, vum->vhost_user_interfaces,
2223                     unmap_all_mem_regions (vui);
2224         );
2225     }
2226 }
2227
2228 /*
2229  * fd.io coding-style-patch-verification: ON
2230  *
2231  * Local Variables:
2232  * eval: (c-set-style "gnu")
2233  * End:
2234  */