vhost-user: Reset virt-queue info when a vhost interface is disconnected.
[vpp.git] / vnet / vnet / devices / dpdk / vhost_user.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <assert.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <sys/stat.h>
19 #include <sys/vfs.h>
20
21 #include <vlib/vlib.h>
22 #include <vlib/unix/unix.h>
23
24 #include <vnet/vnet.h>
25 #include <vppinfra/vec.h>
26 #include <vppinfra/error.h>
27 #include <vppinfra/format.h>
28
29 #include <vnet/ethernet/ethernet.h>
30 #include <vnet/devices/dpdk/dpdk.h>
31
32 #include <vnet/devices/virtio/vhost-user.h>
33
34 #define VHOST_USER_DEBUG_SOCKET 0
35
36 #if VHOST_USER_DEBUG_SOCKET == 1
37 #define DBG_SOCK(args...) clib_warning(args);
38 #else
39 #define DBG_SOCK(args...)
40 #endif
41
42 static const char *vhost_message_str[] __attribute__((unused)) = {
43     [VHOST_USER_NONE] = "VHOST_USER_NONE",
44     [VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES",
45     [VHOST_USER_SET_FEATURES] = "VHOST_USER_SET_FEATURES",
46     [VHOST_USER_SET_OWNER] = "VHOST_USER_SET_OWNER",
47     [VHOST_USER_RESET_OWNER] = "VHOST_USER_RESET_OWNER",
48     [VHOST_USER_SET_MEM_TABLE] = "VHOST_USER_SET_MEM_TABLE",
49     [VHOST_USER_SET_LOG_BASE] = "VHOST_USER_SET_LOG_BASE",
50     [VHOST_USER_SET_LOG_FD] = "VHOST_USER_SET_LOG_FD",
51     [VHOST_USER_SET_VRING_NUM] = "VHOST_USER_SET_VRING_NUM",
52     [VHOST_USER_SET_VRING_ADDR] = "VHOST_USER_SET_VRING_ADDR",
53     [VHOST_USER_SET_VRING_BASE] = "VHOST_USER_SET_VRING_BASE",
54     [VHOST_USER_GET_VRING_BASE] = "VHOST_USER_GET_VRING_BASE",
55     [VHOST_USER_SET_VRING_KICK] = "VHOST_USER_SET_VRING_KICK",
56     [VHOST_USER_SET_VRING_CALL] = "VHOST_USER_SET_VRING_CALL",
57     [VHOST_USER_SET_VRING_ERR]  = "VHOST_USER_SET_VRING_ERR",
58     [VHOST_USER_GET_PROTOCOL_FEATURES]  = "VHOST_USER_GET_PROTOCOL_FEATURES",
59     [VHOST_USER_SET_PROTOCOL_FEATURES]  = "VHOST_USER_SET_PROTOCOL_FEATURES",
60     [VHOST_USER_GET_QUEUE_NUM]  = "VHOST_USER_GET_QUEUE_NUM",
61     [VHOST_USER_SET_VRING_ENABLE]  = "VHOST_USER_SET_VRING_ENABLE",
62 };
63
64 static int dpdk_vhost_user_set_vring_enable(u32 hw_if_index,
65     u8 idx, int enable);
66
67 /*
68  * DPDK vhost-user functions 
69  */
70
71 /* portions taken from dpdk 
72  *   BSD LICENSE
73  *
74  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
75  *   All rights reserved.
76  *
77  *   Redistribution and use in source and binary forms, with or without
78  *   modification, are permitted provided that the following conditions
79  *   are met:
80  *
81  *     * Redistributions of source code must retain the above copyright
82  *       notice, this list of conditions and the following disclaimer.
83  *     * Redistributions in binary form must reproduce the above copyright
84  *       notice, this list of conditions and the following disclaimer in
85  *       the documentation and/or other materials provided with the
86  *       distribution.
87  *     * Neither the name of Intel Corporation nor the names of its
88  *       contributors may be used to endorse or promote products derived
89  *       from this software without specific prior written permission.
90  *
91  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
92  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
93  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
94  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
95  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
96  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
97  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
98  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
99  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
100  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
101  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
102  */
103
104
105 static uword
106 qva_to_vva(struct virtio_net *dev, uword qemu_va)
107 {
108   struct virtio_memory_regions *region;
109   uword vhost_va = 0;
110   uint32_t regionidx = 0;
111
112   /* Find the region where the address lives. */
113   for (regionidx = 0; regionidx < dev->mem->nregions; regionidx++) {
114     region = &dev->mem->regions[regionidx];
115     if ((qemu_va >= region->userspace_address) &&
116       (qemu_va <= region->userspace_address +
117       region->memory_size)) {
118       vhost_va = qemu_va + region->guest_phys_address +
119         region->address_offset -
120         region->userspace_address;
121       break;
122     }
123   }
124   return vhost_va;
125 }
126
127 static dpdk_device_t *
128 dpdk_vhost_user_device_from_hw_if_index(u32 hw_if_index)
129 {
130   vnet_main_t *vnm = vnet_get_main();
131   dpdk_main_t * dm = &dpdk_main;
132   vnet_hw_interface_t * hi = vnet_get_hw_interface (vnm, hw_if_index);
133   dpdk_device_t * xd = vec_elt_at_index (dm->devices, hi->dev_instance);
134
135   if (xd->dev_type != VNET_DPDK_DEV_VHOST_USER)
136     return 0;
137
138   return xd;
139 }
140
141 static dpdk_device_t *
142 dpdk_vhost_user_device_from_sw_if_index(u32 sw_if_index)
143 {
144   vnet_main_t *vnm = vnet_get_main();
145   vnet_sw_interface_t * sw = vnet_get_sw_interface (vnm, sw_if_index);
146   ASSERT (sw->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
147
148   return dpdk_vhost_user_device_from_hw_if_index(sw->hw_if_index);
149 }
150
151 static void stop_processing_packets(u32 hw_if_index, u8 idx)
152 {
153   dpdk_device_t *xd =
154     dpdk_vhost_user_device_from_hw_if_index(hw_if_index);
155   assert(xd);
156   xd->vu_vhost_dev.virtqueue[idx]->enabled = 0;
157 }
158
159 static void disable_interface(dpdk_device_t * xd)
160 {
161   u8 idx;
162   int numqs = xd->vu_vhost_dev.virt_qp_nb * VIRTIO_QNUM;
163   for (idx = 0;  idx < numqs; idx++)
164     xd->vu_vhost_dev.virtqueue[idx]->enabled = 0;
165
166   xd->vu_is_running = 0;
167 }
168
169 static inline void * map_guest_mem(dpdk_device_t * xd, uword addr)
170 {
171   dpdk_vu_intf_t * vui = xd->vu_intf;
172   struct virtio_memory * mem = xd->vu_vhost_dev.mem;
173   int i;
174   for (i=0; i<mem->nregions; i++) {
175     if ((mem->regions[i].guest_phys_address <= addr) &&
176        ((mem->regions[i].guest_phys_address + mem->regions[i].memory_size) > addr)) {
177          return (void *) ((uword)vui->region_addr[i] + addr - (uword)mem->regions[i].guest_phys_address);
178        }
179   }
180   DBG_SOCK("failed to map guest mem addr %lx", addr);
181   return 0;
182 }
183
184 static clib_error_t *
185 dpdk_create_vhost_user_if_internal (u32 * hw_if_index, u32 if_id, u8 *hwaddr)
186 {
187   dpdk_main_t * dm = &dpdk_main;
188   vlib_main_t * vm = vlib_get_main();
189   vlib_thread_main_t * tm = vlib_get_thread_main();
190   vnet_sw_interface_t * sw;
191   clib_error_t * error;
192   dpdk_device_and_queue_t * dq;
193   int num_qpairs = 1;
194   dpdk_vu_intf_t *vui = NULL;
195
196   num_qpairs = dm->use_rss < 1 ? 1 : tm->n_vlib_mains;
197
198   dpdk_device_t * xd = NULL;
199   u8 addr[6];
200   int j;
201
202   vlib_worker_thread_barrier_sync (vm);
203
204   int inactive_cnt = vec_len(dm->vu_inactive_interfaces_device_index);
205   // if there are any inactive ifaces
206   if (inactive_cnt > 0) {
207     // take last
208     u32 vui_idx = dm->vu_inactive_interfaces_device_index[inactive_cnt - 1];
209     if (vec_len(dm->devices) > vui_idx) {
210       xd = vec_elt_at_index (dm->devices, vui_idx);
211       if (xd->dev_type == VNET_DPDK_DEV_VHOST_USER) {
212           DBG_SOCK("reusing inactive vhost-user interface sw_if_index %d", xd->vlib_sw_if_index);
213       } else {
214           clib_warning("error: inactive vhost-user interface sw_if_index %d not VHOST_USER type!",
215                   xd->vlib_sw_if_index);
216           // reset so new interface is created
217           xd = NULL;
218       }
219     }
220     // "remove" from inactive list
221     _vec_len(dm->vu_inactive_interfaces_device_index) -= 1;
222   }
223
224   if (xd) {
225       // existing interface used - do not overwrite if_id if not needed
226       if (if_id != (u32)~0)
227           xd->vu_if_id = if_id;
228
229       // reset virtqueues
230       vui = xd->vu_intf;
231       for (j = 0; j < num_qpairs * VIRTIO_QNUM; j++) {
232           memset(xd->vu_vhost_dev.virtqueue[j], 0, sizeof(struct vhost_virtqueue));
233           xd->vu_vhost_dev.virtqueue[j]->kickfd = -1; 
234           xd->vu_vhost_dev.virtqueue[j]->callfd = -1; 
235           xd->vu_vhost_dev.virtqueue[j]->backend = -1; 
236           vui->vrings[j].packets = 0;
237           vui->vrings[j].bytes = 0;
238        }
239
240       // reset lockp
241       dpdk_device_lock_free(xd);
242       dpdk_device_lock_init(xd);
243
244       // reset tx vectors
245       for (j = 0; j < tm->n_vlib_mains; j++)
246         {
247           vec_validate_ha (xd->tx_vectors[j], DPDK_TX_RING_SIZE,
248                            sizeof(tx_ring_hdr_t), CLIB_CACHE_LINE_BYTES);
249           vec_reset_length (xd->tx_vectors[j]);
250         }
251
252       // reset rx vector
253       for (j = 0; j < xd->rx_q_used; j++)
254         {
255           vec_validate_aligned (xd->rx_vectors[j], VLIB_FRAME_SIZE-1,
256                                 CLIB_CACHE_LINE_BYTES);
257           vec_reset_length (xd->rx_vectors[j]);
258         }
259   } else {
260       // vui was not retrieved from inactive ifaces - create new
261       vec_add2_aligned (dm->devices, xd, 1, CLIB_CACHE_LINE_BYTES);
262       xd->dev_type = VNET_DPDK_DEV_VHOST_USER;
263       xd->rx_q_used = num_qpairs;
264       xd->tx_q_used = num_qpairs;
265       xd->vu_vhost_dev.virt_qp_nb = num_qpairs;
266
267       vec_validate_aligned (xd->rx_vectors, xd->rx_q_used, CLIB_CACHE_LINE_BYTES);
268
269       if (if_id == (u32)~0)
270           xd->vu_if_id = dm->next_vu_if_id++;
271       else
272           xd->vu_if_id = if_id;
273
274       xd->device_index = xd - dm->devices;
275       xd->per_interface_next_index = ~0;
276       xd->vu_intf = clib_mem_alloc (sizeof(*(xd->vu_intf)));
277
278       xd->vu_vhost_dev.mem = clib_mem_alloc (sizeof(struct virtio_memory) +
279                                              VHOST_MEMORY_MAX_NREGIONS *
280                                              sizeof(struct virtio_memory_regions));
281
282       /* Will be set when guest sends VHOST_USER_SET_MEM_TABLE cmd */
283       xd->vu_vhost_dev.mem->nregions = 0;
284
285       /* 
286        * New virtqueue structure is an array of VHOST_MAX_QUEUE_PAIRS * 2
287        * We need to allocate numq pairs.
288        */
289       vui = xd->vu_intf;
290       for (j = 0; j < num_qpairs * VIRTIO_QNUM; j++) {
291           xd->vu_vhost_dev.virtqueue[j] = clib_mem_alloc (sizeof(struct vhost_virtqueue));
292           memset(xd->vu_vhost_dev.virtqueue[j], 0, sizeof(struct vhost_virtqueue));
293           xd->vu_vhost_dev.virtqueue[j]->kickfd = -1; 
294           xd->vu_vhost_dev.virtqueue[j]->callfd = -1; 
295           xd->vu_vhost_dev.virtqueue[j]->backend = -1; 
296           vui->vrings[j].packets = 0;
297           vui->vrings[j].bytes = 0;
298       }
299
300       dpdk_device_lock_init(xd);
301
302       DBG_SOCK("tm->n_vlib_mains: %d. TX %d, RX: %d, num_qpairs: %d, Lock: %p",
303         tm->n_vlib_mains, xd->tx_q_used, xd->rx_q_used, num_qpairs, xd->lockp);
304
305       vec_validate_aligned (xd->tx_vectors, tm->n_vlib_mains,
306                             CLIB_CACHE_LINE_BYTES);
307
308       for (j = 0; j < tm->n_vlib_mains; j++)
309         {
310           vec_validate_ha (xd->tx_vectors[j], DPDK_TX_RING_SIZE,
311                            sizeof(tx_ring_hdr_t), CLIB_CACHE_LINE_BYTES);
312           vec_reset_length (xd->tx_vectors[j]);
313         }
314
315       // reset rx vector
316       for (j = 0; j < xd->rx_q_used; j++)
317         {
318           vec_validate_aligned (xd->rx_vectors[j], VLIB_FRAME_SIZE-1,
319                                 CLIB_CACHE_LINE_BYTES);
320           vec_reset_length (xd->rx_vectors[j]);
321         }
322
323       vec_validate_aligned (xd->frames, tm->n_vlib_mains,
324                             CLIB_CACHE_LINE_BYTES);
325
326   }
327   /*
328    * Generate random MAC address for the interface
329    */
330   if (hwaddr) {
331     clib_memcpy(addr, hwaddr, sizeof(addr));
332   } else {
333     f64 now = vlib_time_now(vm);
334     u32 rnd;
335     rnd = (u32) (now * 1e6);
336     rnd = random_u32 (&rnd);
337
338     clib_memcpy (addr+2, &rnd, sizeof(rnd));
339     addr[0] = 2;
340     addr[1] = 0xfe;
341   }
342
343   error = ethernet_register_interface
344     (dm->vnet_main,
345      dpdk_device_class.index,
346      xd->device_index,
347      /* ethernet address */ addr,
348      &xd->vlib_hw_if_index,
349      0);
350
351   if (error)
352     return error;
353
354   sw = vnet_get_hw_sw_interface (dm->vnet_main, xd->vlib_hw_if_index);
355   xd->vlib_sw_if_index = sw->sw_if_index;
356
357   *hw_if_index = xd->vlib_hw_if_index;
358
359   DBG_SOCK("xd->device_index: %d, dm->input_cpu_count: %d, "
360     "dm->input_cpu_first_index: %d\n", xd->device_index,
361     dm->input_cpu_count, dm->input_cpu_first_index);
362
363   int q, next_cpu = 0;
364   for (q = 0; q < num_qpairs; q++) {
365       int cpu = dm->input_cpu_first_index +
366         (next_cpu % dm->input_cpu_count);
367
368       unsigned lcore = vlib_worker_threads[cpu].dpdk_lcore_id;
369       vec_validate(xd->cpu_socket_id_by_queue, q);
370       xd->cpu_socket_id_by_queue[q] = rte_lcore_to_socket_id(lcore);
371
372       vec_add2(dm->devices_by_cpu[cpu], dq, 1);
373       dq->device = xd->device_index;
374       dq->queue_id = q;
375       DBG_SOCK("CPU for %d = %d. QID: %d", *hw_if_index, cpu, dq->queue_id);
376
377       // start polling if it was not started yet (because of no phys ifaces)
378       if (tm->n_vlib_mains == 1 && dpdk_input_node.state != VLIB_NODE_STATE_POLLING)
379         vlib_node_set_state (vm, dpdk_input_node.index, VLIB_NODE_STATE_POLLING);
380
381       if (tm->n_vlib_mains > 1)
382         vlib_node_set_state (vlib_mains[cpu], dpdk_input_node.index,
383                              VLIB_NODE_STATE_POLLING);
384       next_cpu++;
385   }
386
387   vlib_worker_thread_barrier_release (vm);
388   return 0;
389 }
390
391 #if RTE_VERSION >= RTE_VERSION_NUM(16, 4, 0, 0)
392 static long get_huge_page_size(int fd)
393 {
394   struct statfs s;
395   fstatfs(fd, &s);
396   return s.f_bsize;
397 }
398 #endif
399
400 static clib_error_t *
401 dpdk_vhost_user_set_protocol_features(u32 hw_if_index, u64 prot_features)
402 {
403   dpdk_device_t * xd;
404   xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index);
405   assert(xd);
406   xd->vu_vhost_dev.protocol_features = prot_features;
407   return 0;
408 }
409
410 static clib_error_t *
411 dpdk_vhost_user_get_features(u32 hw_if_index, u64 * features)
412 {
413   *features = rte_vhost_feature_get();
414
415 #if RTE_VERSION >= RTE_VERSION_NUM(16, 4, 0, 0)
416 #define OFFLOAD_FEATURES ((1ULL << VIRTIO_NET_F_HOST_TSO4) | \
417                 (1ULL << VIRTIO_NET_F_HOST_TSO6) | \
418                 (1ULL << VIRTIO_NET_F_CSUM)    | \
419                 (1ULL << VIRTIO_NET_F_GUEST_CSUM) | \
420                 (1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
421                 (1ULL << VIRTIO_NET_F_GUEST_TSO6))
422
423   /* These are not suppoted as bridging/tunneling VHOST
424    * interfaces with hardware interfaces/drivers that does
425    * not support offloading breaks L4 traffic.
426    */
427   *features &= (~OFFLOAD_FEATURES);
428 #endif
429
430   DBG_SOCK("supported features: 0x%lx", *features);
431   return 0;
432 }
433
434 static clib_error_t *
435 dpdk_vhost_user_set_features(u32 hw_if_index, u64 features)
436 {
437   dpdk_device_t * xd;
438   u16 hdr_len = sizeof(struct virtio_net_hdr);
439
440
441   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
442     clib_warning("not a vhost-user interface");
443     return 0;
444   }
445
446   xd->vu_vhost_dev.features = features;
447
448   if (xd->vu_vhost_dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))
449     hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
450
451   int numqs = VIRTIO_QNUM;
452   u8 idx;
453   int prot_feature = features &
454         (1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
455   numqs = xd->vu_vhost_dev.virt_qp_nb * VIRTIO_QNUM;
456   for (idx = 0; idx < numqs; idx++) {
457       xd->vu_vhost_dev.virtqueue[idx]->vhost_hlen = hdr_len;
458       /*
459        * Spec says, if F_PROTOCOL_FEATURE is not set by the
460        * slave, then all the vrings should start off as
461        * enabled. If slave negotiates F_PROTOCOL_FEATURE, then
462        * slave is responsible to enable it.
463        */
464       if (! prot_feature)
465           dpdk_vhost_user_set_vring_enable(hw_if_index, idx, 1);
466   }
467
468   return 0;
469 }
470
471 static clib_error_t *
472 dpdk_vhost_user_set_mem_table(u32 hw_if_index, vhost_user_memory_t * vum, int fd[])
473 {
474   struct virtio_memory * mem;
475   int i;
476   dpdk_device_t * xd;
477   dpdk_vu_intf_t * vui;
478
479   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
480     clib_warning("not a vhost-user interface");
481     return 0;
482   }
483
484   vui = xd->vu_intf;
485   mem = xd->vu_vhost_dev.mem;
486
487   mem->nregions = vum->nregions;
488
489   for (i=0; i < mem->nregions; i++) {
490     u64 mapped_size, mapped_address;
491
492     mem->regions[i].guest_phys_address     = vum->regions[i].guest_phys_addr;
493     mem->regions[i].guest_phys_address_end = vum->regions[i].guest_phys_addr +
494                                              vum->regions[i].memory_size;
495     mem->regions[i].memory_size            = vum->regions[i].memory_size;
496     mem->regions[i].userspace_address      = vum->regions[i].userspace_addr;
497
498     mapped_size = mem->regions[i].memory_size + vum->regions[i].mmap_offset;
499     mapped_address = pointer_to_uword(mmap(NULL, mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0));
500
501     if (uword_to_pointer(mapped_address, void*) == MAP_FAILED)
502     {
503       clib_warning("mmap error");
504       return 0;
505     }
506
507     mapped_address +=  vum->regions[i].mmap_offset;
508     vui->region_addr[i] = mapped_address;
509     vui->region_fd[i] = fd[i];
510     vui->region_offset[i] = vum->regions[i].mmap_offset;
511     mem->regions[i].address_offset = mapped_address - mem->regions[i].guest_phys_address;
512
513     DBG_SOCK("map memory region %d addr 0x%lx off 0x%lx len 0x%lx",
514       i, vui->region_addr[i], vui->region_offset[i], mapped_size);
515
516     if (vum->regions[i].guest_phys_addr == 0) {
517       mem->base_address = vum->regions[i].userspace_addr;
518       mem->mapped_address = mem->regions[i].address_offset;
519     }
520   }
521
522   disable_interface(xd);
523   return 0;
524 }
525
526 static clib_error_t *
527 dpdk_vhost_user_set_vring_num(u32 hw_if_index, u8 idx, u32 num)
528 {
529   dpdk_device_t * xd;
530   struct vhost_virtqueue *vq;
531
532   DBG_SOCK("idx %u num %u", idx, num);
533
534   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
535     clib_warning("not a vhost-user interface");
536     return 0;
537   }
538   vq = xd->vu_vhost_dev.virtqueue[idx];
539   vq->size = num;
540
541   stop_processing_packets(hw_if_index, idx);
542
543   return 0;
544 }
545
546 static clib_error_t *
547 dpdk_vhost_user_set_vring_addr(u32 hw_if_index, u8 idx, uword desc, \
548     uword used, uword avail, uword log)
549 {
550   dpdk_device_t * xd;
551   struct vhost_virtqueue *vq;
552
553   DBG_SOCK("idx %u desc 0x%lx used 0x%lx avail 0x%lx log 0x%lx",
554     idx, desc, used, avail, log);
555
556   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
557     clib_warning("not a vhost-user interface");
558     return 0;
559   }
560   vq = xd->vu_vhost_dev.virtqueue[idx];
561
562   vq->desc = (struct vring_desc *) qva_to_vva(&xd->vu_vhost_dev, desc);
563   vq->used = (struct vring_used *) qva_to_vva(&xd->vu_vhost_dev, used);
564   vq->avail = (struct vring_avail *) qva_to_vva(&xd->vu_vhost_dev, avail);
565 #if RTE_VERSION >= RTE_VERSION_NUM(16, 4, 0, 0)
566   vq->log_guest_addr = log;
567 #endif
568
569   if (!(vq->desc && vq->used && vq->avail)) {
570     clib_warning("falied to set vring addr");
571   }
572
573   if (vq->last_used_idx != vq->used->idx) {
574     clib_warning("last_used_idx (%u) and vq->used->idx (%u) mismatches; "
575                  "some packets maybe resent for Tx and dropped for Rx",
576                  vq->last_used_idx, vq->used->idx);
577       vq->last_used_idx     = vq->used->idx;
578       vq->last_used_idx_res = vq->used->idx;
579   }
580
581   /*
582    * Inform the guest that there is no need to inform (kick) the
583    * host when it adds buffers. kick results in vmexit and will
584    * incur performance degradation.
585    *
586    * The below function sets a flag in used table. Therefore,
587    * should be initialized after initializing vq->used.
588    */
589   rte_vhost_enable_guest_notification(&xd->vu_vhost_dev, idx, 0);
590   stop_processing_packets(hw_if_index, idx);
591
592   return 0;
593 }
594
595 static clib_error_t *
596 dpdk_vhost_user_get_vring_base(u32 hw_if_index, u8 idx, u32 * num)
597 {
598   dpdk_device_t * xd;
599   struct vhost_virtqueue *vq;
600
601   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
602     clib_warning("not a vhost-user interface");
603     return 0;
604   }
605
606   vq = xd->vu_vhost_dev.virtqueue[idx];
607   *num = vq->last_used_idx;
608
609 /*
610  * From spec:
611  * Client must start ring upon receiving a kick
612  * (that is, detecting that file descriptor is readable)
613  * on the descriptor specified by VHOST_USER_SET_VRING_KICK,
614  * and stop ring upon receiving VHOST_USER_GET_VRING_BASE.
615  */
616   DBG_SOCK("Stopping vring Q %u of device %d", idx, hw_if_index);
617   dpdk_vu_intf_t *vui = xd->vu_intf;
618   vui->vrings[idx].enabled = 0; /* Reset local copy */
619   vui->vrings[idx].callfd = -1; /* Reset FD */
620   vq->enabled = 0;
621   vq->desc = NULL;
622   vq->used = NULL;
623   vq->avail = NULL;
624 #if RTE_VERSION >= RTE_VERSION_NUM(16, 4, 0, 0)
625   vq->log_guest_addr = 0;
626 #endif
627
628   /* Check if all Qs are disabled */
629   int numqs = xd->vu_vhost_dev.virt_qp_nb * VIRTIO_QNUM;
630   for (idx = 0;  idx < numqs; idx++) {
631     if (xd->vu_vhost_dev.virtqueue[idx]->enabled)
632         break;
633   }
634
635   /* If all vrings are disabed then disable device */
636   if (idx == numqs)  {
637       DBG_SOCK("Device %d disabled", hw_if_index);
638       xd->vu_is_running = 0;
639   }
640
641   return 0;
642 }
643
644 static clib_error_t *
645 dpdk_vhost_user_set_vring_base(u32 hw_if_index, u8 idx, u32 num)
646 {
647   dpdk_device_t * xd;
648   struct vhost_virtqueue *vq;
649
650   DBG_SOCK("idx %u num %u", idx, num);
651
652   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
653     clib_warning("not a vhost-user interface");
654     return 0;
655   }
656
657   vq = xd->vu_vhost_dev.virtqueue[idx];
658   vq->last_used_idx = num;
659   vq->last_used_idx_res = num;
660
661   stop_processing_packets(hw_if_index, idx);
662
663   return 0;
664 }
665
666 static clib_error_t *
667 dpdk_vhost_user_set_vring_kick(u32 hw_if_index, u8 idx, int fd)
668 {
669   dpdk_main_t * dm = &dpdk_main;
670   dpdk_device_t * xd;
671   dpdk_vu_vring *vring;
672   struct vhost_virtqueue *vq0, *vq1, *vq;
673   int index, vu_is_running = 0;
674
675   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
676     clib_warning("not a vhost-user interface");
677     return 0;
678   }
679
680   vq = xd->vu_vhost_dev.virtqueue[idx];
681   vq->kickfd = fd;
682
683   vring = &xd->vu_intf->vrings[idx];
684   vq->enabled = (vq->desc && vq->avail && vq->used && vring->enabled) ? 1 : 0;
685
686   /*
687    * Set xd->vu_is_running if at least one pair of
688    * RX/TX queues are enabled.
689    */
690   int numqs = VIRTIO_QNUM;
691   numqs = xd->vu_vhost_dev.virt_qp_nb * VIRTIO_QNUM;
692
693   for (index = 0; index < numqs; index += 2) {
694     vq0 = xd->vu_vhost_dev.virtqueue[index]; /* RX */
695     vq1 = xd->vu_vhost_dev.virtqueue[index + 1]; /* TX */
696     if (vq0->enabled && vq1->enabled)
697     {
698         vu_is_running = 1;
699         break;
700     }
701   }
702   DBG_SOCK("SET_VRING_KICK - idx %d, running %d, fd: %d",
703     idx, vu_is_running, fd);
704
705   xd->vu_is_running = vu_is_running;
706   if (xd->vu_is_running && xd->admin_up) {
707     vnet_hw_interface_set_flags (dm->vnet_main,
708       xd->vlib_hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP |
709       ETH_LINK_FULL_DUPLEX );
710   }
711
712   return 0;
713 }
714
715 static int
716 dpdk_vhost_user_set_vring_enable(u32 hw_if_index, u8 idx, int enable)
717 {
718   dpdk_device_t * xd;
719   struct vhost_virtqueue *vq;
720   dpdk_vu_intf_t *vui;
721
722   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
723     clib_warning("not a vhost-user interface");
724     return 0;
725   }
726
727   vui = xd->vu_intf;
728   /*
729    * Guest vhost driver wrongly enables queue before
730    * setting the vring address. Therefore, save a
731    * local copy. Reflect it in vq structure if addresses
732    * are set. If not, vq will be enabled when vring
733    * is kicked.
734    */
735   vui->vrings[idx].enabled = enable; /* Save local copy */
736
737   int numqs = xd->vu_vhost_dev.virt_qp_nb * VIRTIO_QNUM;
738   while (numqs--) {
739     if (! vui->vrings[numqs].enabled)
740         break;
741   }
742
743   if (numqs == -1) /* All Qs are enabled */
744     xd->need_txlock = 0;
745   else
746     xd->need_txlock = 1;
747
748   vq = xd->vu_vhost_dev.virtqueue[idx];
749   if (vq->desc && vq->avail && vq->used)
750     xd->vu_vhost_dev.virtqueue[idx]->enabled = enable;
751
752   return 0;
753 }
754
755 static clib_error_t * dpdk_vhost_user_callfd_read_ready (unix_file_t * uf)
756 {
757   __attribute__((unused)) int n;
758   u8 buff[8];
759   n = read(uf->file_descriptor, ((char*)&buff), 8);
760   return 0;
761 }
762
763 static clib_error_t *
764 dpdk_vhost_user_set_vring_call(u32 hw_if_index, u8 idx, int fd)
765 {
766   dpdk_device_t * xd;
767   struct vhost_virtqueue *vq;
768   unix_file_t template = {0};
769
770   DBG_SOCK("SET_VRING_CALL - idx %d, fd %d", idx, fd);
771
772   if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_index))) {
773     clib_warning("not a vhost-user interface");
774     return 0;
775   }
776
777   dpdk_vu_intf_t *vui = xd->vu_intf;
778
779   /* if there is old fd, delete it */
780   if (vui->vrings[idx].callfd > 0) {
781     unix_file_t * uf = pool_elt_at_index (unix_main.file_pool,
782       vui->vrings[idx].callfd_idx);
783     unix_file_del (&unix_main, uf);
784   }
785   vui->vrings[idx].callfd = fd;
786   template.read_function = dpdk_vhost_user_callfd_read_ready;
787   template.file_descriptor = fd;
788   vui->vrings[idx].callfd_idx = unix_file_add (&unix_main, &template);
789
790   vq = xd->vu_vhost_dev.virtqueue[idx];
791   vq->callfd = -1; /* We use locally saved vring->callfd; */
792
793   return 0;
794 }
795
796 u8
797 dpdk_vhost_user_want_interrupt(dpdk_device_t *xd, int idx)
798 {
799     dpdk_vu_intf_t *vui = xd->vu_intf;
800     ASSERT(vui != NULL);
801
802     if (PREDICT_FALSE(vui->num_vrings <= 0))
803         return 0;
804
805     dpdk_vu_vring *vring = &(vui->vrings[idx]);
806     struct vhost_virtqueue *vq = xd->vu_vhost_dev.virtqueue[idx];
807
808     /* return if vm is interested in interrupts */
809     return (vring->callfd > 0) && !(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT);
810 }
811
812 void
813 dpdk_vhost_user_send_interrupt(vlib_main_t * vm, dpdk_device_t * xd, int idx)
814 {
815     dpdk_main_t * dm = &dpdk_main;
816     dpdk_vu_intf_t *vui = xd->vu_intf;
817     ASSERT(vui != NULL);
818
819     if (PREDICT_FALSE(vui->num_vrings <= 0))
820         return;
821
822     dpdk_vu_vring *vring = &(vui->vrings[idx]);
823     struct vhost_virtqueue *vq = xd->vu_vhost_dev.virtqueue[idx];
824
825     /* if vm is interested in interrupts */
826     if((vring->callfd > 0) && !(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
827         eventfd_write(vring->callfd, (eventfd_t)1);
828         vring->n_since_last_int = 0;
829         vring->int_deadline = vlib_time_now(vm) + dm->conf->vhost_coalesce_time;
830     }
831 }
832
833 /*
834  * vhost-user interface management functions 
835  */
836
837 // initialize vui with specified attributes
838 static void 
839 dpdk_vhost_user_vui_init(vnet_main_t * vnm,
840                          dpdk_device_t *xd, int sockfd,
841                          const char * sock_filename,
842                          u8 is_server, u64 feature_mask,
843                          u32 * sw_if_index)
844 {
845   dpdk_vu_intf_t *vui = xd->vu_intf;
846   memset(vui, 0, sizeof(*vui));
847
848   vui->unix_fd = sockfd;
849   vui->num_vrings = xd->vu_vhost_dev.virt_qp_nb * VIRTIO_QNUM;
850   DBG_SOCK("dpdk_vhost_user_vui_init VRINGS: %d", vui->num_vrings);
851   vui->sock_is_server = is_server;
852   strncpy(vui->sock_filename, sock_filename, ARRAY_LEN(vui->sock_filename)-1);
853   vui->sock_errno = 0;
854   vui->is_up = 0;
855   vui->feature_mask = feature_mask;
856   vui->active = 1;
857   vui->unix_file_index = ~0;
858
859   vnet_hw_interface_set_flags (vnm, xd->vlib_hw_if_index,  0);
860
861   if (sw_if_index)
862       *sw_if_index = xd->vlib_sw_if_index;
863 }
864
865 // register vui and start polling on it
866 static void 
867 dpdk_vhost_user_vui_register(vlib_main_t * vm, dpdk_device_t *xd)
868 {
869   dpdk_main_t * dm = &dpdk_main;
870   dpdk_vu_intf_t *vui = xd->vu_intf;
871
872   hash_set (dm->vu_sw_if_index_by_listener_fd, vui->unix_fd,
873             xd->vlib_sw_if_index);
874 }
875
876 static void dpdk_unmap_all_mem_regions(dpdk_device_t * xd)
877 {
878   int i, r;
879   dpdk_vu_intf_t *vui = xd->vu_intf;
880   struct virtio_memory * mem = xd->vu_vhost_dev.mem;
881
882   for (i=0; i<mem->nregions; i++) {
883     if (vui->region_addr[i] != -1) {
884
885       long page_sz = get_huge_page_size(vui->region_fd[i]);
886
887       ssize_t map_sz = (mem->regions[i].memory_size +
888         vui->region_offset[i] + page_sz) & ~(page_sz - 1);
889
890       r = munmap((void *)(vui->region_addr[i] - vui->region_offset[i]), map_sz);
891
892       DBG_SOCK("unmap memory region %d addr 0x%lx off 0x%lx len 0x%lx page_sz 0x%x",
893         i, vui->region_addr[i], vui->region_offset[i], map_sz, page_sz);
894
895       vui->region_addr[i]= -1;
896
897       if (r == -1) {
898         clib_unix_warning("failed to unmap memory region");
899       }
900       close(vui->region_fd[i]);
901     }
902   }
903   mem->nregions = 0;
904 }
905
906 static inline void
907 dpdk_vhost_user_if_disconnect(dpdk_device_t * xd)
908 {
909     dpdk_vu_intf_t *vui = xd->vu_intf;
910     vnet_main_t * vnm = vnet_get_main();
911     dpdk_main_t * dm = &dpdk_main;
912     struct vhost_virtqueue *vq;
913     int q;
914
915     xd->admin_up = 0;
916     vnet_hw_interface_set_flags (vnm, xd->vlib_hw_if_index,  0);
917
918     if (vui->unix_file_index != ~0) {
919         unix_file_del (&unix_main, unix_main.file_pool + vui->unix_file_index);
920         vui->unix_file_index = ~0;
921     }
922
923     hash_unset(dm->vu_sw_if_index_by_sock_fd, vui->unix_fd);
924     hash_unset(dm->vu_sw_if_index_by_listener_fd, vui->unix_fd);
925     close(vui->unix_fd);
926     vui->unix_fd = -1;
927     vui->is_up = 0;
928
929     for (q = 0; q < vui->num_vrings; q++) {
930         vq = xd->vu_vhost_dev.virtqueue[q];
931         vui->vrings[q].enabled = 0; /* Reset local copy */
932         vui->vrings[q].callfd = -1; /* Reset FD */
933         vq->enabled = 0;
934 #if RTE_VERSION >= RTE_VERSION_NUM(16, 4, 0, 0)
935         vq->log_guest_addr = 0;
936 #endif
937         vq->desc = NULL;
938         vq->used = NULL;
939         vq->avail = NULL;
940     }
941     xd->vu_is_running = 0;
942
943     dpdk_unmap_all_mem_regions(xd);
944     DBG_SOCK("interface ifindex %d disconnected", xd->vlib_sw_if_index);
945 }
946
947 static clib_error_t * dpdk_vhost_user_socket_read (unix_file_t * uf)
948 {
949   int n;
950   int fd, number_of_fds = 0;
951   int fds[VHOST_MEMORY_MAX_NREGIONS];
952   vhost_user_msg_t msg;
953   struct msghdr mh;
954   struct iovec iov[1];
955   dpdk_main_t * dm = &dpdk_main;
956   dpdk_device_t *xd;
957   dpdk_vu_intf_t *vui;
958   struct cmsghdr *cmsg;
959   uword * p;
960   u8 q;
961   vnet_main_t * vnm = vnet_get_main();
962
963   p = hash_get (dm->vu_sw_if_index_by_sock_fd, uf->file_descriptor);
964   if (p == 0) {
965       DBG_SOCK ("FD %d doesn't belong to any interface",
966                     uf->file_descriptor);
967       return 0;
968     }
969   else
970       xd = dpdk_vhost_user_device_from_sw_if_index(p[0]);
971
972   ASSERT(xd != NULL);
973   vui = xd->vu_intf;
974
975   char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))];
976
977   memset(&mh, 0, sizeof(mh));
978   memset(control, 0, sizeof(control));
979
980   /* set the payload */
981   iov[0].iov_base = (void *) &msg;
982   iov[0].iov_len = VHOST_USER_MSG_HDR_SZ;
983
984   mh.msg_iov = iov;
985   mh.msg_iovlen = 1;
986   mh.msg_control = control;
987   mh.msg_controllen = sizeof(control);
988
989   n = recvmsg(uf->file_descriptor, &mh, 0);
990
991   if (n != VHOST_USER_MSG_HDR_SZ)
992     goto close_socket;
993
994   if (mh.msg_flags & MSG_CTRUNC) {
995     goto close_socket;
996   }
997
998   cmsg = CMSG_FIRSTHDR(&mh);
999
1000   if (cmsg && (cmsg->cmsg_len > 0) && (cmsg->cmsg_level == SOL_SOCKET) &&
1001       (cmsg->cmsg_type == SCM_RIGHTS) &&
1002       (cmsg->cmsg_len - CMSG_LEN(0) <= VHOST_MEMORY_MAX_NREGIONS * sizeof(int))) {
1003         number_of_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
1004         clib_memcpy(fds, CMSG_DATA(cmsg), number_of_fds * sizeof(int));
1005   }
1006
1007   /* version 1, no reply bit set*/
1008   if ((msg.flags & 7) != 1) {
1009     DBG_SOCK("malformed message received. closing socket");
1010     goto close_socket;
1011   }
1012
1013   {
1014       int rv __attribute__((unused));
1015       /* $$$$ pay attention to rv */
1016       rv = read(uf->file_descriptor, ((char*)&msg) + n, msg.size);
1017   }
1018
1019   DBG_SOCK("VPP VHOST message %s", vhost_message_str[msg.request]);
1020   switch (msg.request) {
1021     case VHOST_USER_GET_FEATURES:
1022       DBG_SOCK("if %d msg VHOST_USER_GET_FEATURES",
1023         xd->vlib_hw_if_index);
1024
1025       msg.flags |= VHOST_USER_REPLY_MASK;
1026
1027       dpdk_vhost_user_get_features(xd->vlib_hw_if_index, &msg.u64);
1028       msg.u64 &= vui->feature_mask;
1029       msg.size = sizeof(msg.u64);
1030       break;
1031
1032     case VHOST_USER_SET_FEATURES:
1033       DBG_SOCK("if %d msg VHOST_USER_SET_FEATURES features 0x%016lx",
1034         xd->vlib_hw_if_index, msg.u64);
1035
1036       dpdk_vhost_user_set_features(xd->vlib_hw_if_index, msg.u64);
1037       break;
1038
1039     case VHOST_USER_SET_MEM_TABLE:
1040       DBG_SOCK("if %d msg VHOST_USER_SET_MEM_TABLE nregions %d",
1041         xd->vlib_hw_if_index, msg.memory.nregions);
1042
1043       if ((msg.memory.nregions < 1) ||
1044           (msg.memory.nregions > VHOST_MEMORY_MAX_NREGIONS)) {
1045
1046         DBG_SOCK("number of mem regions must be between 1 and %i",
1047           VHOST_MEMORY_MAX_NREGIONS);
1048
1049         goto close_socket;
1050       }
1051
1052       if (msg.memory.nregions != number_of_fds) {
1053         DBG_SOCK("each memory region must have FD");
1054         goto close_socket;
1055       }
1056
1057       dpdk_vhost_user_set_mem_table(xd->vlib_hw_if_index, &msg.memory, fds);
1058       break;
1059
1060     case VHOST_USER_SET_VRING_NUM:
1061       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_NUM idx %d num %d",
1062         xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1063
1064       if ((msg.state.num > 32768) || /* maximum ring size is 32768 */
1065           (msg.state.num == 0) ||    /* it cannot be zero */
1066           (msg.state.num % 2))       /* must be power of 2 */
1067         goto close_socket;
1068
1069       dpdk_vhost_user_set_vring_num(xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1070       break;
1071
1072     case VHOST_USER_SET_VRING_ADDR:
1073       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_ADDR idx %d",
1074         xd->vlib_hw_if_index, msg.state.index);
1075
1076       dpdk_vhost_user_set_vring_addr(xd->vlib_hw_if_index, msg.state.index,
1077                                     msg.addr.desc_user_addr,
1078                                     msg.addr.used_user_addr,
1079                                     msg.addr.avail_user_addr,
1080                                     msg.addr.log_guest_addr);
1081       break;
1082
1083     case VHOST_USER_SET_OWNER:
1084       DBG_SOCK("if %d msg VHOST_USER_SET_OWNER",
1085         xd->vlib_hw_if_index);
1086       break;
1087
1088     case VHOST_USER_RESET_OWNER:
1089       DBG_SOCK("if %d msg VHOST_USER_RESET_OWNER",
1090         xd->vlib_hw_if_index);
1091       break;
1092
1093     case VHOST_USER_SET_VRING_CALL:
1094       q = (u8) (msg.u64 & 0xFF);
1095
1096       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_CALL u64 %lx, idx: %d",
1097         xd->vlib_hw_if_index, msg.u64, q);
1098
1099       if (!(msg.u64 & 0x100))
1100       {
1101         if (number_of_fds != 1)
1102           goto close_socket;
1103         fd = fds[0];
1104       } else {
1105         fd = -1;
1106       }
1107       dpdk_vhost_user_set_vring_call(xd->vlib_hw_if_index, q, fd);
1108
1109       break;
1110
1111     case VHOST_USER_SET_VRING_KICK:
1112
1113       q = (u8) (msg.u64 & 0xFF);
1114
1115       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_KICK u64 %lx, idx: %d",
1116         xd->vlib_hw_if_index, msg.u64, q);
1117
1118       if (!(msg.u64 & 0x100))
1119       {
1120         if (number_of_fds != 1)
1121           goto close_socket;
1122
1123         vui->vrings[q].kickfd = fds[0];
1124       }
1125       else
1126         vui->vrings[q].kickfd = -1;
1127
1128       dpdk_vhost_user_set_vring_kick(xd->vlib_hw_if_index, q, vui->vrings[q].kickfd);
1129       break;
1130
1131     case VHOST_USER_SET_VRING_ERR:
1132
1133       q = (u8) (msg.u64 & 0xFF);
1134
1135       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_ERR u64 %lx, idx: %d",
1136         xd->vlib_hw_if_index, msg.u64, q);
1137
1138       if (!(msg.u64 & 0x100))
1139       {
1140         if (number_of_fds != 1)
1141           goto close_socket;
1142
1143         fd = fds[0];
1144       }
1145       else
1146         fd = -1;
1147
1148       vui->vrings[q].errfd = fd;
1149       break;
1150
1151     case VHOST_USER_SET_VRING_BASE:
1152       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_BASE idx %d num %d",
1153         xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1154
1155       dpdk_vhost_user_set_vring_base(xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1156       break;
1157
1158     case VHOST_USER_GET_VRING_BASE:
1159       DBG_SOCK("if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
1160         xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1161
1162       msg.flags |= VHOST_USER_REPLY_MASK;
1163       msg.size = sizeof(msg.state);
1164
1165       dpdk_vhost_user_get_vring_base(xd->vlib_hw_if_index, msg.state.index, &msg.state.num);
1166       break;
1167
1168     case VHOST_USER_NONE:
1169       DBG_SOCK("if %d msg VHOST_USER_NONE",
1170         xd->vlib_hw_if_index);
1171       break;
1172
1173     case VHOST_USER_SET_LOG_BASE:
1174 #if RTE_VERSION >= RTE_VERSION_NUM(16, 4, 0, 0)
1175       DBG_SOCK("if %d msg VHOST_USER_SET_LOG_BASE",
1176         xd->vlib_hw_if_index);
1177
1178       if (msg.size != sizeof(msg.log)) {
1179         DBG_SOCK("invalid msg size for VHOST_USER_SET_LOG_BASE: %u instead of %lu",
1180                  msg.size, sizeof(msg.log));
1181         goto close_socket;
1182       }
1183
1184       if (!(xd->vu_vhost_dev.protocol_features & (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD))) {
1185         DBG_SOCK("VHOST_USER_PROTOCOL_F_LOG_SHMFD not set but VHOST_USER_SET_LOG_BASE received");
1186         goto close_socket;
1187       }
1188
1189       fd = fds[0];
1190       /* align size to 2M page */
1191       long page_sz = get_huge_page_size(fd);
1192       ssize_t map_sz = (msg.log.size + msg.log.offset + page_sz) & ~(page_sz - 1);
1193
1194       void *addr = mmap(0, map_sz, PROT_READ | PROT_WRITE,
1195                                 MAP_SHARED, fd, 0);
1196
1197       DBG_SOCK("map log region addr 0 len 0x%lx off 0x%lx fd %d mapped %p",
1198                map_sz, msg.log.offset, fd, addr);
1199
1200       if (addr == MAP_FAILED) {
1201         clib_warning("failed to map memory. errno is %d", errno);
1202         goto close_socket;
1203       }
1204
1205       xd->vu_vhost_dev.log_base += pointer_to_uword(addr) + msg.log.offset;
1206       xd->vu_vhost_dev.log_size = msg.log.size;
1207       msg.flags |= VHOST_USER_REPLY_MASK;
1208       msg.size = sizeof(msg.u64);
1209 #else
1210       DBG_SOCK("if %d msg VHOST_USER_SET_LOG_BASE Not-Implemented",
1211         xd->vlib_hw_if_index);
1212 #endif
1213       break;
1214
1215     case VHOST_USER_SET_LOG_FD:
1216       DBG_SOCK("if %d msg VHOST_USER_SET_LOG_FD",
1217         xd->vlib_hw_if_index);
1218       break;
1219
1220     case VHOST_USER_GET_PROTOCOL_FEATURES:
1221       DBG_SOCK("if %d msg VHOST_USER_GET_PROTOCOL_FEATURES",
1222         xd->vlib_hw_if_index);
1223
1224       msg.flags |= VHOST_USER_REPLY_MASK;
1225       msg.u64 = VHOST_USER_PROTOCOL_FEATURES;
1226       DBG_SOCK("VHOST_USER_PROTOCOL_FEATURES: %llx", VHOST_USER_PROTOCOL_FEATURES);
1227       msg.size = sizeof(msg.u64);
1228       break;
1229
1230     case VHOST_USER_SET_PROTOCOL_FEATURES:
1231       DBG_SOCK("if %d msg VHOST_USER_SET_PROTOCOL_FEATURES",
1232         xd->vlib_hw_if_index);
1233
1234       DBG_SOCK("VHOST_USER_SET_PROTOCOL_FEATURES: 0x%lx",
1235         msg.u64);
1236       dpdk_vhost_user_set_protocol_features(xd->vlib_hw_if_index,
1237         msg.u64);
1238       break;
1239
1240     case VHOST_USER_SET_VRING_ENABLE:
1241       DBG_SOCK("%d VPP VHOST_USER_SET_VRING_ENABLE IDX: %d, Enable: %d",
1242         xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1243       dpdk_vhost_user_set_vring_enable
1244         (xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1245       break;
1246
1247     case VHOST_USER_GET_QUEUE_NUM:
1248       DBG_SOCK("if %d msg VHOST_USER_GET_QUEUE_NUM:",
1249         xd->vlib_hw_if_index);
1250
1251       msg.flags |= VHOST_USER_REPLY_MASK;
1252       msg.u64 = xd->vu_vhost_dev.virt_qp_nb;
1253       msg.size = sizeof(msg.u64);
1254       break;
1255
1256     default:
1257       DBG_SOCK("unknown vhost-user message %d received. closing socket",
1258         msg.request);
1259       goto close_socket;
1260   }
1261
1262   /* if we have pointers to descriptor table, go up*/
1263   if (!vui->is_up &&
1264       xd->vu_vhost_dev.virtqueue[VHOST_NET_VRING_IDX_TX]->desc &&
1265       xd->vu_vhost_dev.virtqueue[VHOST_NET_VRING_IDX_RX]->desc) {
1266
1267       DBG_SOCK("interface %d connected", xd->vlib_sw_if_index);
1268
1269       vnet_hw_interface_set_flags (vnm, xd->vlib_hw_if_index,  VNET_HW_INTERFACE_FLAG_LINK_UP);
1270       vui->is_up = 1;
1271       xd->admin_up = 1;
1272   }
1273
1274   /* if we need to reply */
1275   if (msg.flags & VHOST_USER_REPLY_MASK)
1276   {
1277       n = send(uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
1278       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
1279         goto close_socket;
1280   }
1281
1282   return 0;
1283
1284 close_socket:
1285   DBG_SOCK("error: close_socket");
1286   dpdk_vhost_user_if_disconnect(xd);
1287   return 0;
1288 }
1289
1290 static clib_error_t * dpdk_vhost_user_socket_error (unix_file_t * uf)
1291 {
1292   dpdk_main_t * dm = &dpdk_main;
1293   dpdk_device_t *xd;
1294   uword * p;
1295
1296   p = hash_get (dm->vu_sw_if_index_by_sock_fd, uf->file_descriptor);
1297   if (p == 0) {
1298       DBG_SOCK ("FD %d doesn't belong to any interface",
1299                     uf->file_descriptor);
1300       return 0;
1301     }
1302   else
1303       xd = dpdk_vhost_user_device_from_sw_if_index(p[0]);
1304
1305   dpdk_vhost_user_if_disconnect(xd);
1306   return 0;
1307 }
1308
1309 static clib_error_t * dpdk_vhost_user_socksvr_accept_ready (unix_file_t * uf)
1310 {
1311   int client_fd, client_len;
1312   struct sockaddr_un client;
1313   unix_file_t template = {0};
1314   dpdk_main_t * dm = &dpdk_main;
1315   dpdk_device_t * xd = NULL;
1316   dpdk_vu_intf_t * vui;
1317   uword * p;
1318
1319   p = hash_get (dm->vu_sw_if_index_by_listener_fd,
1320                 uf->file_descriptor);
1321   if (p == 0) {
1322       DBG_SOCK ("fd %d doesn't belong to any interface",
1323                     uf->file_descriptor);
1324       return 0;
1325     }
1326
1327   xd = dpdk_vhost_user_device_from_sw_if_index(p[0]);
1328   ASSERT(xd != NULL);
1329   vui = xd->vu_intf;
1330
1331   client_len = sizeof(client);
1332   client_fd = accept (uf->file_descriptor,
1333                       (struct sockaddr *)&client,
1334                       (socklen_t *)&client_len);
1335
1336   if (client_fd < 0)
1337       return clib_error_return_unix (0, "accept");
1338
1339   template.read_function = dpdk_vhost_user_socket_read;
1340   template.error_function = dpdk_vhost_user_socket_error;
1341   template.file_descriptor = client_fd;
1342   vui->unix_file_index = unix_file_add (&unix_main, &template);
1343
1344   vui->client_fd = client_fd;
1345   hash_set (dm->vu_sw_if_index_by_sock_fd, vui->client_fd,
1346             xd->vlib_sw_if_index);
1347
1348   return 0;
1349 }
1350
1351 // init server socket on specified sock_filename
1352 static int dpdk_vhost_user_init_server_sock(const char * sock_filename, int *sockfd)
1353 {
1354   int rv = 0, len;
1355   struct sockaddr_un un;
1356   int fd;
1357   /* create listening socket */
1358   fd = socket(AF_UNIX, SOCK_STREAM, 0);
1359
1360   if (fd < 0) {
1361     return VNET_API_ERROR_SYSCALL_ERROR_1;
1362   }
1363
1364   un.sun_family = AF_UNIX;
1365   strcpy((char *) un.sun_path, (char *) sock_filename);
1366
1367   /* remove if exists */
1368   unlink( (char *) sock_filename);
1369
1370   len = strlen((char *) un.sun_path) + strlen((char *) sock_filename);
1371
1372   if (bind(fd, (struct sockaddr *) &un, len) == -1) {
1373     rv = VNET_API_ERROR_SYSCALL_ERROR_2;
1374     goto error;
1375   }
1376
1377   if (listen(fd, 1) == -1) {
1378     rv = VNET_API_ERROR_SYSCALL_ERROR_3;
1379     goto error;
1380   }
1381
1382   unix_file_t template = {0};
1383   template.read_function = dpdk_vhost_user_socksvr_accept_ready;
1384   template.file_descriptor = fd;
1385   unix_file_add (&unix_main, &template);
1386   *sockfd = fd;
1387   return rv;
1388
1389 error:
1390   close(fd);
1391   return rv;
1392 }
1393
1394 /*
1395  * vhost-user interface control functions used from vpe api
1396  */
1397
1398 int dpdk_vhost_user_create_if(vnet_main_t * vnm, vlib_main_t * vm,
1399                               const char * sock_filename,
1400                               u8 is_server,
1401                               u32 * sw_if_index,
1402                               u64 feature_mask,
1403                               u8 renumber, u32 custom_dev_instance,
1404                               u8 *hwaddr)
1405 {
1406   dpdk_main_t * dm = &dpdk_main;
1407   dpdk_device_t *xd;
1408   u32 hw_if_idx = ~0;
1409   int sockfd = -1;
1410   int rv = 0;
1411
1412   // using virtio vhost user?
1413   if (dm->conf->use_virtio_vhost) {
1414       return vhost_user_create_if(vnm, vm, sock_filename, is_server,
1415               sw_if_index, feature_mask, renumber, custom_dev_instance, hwaddr);
1416   }
1417
1418   if (is_server) {
1419     if ((rv = dpdk_vhost_user_init_server_sock (sock_filename, &sockfd)) != 0) {
1420         return rv;
1421     }
1422   }
1423
1424   if (renumber) {
1425       // set next vhost-user if id if custom one is higher or equal
1426       if (custom_dev_instance >= dm->next_vu_if_id)
1427           dm->next_vu_if_id = custom_dev_instance + 1;
1428
1429     dpdk_create_vhost_user_if_internal(&hw_if_idx, custom_dev_instance, hwaddr);
1430   } else 
1431     dpdk_create_vhost_user_if_internal(&hw_if_idx, (u32)~0, hwaddr);
1432   DBG_SOCK("dpdk vhost-user interface created hw_if_index %d", hw_if_idx);
1433
1434   xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_idx);
1435   ASSERT(xd != NULL);
1436
1437   dpdk_vhost_user_vui_init (vnm, xd, sockfd, sock_filename, is_server,
1438                             feature_mask, sw_if_index);
1439
1440   dpdk_vhost_user_vui_register (vm, xd);
1441   return rv;
1442 }
1443
1444 int dpdk_vhost_user_modify_if(vnet_main_t * vnm, vlib_main_t * vm,
1445                          const char * sock_filename,
1446                          u8 is_server,
1447                          u32 sw_if_index,
1448                          u64 feature_mask,
1449                          u8 renumber, u32 custom_dev_instance)
1450 {
1451   dpdk_main_t * dm = &dpdk_main;
1452   dpdk_device_t * xd;
1453   dpdk_vu_intf_t * vui = NULL;
1454   u32 sw_if_idx = ~0;
1455   int sockfd = -1;
1456   int rv = 0;
1457
1458   // using virtio vhost user?
1459   if (dm->conf->use_virtio_vhost) {
1460       return vhost_user_modify_if(vnm, vm, sock_filename, is_server,
1461               sw_if_index, feature_mask, renumber, custom_dev_instance);
1462   }
1463
1464   xd = dpdk_vhost_user_device_from_sw_if_index(sw_if_index);
1465
1466   if (xd == NULL)
1467     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1468
1469   vui = xd->vu_intf;
1470
1471   // interface is inactive
1472   vui->active = 0;
1473   // disconnect interface sockets
1474   dpdk_vhost_user_if_disconnect(xd);
1475
1476   if (is_server) {
1477       if ((rv = dpdk_vhost_user_init_server_sock (sock_filename, &sockfd)) != 0) {
1478           return rv;
1479       }
1480   }
1481
1482   dpdk_vhost_user_vui_init (vnm, xd, sockfd, sock_filename, is_server,
1483                        feature_mask, &sw_if_idx);
1484
1485   if (renumber) {
1486     vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
1487   }
1488
1489   dpdk_vhost_user_vui_register (vm, xd);
1490
1491   return rv;
1492 }
1493
1494 int dpdk_vhost_user_delete_if(vnet_main_t * vnm, vlib_main_t * vm,
1495                          u32 sw_if_index)
1496 {
1497   dpdk_main_t * dm = &dpdk_main;
1498   dpdk_device_t * xd = NULL;
1499   dpdk_vu_intf_t * vui;
1500   int rv = 0;
1501
1502   // using virtio vhost user?
1503   if (dm->conf->use_virtio_vhost) {
1504       return vhost_user_delete_if(vnm, vm, sw_if_index);
1505   }
1506
1507   xd = dpdk_vhost_user_device_from_sw_if_index(sw_if_index);
1508
1509   if (xd == NULL)
1510     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1511
1512   vui = xd->vu_intf;
1513
1514   // interface is inactive
1515   vui->active = 0;
1516   // disconnect interface sockets
1517   dpdk_vhost_user_if_disconnect(xd);
1518   // add to inactive interface list
1519   vec_add1 (dm->vu_inactive_interfaces_device_index, xd->device_index);
1520
1521   ethernet_delete_interface (vnm, xd->vlib_hw_if_index);
1522   DBG_SOCK ("deleted (deactivated) vhost-user interface sw_if_index %d", sw_if_index);
1523
1524   return rv;
1525 }
1526
1527 int dpdk_vhost_user_dump_ifs(vnet_main_t * vnm, vlib_main_t * vm, vhost_user_intf_details_t **out_vuids)
1528 {
1529     int rv = 0;
1530     dpdk_main_t * dm = &dpdk_main;
1531     dpdk_device_t * xd;
1532     dpdk_vu_intf_t * vui;
1533     struct virtio_net * vhost_dev;
1534     vhost_user_intf_details_t * r_vuids = NULL;
1535     vhost_user_intf_details_t * vuid = NULL;
1536     u32 * hw_if_indices = 0;
1537     vnet_hw_interface_t * hi;
1538     u8 *s = NULL;
1539     int i;
1540
1541     if (!out_vuids)
1542         return -1;
1543
1544     // using virtio vhost user?
1545     if (dm->conf->use_virtio_vhost) {
1546         return vhost_user_dump_ifs(vnm, vm, out_vuids);
1547     }
1548
1549     vec_foreach (xd, dm->devices) {
1550       if (xd->dev_type == VNET_DPDK_DEV_VHOST_USER &&
1551               xd->vu_intf->active)
1552         vec_add1(hw_if_indices, xd->vlib_hw_if_index);
1553     }
1554
1555     for (i = 0; i < vec_len (hw_if_indices); i++) {
1556       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
1557       xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_indices[i]);
1558       if (!xd) {
1559           clib_warning("invalid vhost-user interface hw_if_index %d", hw_if_indices[i]);
1560           continue;
1561       }
1562
1563       vui = xd->vu_intf;
1564       ASSERT(vui != NULL);
1565       vhost_dev = &xd->vu_vhost_dev;
1566       u32 virtio_net_hdr_sz = (vui->num_vrings > 0 ?
1567             vhost_dev->virtqueue[0]->vhost_hlen : 0);
1568
1569       vec_add2(r_vuids, vuid, 1);
1570       vuid->sw_if_index = xd->vlib_sw_if_index;
1571       vuid->virtio_net_hdr_sz = virtio_net_hdr_sz;
1572       vuid->features = vhost_dev->features;
1573       vuid->is_server = vui->sock_is_server;
1574       vuid->num_regions = (vhost_dev->mem != NULL ? vhost_dev->mem->nregions : 0);
1575       vuid->sock_errno = vui->sock_errno;
1576       strncpy((char *)vuid->sock_filename, (char *)vui->sock_filename,
1577               ARRAY_LEN(vuid->sock_filename)-1);
1578
1579       s = format (s, "%v%c", hi->name, 0);
1580
1581       strncpy((char *)vuid->if_name, (char *)s,
1582               ARRAY_LEN(vuid->if_name)-1);
1583       _vec_len(s) = 0;
1584     }
1585
1586     vec_free (s);
1587     vec_free (hw_if_indices);
1588
1589     *out_vuids = r_vuids;
1590
1591     return rv;
1592 }
1593
1594 /*
1595  * Processing functions called from dpdk process fn
1596  */
1597
1598 typedef struct {
1599     struct sockaddr_un sun;
1600     int sockfd;
1601     unix_file_t template;
1602     uword *event_data;
1603 } dpdk_vu_process_state;
1604
1605 void dpdk_vhost_user_process_init (void **ctx)
1606 {
1607     dpdk_vu_process_state *state = clib_mem_alloc (sizeof(dpdk_vu_process_state));
1608     memset(state, 0, sizeof(*state));
1609     state->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1610     state->sun.sun_family = AF_UNIX;
1611     state->template.read_function = dpdk_vhost_user_socket_read;
1612     state->template.error_function = dpdk_vhost_user_socket_error;
1613     state->event_data = 0;
1614     *ctx = state;
1615 }
1616
1617 void dpdk_vhost_user_process_cleanup (void *ctx)
1618 {
1619     clib_mem_free(ctx);
1620 }
1621
1622 uword dpdk_vhost_user_process_if (vlib_main_t *vm, dpdk_device_t *xd, void *ctx)
1623 {
1624     dpdk_main_t * dm = &dpdk_main;
1625     dpdk_vu_process_state *state = (dpdk_vu_process_state *)ctx;
1626     dpdk_vu_intf_t *vui = xd->vu_intf;
1627
1628     if (vui->sock_is_server || !vui->active)
1629         return 0;
1630
1631     if (vui->unix_fd == -1) {
1632         /* try to connect */
1633         strncpy(state->sun.sun_path,  (char *) vui->sock_filename, sizeof(state->sun.sun_path) - 1);
1634
1635         if (connect(state->sockfd, (struct sockaddr *) &(state->sun), sizeof(struct sockaddr_un)) == 0) {
1636             vui->sock_errno = 0;
1637             vui->unix_fd = state->sockfd;
1638             state->template.file_descriptor = state->sockfd;
1639             vui->unix_file_index = unix_file_add (&unix_main, &(state->template));
1640             hash_set (dm->vu_sw_if_index_by_sock_fd, state->sockfd, xd->vlib_sw_if_index);
1641
1642             state->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1643             if (state->sockfd < 0)
1644                 return -1;
1645         } else {
1646             vui->sock_errno = errno;
1647         }
1648     } else {
1649         /* check if socket is alive */
1650         int error = 0;
1651         socklen_t len = sizeof (error);
1652         int retval = getsockopt(vui->unix_fd, SOL_SOCKET, SO_ERROR, &error, &len);
1653
1654         if (retval)
1655             dpdk_vhost_user_if_disconnect(xd);
1656     }
1657     return 0;
1658 }
1659
1660 /*
1661  * CLI functions
1662  */
1663
1664 static clib_error_t *
1665 dpdk_vhost_user_connect_command_fn (vlib_main_t * vm,
1666                  unformat_input_t * input,
1667                  vlib_cli_command_t * cmd)
1668 {
1669   dpdk_main_t * dm = &dpdk_main;
1670   unformat_input_t _line_input, * line_input = &_line_input;
1671   u8 * sock_filename = NULL;
1672   u32 sw_if_index;
1673   u8 is_server = 0;
1674   u64 feature_mask = (u64)~0;
1675   u8 renumber = 0;
1676   u32 custom_dev_instance = ~0;
1677   u8 hwaddr[6];
1678   u8 *hw = NULL;
1679
1680   if (dm->conf->use_virtio_vhost) {
1681       return vhost_user_connect_command_fn(vm, input, cmd);
1682   }
1683
1684   /* Get a line of input. */
1685   if (! unformat_user (input, unformat_line_input, line_input))
1686     return 0;
1687
1688   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
1689     if (unformat (line_input, "socket %s", &sock_filename))
1690       ;
1691     else if (unformat (line_input, "server"))
1692       is_server = 1;
1693     else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
1694       ;
1695     else if (unformat (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
1696       hw = hwaddr;
1697     else if (unformat (line_input, "renumber %d", &custom_dev_instance)) {
1698         renumber = 1;
1699     }
1700     else
1701       return clib_error_return (0, "unknown input `%U'",
1702                                 format_unformat_error, input);
1703   }
1704   unformat_free (line_input);
1705
1706   vnet_main_t *vnm = vnet_get_main();
1707   if (sock_filename == NULL)
1708       return clib_error_return (0, "missing socket file");
1709
1710   dpdk_vhost_user_create_if(vnm, vm, (char *)sock_filename,
1711                             is_server, &sw_if_index, feature_mask,
1712                             renumber, custom_dev_instance, hw);
1713
1714   vec_free(sock_filename);
1715   vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
1716   return 0;
1717 }
1718
1719 VLIB_CLI_COMMAND (dpdk_vhost_user_connect_command, static) = {
1720     .path = "create vhost-user",
1721     .short_help = "create vhost-user socket <socket-filename> [server] [feature-mask <hex>] [renumber <dev_instance>]",
1722     .function = dpdk_vhost_user_connect_command_fn,
1723 };
1724
1725 static clib_error_t *
1726 dpdk_vhost_user_delete_command_fn (vlib_main_t * vm,
1727                  unformat_input_t * input,
1728                  vlib_cli_command_t * cmd)
1729 {
1730   dpdk_main_t * dm = &dpdk_main;
1731   clib_error_t * error = 0;
1732   unformat_input_t _line_input, * line_input = &_line_input;
1733   u32 sw_if_index = ~0;
1734
1735   if (dm->conf->use_virtio_vhost) {
1736       return vhost_user_delete_command_fn(vm, input, cmd);
1737   }
1738
1739   /* Get a line of input. */
1740   if (! unformat_user (input, unformat_line_input, line_input))
1741     return 0;
1742
1743   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
1744     if (unformat (line_input, "sw_if_index %d", &sw_if_index))
1745       ;
1746     else
1747       return clib_error_return (0, "unknown input `%U'",
1748                                 format_unformat_error, input);
1749   }
1750   unformat_free (line_input);
1751
1752   if (sw_if_index == ~0) {
1753       error = clib_error_return (0, "invalid sw_if_index",
1754                                  format_unformat_error, input);
1755       return error;
1756   }
1757
1758   vnet_main_t *vnm = vnet_get_main();
1759
1760   dpdk_vhost_user_delete_if(vnm, vm, sw_if_index);
1761
1762   return 0;
1763 }
1764
1765 VLIB_CLI_COMMAND (dpdk_vhost_user_delete_command, static) = {
1766     .path = "delete vhost-user",
1767     .short_help = "delete vhost-user sw_if_index <nn>",
1768     .function = dpdk_vhost_user_delete_command_fn,
1769 };
1770
1771 #define foreach_dpdk_vhost_feature      \
1772  _ (VIRTIO_NET_F_MRG_RXBUF)             \
1773  _ (VIRTIO_NET_F_CTRL_VQ)               \
1774  _ (VIRTIO_NET_F_CTRL_RX)
1775
1776 static clib_error_t *
1777 show_dpdk_vhost_user_command_fn (vlib_main_t * vm,
1778                  unformat_input_t * input,
1779                  vlib_cli_command_t * cmd)
1780 {
1781   clib_error_t * error = 0;
1782   dpdk_main_t * dm = &dpdk_main;
1783   vnet_main_t * vnm = vnet_get_main();
1784   dpdk_device_t * xd;
1785   dpdk_vu_intf_t * vui;
1786   struct virtio_net * vhost_dev;
1787   u32 hw_if_index, * hw_if_indices = 0;
1788   vnet_hw_interface_t * hi;
1789   int i, j, q;
1790   int show_descr = 0;
1791   struct virtio_memory * mem;
1792   struct feat_struct { u8 bit; char *str;};
1793   struct feat_struct *feat_entry;
1794
1795   static struct feat_struct feat_array[] = {
1796 #define _(f) { .str = #f, .bit = f, },
1797   foreach_dpdk_vhost_feature
1798 #undef _
1799   { .str = NULL }
1800   };
1801
1802   if (dm->conf->use_virtio_vhost) {
1803     return show_vhost_user_command_fn(vm, input, cmd);
1804   }
1805
1806   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1807     if (unformat (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) {
1808       vec_add1 (hw_if_indices, hw_if_index);
1809       vlib_cli_output(vm, "add %d", hw_if_index);
1810     }
1811     else if (unformat (input, "descriptors") || unformat (input, "desc") )
1812       show_descr = 1;
1813     else {
1814       error = clib_error_return (0, "unknown input `%U'",
1815                                      format_unformat_error, input);
1816       goto done;
1817     }
1818   }
1819   if (vec_len (hw_if_indices) == 0) {
1820     vec_foreach (xd, dm->devices) {
1821       if (xd->dev_type == VNET_DPDK_DEV_VHOST_USER && xd->vu_intf->active)
1822         vec_add1(hw_if_indices, xd->vlib_hw_if_index);
1823     }
1824   }
1825
1826   vlib_cli_output (vm, "DPDK vhost-user interfaces");
1827   vlib_cli_output (vm, "Global:\n  coalesce frames %d time %e\n\n",
1828                    dm->conf->vhost_coalesce_frames, dm->conf->vhost_coalesce_time);
1829
1830   for (i = 0; i < vec_len (hw_if_indices); i++) {
1831     hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
1832
1833     if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_indices[i]))) {
1834         error = clib_error_return (0, "not dpdk vhost-user interface: '%s'",
1835                                        hi->name);
1836         goto done;
1837     }
1838     vui = xd->vu_intf;
1839     vhost_dev = &xd->vu_vhost_dev;
1840     mem = vhost_dev->mem;
1841     u32 virtio_net_hdr_sz = (vui->num_vrings > 0 ?
1842             vhost_dev->virtqueue[0]->vhost_hlen : 0);
1843
1844     vlib_cli_output (vm, "Interface: %v (ifindex %d)",
1845                          hi->name, hw_if_indices[i]);
1846
1847     vlib_cli_output (vm, "virtio_net_hdr_sz %d\n features (0x%llx): \n",
1848                          virtio_net_hdr_sz, xd->vu_vhost_dev.features);
1849
1850     feat_entry = (struct feat_struct *) &feat_array;
1851     while(feat_entry->str) {
1852       if (xd->vu_vhost_dev.features & (1 << feat_entry->bit))
1853         vlib_cli_output (vm, "   %s (%d)", feat_entry->str, feat_entry->bit);
1854       feat_entry++;
1855     }
1856
1857     vlib_cli_output (vm, "\n");
1858
1859     vlib_cli_output (vm, " socket filename %s type %s errno \"%s\"\n\n",
1860                          vui->sock_filename, vui->sock_is_server ? "server" : "client",
1861                          strerror(vui->sock_errno));
1862
1863     vlib_cli_output (vm, " Memory regions (total %d)\n", mem->nregions);
1864
1865     if (mem->nregions){
1866       vlib_cli_output(vm, " region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr\n");
1867       vlib_cli_output(vm, " ====== ===== ================== ================== ================== ================== ==================\n");
1868     }
1869     for (j = 0; j < mem->nregions; j++) {
1870       vlib_cli_output(vm, "  %d     %-5d 0x%016lx 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n", j,
1871         vui->region_fd[j],
1872         mem->regions[j].guest_phys_address,
1873         mem->regions[j].memory_size,
1874         mem->regions[j].userspace_address,
1875         mem->regions[j].address_offset,
1876         vui->region_addr[j]);
1877     }
1878     for (q = 0; q < vui->num_vrings; q++) {
1879       struct vhost_virtqueue *vq = vhost_dev->virtqueue[q];
1880       const char *qtype = (q & 1) ? "TX" : "RX";
1881
1882       vlib_cli_output(vm, "\n Virtqueue %d (%s)\n", q/2, qtype);
1883
1884       vlib_cli_output(vm, "  qsz %d last_used_idx %d last_used_idx_res %d\n",
1885               vq->size, vq->last_used_idx, vq->last_used_idx_res);
1886
1887       if (vq->avail && vq->used)
1888         vlib_cli_output(vm, "  avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
1889           vq->avail->flags, vq->avail->idx, vq->used->flags, vq->used->idx);
1890
1891       vlib_cli_output(vm, "  kickfd %d callfd %d errfd %d enabled %d\n",
1892         vq->kickfd, vq->callfd, vui->vrings[q].errfd, vq->enabled);
1893
1894       if (show_descr && vq->enabled) {
1895         vlib_cli_output(vm, "\n  descriptor table:\n");
1896         vlib_cli_output(vm, "   id          addr         len  flags  next      user_addr\n");
1897         vlib_cli_output(vm, "  ===== ================== ===== ====== ===== ==================\n");
1898         for(j = 0; j < vq->size; j++) {
1899           vlib_cli_output(vm, "  %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
1900             j,
1901             vq->desc[j].addr,
1902             vq->desc[j].len,
1903             vq->desc[j].flags,
1904             vq->desc[j].next,
1905             pointer_to_uword(map_guest_mem(xd, vq->desc[j].addr)));}
1906       }
1907     }
1908     vlib_cli_output (vm, "\n");
1909   }
1910 done:
1911   vec_free (hw_if_indices);
1912   return error;
1913 }
1914
1915 VLIB_CLI_COMMAND (show_vhost_user_command, static) = {
1916     .path = "show vhost-user",
1917     .short_help = "show vhost-user interface",
1918     .function = show_dpdk_vhost_user_command_fn,
1919 };