Retire support for DPDK 2.1.0 and older
[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
913     xd->admin_up = 0;
914     vnet_hw_interface_set_flags (vnm, xd->vlib_hw_if_index,  0);
915
916     if (vui->unix_file_index != ~0) {
917         unix_file_del (&unix_main, unix_main.file_pool + vui->unix_file_index);
918         vui->unix_file_index = ~0;
919     }
920
921     hash_unset(dm->vu_sw_if_index_by_sock_fd, vui->unix_fd);
922     hash_unset(dm->vu_sw_if_index_by_listener_fd, vui->unix_fd);
923     close(vui->unix_fd);
924     vui->unix_fd = -1;
925     vui->is_up = 0;
926
927     dpdk_unmap_all_mem_regions(xd);
928     DBG_SOCK("interface ifindex %d disconnected", xd->vlib_sw_if_index);
929 }
930
931 static clib_error_t * dpdk_vhost_user_socket_read (unix_file_t * uf)
932 {
933   int n;
934   int fd, number_of_fds = 0;
935   int fds[VHOST_MEMORY_MAX_NREGIONS];
936   vhost_user_msg_t msg;
937   struct msghdr mh;
938   struct iovec iov[1];
939   dpdk_main_t * dm = &dpdk_main;
940   dpdk_device_t *xd;
941   dpdk_vu_intf_t *vui;
942   struct cmsghdr *cmsg;
943   uword * p;
944   u8 q;
945   vnet_main_t * vnm = vnet_get_main();
946
947   p = hash_get (dm->vu_sw_if_index_by_sock_fd, uf->file_descriptor);
948   if (p == 0) {
949       DBG_SOCK ("FD %d doesn't belong to any interface",
950                     uf->file_descriptor);
951       return 0;
952     }
953   else
954       xd = dpdk_vhost_user_device_from_sw_if_index(p[0]);
955
956   ASSERT(xd != NULL);
957   vui = xd->vu_intf;
958
959   char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))];
960
961   memset(&mh, 0, sizeof(mh));
962   memset(control, 0, sizeof(control));
963
964   /* set the payload */
965   iov[0].iov_base = (void *) &msg;
966   iov[0].iov_len = VHOST_USER_MSG_HDR_SZ;
967
968   mh.msg_iov = iov;
969   mh.msg_iovlen = 1;
970   mh.msg_control = control;
971   mh.msg_controllen = sizeof(control);
972
973   n = recvmsg(uf->file_descriptor, &mh, 0);
974
975   if (n != VHOST_USER_MSG_HDR_SZ)
976     goto close_socket;
977
978   if (mh.msg_flags & MSG_CTRUNC) {
979     goto close_socket;
980   }
981
982   cmsg = CMSG_FIRSTHDR(&mh);
983
984   if (cmsg && (cmsg->cmsg_len > 0) && (cmsg->cmsg_level == SOL_SOCKET) &&
985       (cmsg->cmsg_type == SCM_RIGHTS) &&
986       (cmsg->cmsg_len - CMSG_LEN(0) <= VHOST_MEMORY_MAX_NREGIONS * sizeof(int))) {
987         number_of_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
988         clib_memcpy(fds, CMSG_DATA(cmsg), number_of_fds * sizeof(int));
989   }
990
991   /* version 1, no reply bit set*/
992   if ((msg.flags & 7) != 1) {
993     DBG_SOCK("malformed message received. closing socket");
994     goto close_socket;
995   }
996
997   {
998       int rv __attribute__((unused));
999       /* $$$$ pay attention to rv */
1000       rv = read(uf->file_descriptor, ((char*)&msg) + n, msg.size);
1001   }
1002
1003   DBG_SOCK("VPP VHOST message %s", vhost_message_str[msg.request]);
1004   switch (msg.request) {
1005     case VHOST_USER_GET_FEATURES:
1006       DBG_SOCK("if %d msg VHOST_USER_GET_FEATURES",
1007         xd->vlib_hw_if_index);
1008
1009       msg.flags |= VHOST_USER_REPLY_MASK;
1010
1011       dpdk_vhost_user_get_features(xd->vlib_hw_if_index, &msg.u64);
1012       msg.u64 &= vui->feature_mask;
1013       msg.size = sizeof(msg.u64);
1014       break;
1015
1016     case VHOST_USER_SET_FEATURES:
1017       DBG_SOCK("if %d msg VHOST_USER_SET_FEATURES features 0x%016lx",
1018         xd->vlib_hw_if_index, msg.u64);
1019
1020       dpdk_vhost_user_set_features(xd->vlib_hw_if_index, msg.u64);
1021       break;
1022
1023     case VHOST_USER_SET_MEM_TABLE:
1024       DBG_SOCK("if %d msg VHOST_USER_SET_MEM_TABLE nregions %d",
1025         xd->vlib_hw_if_index, msg.memory.nregions);
1026
1027       if ((msg.memory.nregions < 1) ||
1028           (msg.memory.nregions > VHOST_MEMORY_MAX_NREGIONS)) {
1029
1030         DBG_SOCK("number of mem regions must be between 1 and %i",
1031           VHOST_MEMORY_MAX_NREGIONS);
1032
1033         goto close_socket;
1034       }
1035
1036       if (msg.memory.nregions != number_of_fds) {
1037         DBG_SOCK("each memory region must have FD");
1038         goto close_socket;
1039       }
1040
1041       dpdk_vhost_user_set_mem_table(xd->vlib_hw_if_index, &msg.memory, fds);
1042       break;
1043
1044     case VHOST_USER_SET_VRING_NUM:
1045       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_NUM idx %d num %d",
1046         xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1047
1048       if ((msg.state.num > 32768) || /* maximum ring size is 32768 */
1049           (msg.state.num == 0) ||    /* it cannot be zero */
1050           (msg.state.num % 2))       /* must be power of 2 */
1051         goto close_socket;
1052
1053       dpdk_vhost_user_set_vring_num(xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1054       break;
1055
1056     case VHOST_USER_SET_VRING_ADDR:
1057       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_ADDR idx %d",
1058         xd->vlib_hw_if_index, msg.state.index);
1059
1060       dpdk_vhost_user_set_vring_addr(xd->vlib_hw_if_index, msg.state.index,
1061                                     msg.addr.desc_user_addr,
1062                                     msg.addr.used_user_addr,
1063                                     msg.addr.avail_user_addr,
1064                                     msg.addr.log_guest_addr);
1065       break;
1066
1067     case VHOST_USER_SET_OWNER:
1068       DBG_SOCK("if %d msg VHOST_USER_SET_OWNER",
1069         xd->vlib_hw_if_index);
1070       break;
1071
1072     case VHOST_USER_RESET_OWNER:
1073       DBG_SOCK("if %d msg VHOST_USER_RESET_OWNER",
1074         xd->vlib_hw_if_index);
1075       break;
1076
1077     case VHOST_USER_SET_VRING_CALL:
1078       q = (u8) (msg.u64 & 0xFF);
1079
1080       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_CALL u64 %lx, idx: %d",
1081         xd->vlib_hw_if_index, msg.u64, q);
1082
1083       if (!(msg.u64 & 0x100))
1084       {
1085         if (number_of_fds != 1)
1086           goto close_socket;
1087         fd = fds[0];
1088       } else {
1089         fd = -1;
1090       }
1091       dpdk_vhost_user_set_vring_call(xd->vlib_hw_if_index, q, fd);
1092
1093       break;
1094
1095     case VHOST_USER_SET_VRING_KICK:
1096
1097       q = (u8) (msg.u64 & 0xFF);
1098
1099       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_KICK u64 %lx, idx: %d",
1100         xd->vlib_hw_if_index, msg.u64, q);
1101
1102       if (!(msg.u64 & 0x100))
1103       {
1104         if (number_of_fds != 1)
1105           goto close_socket;
1106
1107         vui->vrings[q].kickfd = fds[0];
1108       }
1109       else
1110         vui->vrings[q].kickfd = -1;
1111
1112       dpdk_vhost_user_set_vring_kick(xd->vlib_hw_if_index, q, vui->vrings[q].kickfd);
1113       break;
1114
1115     case VHOST_USER_SET_VRING_ERR:
1116
1117       q = (u8) (msg.u64 & 0xFF);
1118
1119       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_ERR u64 %lx, idx: %d",
1120         xd->vlib_hw_if_index, msg.u64, q);
1121
1122       if (!(msg.u64 & 0x100))
1123       {
1124         if (number_of_fds != 1)
1125           goto close_socket;
1126
1127         fd = fds[0];
1128       }
1129       else
1130         fd = -1;
1131
1132       vui->vrings[q].errfd = fd;
1133       break;
1134
1135     case VHOST_USER_SET_VRING_BASE:
1136       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_BASE idx %d num %d",
1137         xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1138
1139       dpdk_vhost_user_set_vring_base(xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1140       break;
1141
1142     case VHOST_USER_GET_VRING_BASE:
1143       DBG_SOCK("if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
1144         xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1145
1146       msg.flags |= VHOST_USER_REPLY_MASK;
1147       msg.size = sizeof(msg.state);
1148
1149       dpdk_vhost_user_get_vring_base(xd->vlib_hw_if_index, msg.state.index, &msg.state.num);
1150       break;
1151
1152     case VHOST_USER_NONE:
1153       DBG_SOCK("if %d msg VHOST_USER_NONE",
1154         xd->vlib_hw_if_index);
1155       break;
1156
1157     case VHOST_USER_SET_LOG_BASE:
1158 #if RTE_VERSION >= RTE_VERSION_NUM(16, 4, 0, 0)
1159       DBG_SOCK("if %d msg VHOST_USER_SET_LOG_BASE",
1160         xd->vlib_hw_if_index);
1161
1162       if (msg.size != sizeof(msg.log)) {
1163         DBG_SOCK("invalid msg size for VHOST_USER_SET_LOG_BASE: %u instead of %lu",
1164                  msg.size, sizeof(msg.log));
1165         goto close_socket;
1166       }
1167
1168       if (!(xd->vu_vhost_dev.protocol_features & (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD))) {
1169         DBG_SOCK("VHOST_USER_PROTOCOL_F_LOG_SHMFD not set but VHOST_USER_SET_LOG_BASE received");
1170         goto close_socket;
1171       }
1172
1173       fd = fds[0];
1174       /* align size to 2M page */
1175       long page_sz = get_huge_page_size(fd);
1176       ssize_t map_sz = (msg.log.size + msg.log.offset + page_sz) & ~(page_sz - 1);
1177
1178       void *addr = mmap(0, map_sz, PROT_READ | PROT_WRITE,
1179                                 MAP_SHARED, fd, 0);
1180
1181       DBG_SOCK("map log region addr 0 len 0x%lx off 0x%lx fd %d mapped %p",
1182                map_sz, msg.log.offset, fd, addr);
1183
1184       if (addr == MAP_FAILED) {
1185         clib_warning("failed to map memory. errno is %d", errno);
1186         goto close_socket;
1187       }
1188
1189       xd->vu_vhost_dev.log_base += pointer_to_uword(addr) + msg.log.offset;
1190       xd->vu_vhost_dev.log_size = msg.log.size;
1191       msg.flags |= VHOST_USER_REPLY_MASK;
1192       msg.size = sizeof(msg.u64);
1193 #else
1194       DBG_SOCK("if %d msg VHOST_USER_SET_LOG_BASE Not-Implemented",
1195         xd->vlib_hw_if_index);
1196 #endif
1197       break;
1198
1199     case VHOST_USER_SET_LOG_FD:
1200       DBG_SOCK("if %d msg VHOST_USER_SET_LOG_FD",
1201         xd->vlib_hw_if_index);
1202       break;
1203
1204     case VHOST_USER_GET_PROTOCOL_FEATURES:
1205       DBG_SOCK("if %d msg VHOST_USER_GET_PROTOCOL_FEATURES",
1206         xd->vlib_hw_if_index);
1207
1208       msg.flags |= VHOST_USER_REPLY_MASK;
1209       msg.u64 = VHOST_USER_PROTOCOL_FEATURES;
1210       DBG_SOCK("VHOST_USER_PROTOCOL_FEATURES: %llx", VHOST_USER_PROTOCOL_FEATURES);
1211       msg.size = sizeof(msg.u64);
1212       break;
1213
1214     case VHOST_USER_SET_PROTOCOL_FEATURES:
1215       DBG_SOCK("if %d msg VHOST_USER_SET_PROTOCOL_FEATURES",
1216         xd->vlib_hw_if_index);
1217
1218       DBG_SOCK("VHOST_USER_SET_PROTOCOL_FEATURES: 0x%lx",
1219         msg.u64);
1220       dpdk_vhost_user_set_protocol_features(xd->vlib_hw_if_index,
1221         msg.u64);
1222       break;
1223
1224     case VHOST_USER_SET_VRING_ENABLE:
1225       DBG_SOCK("%d VPP VHOST_USER_SET_VRING_ENABLE IDX: %d, Enable: %d",
1226         xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1227       dpdk_vhost_user_set_vring_enable
1228         (xd->vlib_hw_if_index, msg.state.index, msg.state.num);
1229       break;
1230
1231     case VHOST_USER_GET_QUEUE_NUM:
1232       DBG_SOCK("if %d msg VHOST_USER_GET_QUEUE_NUM:",
1233         xd->vlib_hw_if_index);
1234
1235       msg.flags |= VHOST_USER_REPLY_MASK;
1236       msg.u64 = xd->vu_vhost_dev.virt_qp_nb;
1237       msg.size = sizeof(msg.u64);
1238       break;
1239
1240     default:
1241       DBG_SOCK("unknown vhost-user message %d received. closing socket",
1242         msg.request);
1243       goto close_socket;
1244   }
1245
1246   /* if we have pointers to descriptor table, go up*/
1247   if (!vui->is_up &&
1248       xd->vu_vhost_dev.virtqueue[VHOST_NET_VRING_IDX_TX]->desc &&
1249       xd->vu_vhost_dev.virtqueue[VHOST_NET_VRING_IDX_RX]->desc) {
1250
1251       DBG_SOCK("interface %d connected", xd->vlib_sw_if_index);
1252
1253       vnet_hw_interface_set_flags (vnm, xd->vlib_hw_if_index,  VNET_HW_INTERFACE_FLAG_LINK_UP);
1254       vui->is_up = 1;
1255       xd->admin_up = 1;
1256   }
1257
1258   /* if we need to reply */
1259   if (msg.flags & VHOST_USER_REPLY_MASK)
1260   {
1261       n = send(uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
1262       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
1263         goto close_socket;
1264   }
1265
1266   return 0;
1267
1268 close_socket:
1269   DBG_SOCK("error: close_socket");
1270   dpdk_vhost_user_if_disconnect(xd);
1271   return 0;
1272 }
1273
1274 static clib_error_t * dpdk_vhost_user_socket_error (unix_file_t * uf)
1275 {
1276   dpdk_main_t * dm = &dpdk_main;
1277   dpdk_device_t *xd;
1278   uword * p;
1279
1280   p = hash_get (dm->vu_sw_if_index_by_sock_fd, uf->file_descriptor);
1281   if (p == 0) {
1282       DBG_SOCK ("FD %d doesn't belong to any interface",
1283                     uf->file_descriptor);
1284       return 0;
1285     }
1286   else
1287       xd = dpdk_vhost_user_device_from_sw_if_index(p[0]);
1288
1289   dpdk_vhost_user_if_disconnect(xd);
1290   return 0;
1291 }
1292
1293 static clib_error_t * dpdk_vhost_user_socksvr_accept_ready (unix_file_t * uf)
1294 {
1295   int client_fd, client_len;
1296   struct sockaddr_un client;
1297   unix_file_t template = {0};
1298   dpdk_main_t * dm = &dpdk_main;
1299   dpdk_device_t * xd = NULL;
1300   dpdk_vu_intf_t * vui;
1301   uword * p;
1302
1303   p = hash_get (dm->vu_sw_if_index_by_listener_fd,
1304                 uf->file_descriptor);
1305   if (p == 0) {
1306       DBG_SOCK ("fd %d doesn't belong to any interface",
1307                     uf->file_descriptor);
1308       return 0;
1309     }
1310
1311   xd = dpdk_vhost_user_device_from_sw_if_index(p[0]);
1312   ASSERT(xd != NULL);
1313   vui = xd->vu_intf;
1314
1315   client_len = sizeof(client);
1316   client_fd = accept (uf->file_descriptor,
1317                       (struct sockaddr *)&client,
1318                       (socklen_t *)&client_len);
1319
1320   if (client_fd < 0)
1321       return clib_error_return_unix (0, "accept");
1322
1323   template.read_function = dpdk_vhost_user_socket_read;
1324   template.error_function = dpdk_vhost_user_socket_error;
1325   template.file_descriptor = client_fd;
1326   vui->unix_file_index = unix_file_add (&unix_main, &template);
1327
1328   vui->client_fd = client_fd;
1329   hash_set (dm->vu_sw_if_index_by_sock_fd, vui->client_fd,
1330             xd->vlib_sw_if_index);
1331
1332   return 0;
1333 }
1334
1335 // init server socket on specified sock_filename
1336 static int dpdk_vhost_user_init_server_sock(const char * sock_filename, int *sockfd)
1337 {
1338   int rv = 0, len;
1339   struct sockaddr_un un;
1340   int fd;
1341   /* create listening socket */
1342   fd = socket(AF_UNIX, SOCK_STREAM, 0);
1343
1344   if (fd < 0) {
1345     return VNET_API_ERROR_SYSCALL_ERROR_1;
1346   }
1347
1348   un.sun_family = AF_UNIX;
1349   strcpy((char *) un.sun_path, (char *) sock_filename);
1350
1351   /* remove if exists */
1352   unlink( (char *) sock_filename);
1353
1354   len = strlen((char *) un.sun_path) + strlen((char *) sock_filename);
1355
1356   if (bind(fd, (struct sockaddr *) &un, len) == -1) {
1357     rv = VNET_API_ERROR_SYSCALL_ERROR_2;
1358     goto error;
1359   }
1360
1361   if (listen(fd, 1) == -1) {
1362     rv = VNET_API_ERROR_SYSCALL_ERROR_3;
1363     goto error;
1364   }
1365
1366   unix_file_t template = {0};
1367   template.read_function = dpdk_vhost_user_socksvr_accept_ready;
1368   template.file_descriptor = fd;
1369   unix_file_add (&unix_main, &template);
1370   *sockfd = fd;
1371   return rv;
1372
1373 error:
1374   close(fd);
1375   return rv;
1376 }
1377
1378 /*
1379  * vhost-user interface control functions used from vpe api
1380  */
1381
1382 int dpdk_vhost_user_create_if(vnet_main_t * vnm, vlib_main_t * vm,
1383                               const char * sock_filename,
1384                               u8 is_server,
1385                               u32 * sw_if_index,
1386                               u64 feature_mask,
1387                               u8 renumber, u32 custom_dev_instance,
1388                               u8 *hwaddr)
1389 {
1390   dpdk_main_t * dm = &dpdk_main;
1391   dpdk_device_t *xd;
1392   u32 hw_if_idx = ~0;
1393   int sockfd = -1;
1394   int rv = 0;
1395
1396   // using virtio vhost user?
1397   if (dm->conf->use_virtio_vhost) {
1398       return vhost_user_create_if(vnm, vm, sock_filename, is_server,
1399               sw_if_index, feature_mask, renumber, custom_dev_instance, hwaddr);
1400   }
1401
1402   if (is_server) {
1403     if ((rv = dpdk_vhost_user_init_server_sock (sock_filename, &sockfd)) != 0) {
1404         return rv;
1405     }
1406   }
1407
1408   if (renumber) {
1409       // set next vhost-user if id if custom one is higher or equal
1410       if (custom_dev_instance >= dm->next_vu_if_id)
1411           dm->next_vu_if_id = custom_dev_instance + 1;
1412
1413     dpdk_create_vhost_user_if_internal(&hw_if_idx, custom_dev_instance, hwaddr);
1414   } else 
1415     dpdk_create_vhost_user_if_internal(&hw_if_idx, (u32)~0, hwaddr);
1416   DBG_SOCK("dpdk vhost-user interface created hw_if_index %d", hw_if_idx);
1417
1418   xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_idx);
1419   ASSERT(xd != NULL);
1420
1421   dpdk_vhost_user_vui_init (vnm, xd, sockfd, sock_filename, is_server,
1422                             feature_mask, sw_if_index);
1423
1424   dpdk_vhost_user_vui_register (vm, xd);
1425   return rv;
1426 }
1427
1428 int dpdk_vhost_user_modify_if(vnet_main_t * vnm, vlib_main_t * vm,
1429                          const char * sock_filename,
1430                          u8 is_server,
1431                          u32 sw_if_index,
1432                          u64 feature_mask,
1433                          u8 renumber, u32 custom_dev_instance)
1434 {
1435   dpdk_main_t * dm = &dpdk_main;
1436   dpdk_device_t * xd;
1437   dpdk_vu_intf_t * vui = NULL;
1438   u32 sw_if_idx = ~0;
1439   int sockfd = -1;
1440   int rv = 0;
1441
1442   // using virtio vhost user?
1443   if (dm->conf->use_virtio_vhost) {
1444       return vhost_user_modify_if(vnm, vm, sock_filename, is_server,
1445               sw_if_index, feature_mask, renumber, custom_dev_instance);
1446   }
1447
1448   xd = dpdk_vhost_user_device_from_sw_if_index(sw_if_index);
1449
1450   if (xd == NULL)
1451     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1452
1453   vui = xd->vu_intf;
1454
1455   // interface is inactive
1456   vui->active = 0;
1457   // disconnect interface sockets
1458   dpdk_vhost_user_if_disconnect(xd);
1459
1460   if (is_server) {
1461       if ((rv = dpdk_vhost_user_init_server_sock (sock_filename, &sockfd)) != 0) {
1462           return rv;
1463       }
1464   }
1465
1466   dpdk_vhost_user_vui_init (vnm, xd, sockfd, sock_filename, is_server,
1467                        feature_mask, &sw_if_idx);
1468
1469   if (renumber) {
1470     vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
1471   }
1472
1473   dpdk_vhost_user_vui_register (vm, xd);
1474
1475   return rv;
1476 }
1477
1478 int dpdk_vhost_user_delete_if(vnet_main_t * vnm, vlib_main_t * vm,
1479                          u32 sw_if_index)
1480 {
1481   dpdk_main_t * dm = &dpdk_main;
1482   dpdk_device_t * xd = NULL;
1483   dpdk_vu_intf_t * vui;
1484   int rv = 0;
1485
1486   // using virtio vhost user?
1487   if (dm->conf->use_virtio_vhost) {
1488       return vhost_user_delete_if(vnm, vm, sw_if_index);
1489   }
1490
1491   xd = dpdk_vhost_user_device_from_sw_if_index(sw_if_index);
1492
1493   if (xd == NULL)
1494     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1495
1496   vui = xd->vu_intf;
1497
1498   // interface is inactive
1499   vui->active = 0;
1500   // disconnect interface sockets
1501   dpdk_vhost_user_if_disconnect(xd);
1502   // add to inactive interface list
1503   vec_add1 (dm->vu_inactive_interfaces_device_index, xd->device_index);
1504
1505   ethernet_delete_interface (vnm, xd->vlib_hw_if_index);
1506   DBG_SOCK ("deleted (deactivated) vhost-user interface sw_if_index %d", sw_if_index);
1507
1508   return rv;
1509 }
1510
1511 int dpdk_vhost_user_dump_ifs(vnet_main_t * vnm, vlib_main_t * vm, vhost_user_intf_details_t **out_vuids)
1512 {
1513     int rv = 0;
1514     dpdk_main_t * dm = &dpdk_main;
1515     dpdk_device_t * xd;
1516     dpdk_vu_intf_t * vui;
1517     struct virtio_net * vhost_dev;
1518     vhost_user_intf_details_t * r_vuids = NULL;
1519     vhost_user_intf_details_t * vuid = NULL;
1520     u32 * hw_if_indices = 0;
1521     vnet_hw_interface_t * hi;
1522     u8 *s = NULL;
1523     int i;
1524
1525     if (!out_vuids)
1526         return -1;
1527
1528     // using virtio vhost user?
1529     if (dm->conf->use_virtio_vhost) {
1530         return vhost_user_dump_ifs(vnm, vm, out_vuids);
1531     }
1532
1533     vec_foreach (xd, dm->devices) {
1534       if (xd->dev_type == VNET_DPDK_DEV_VHOST_USER &&
1535               xd->vu_intf->active)
1536         vec_add1(hw_if_indices, xd->vlib_hw_if_index);
1537     }
1538
1539     for (i = 0; i < vec_len (hw_if_indices); i++) {
1540       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
1541       xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_indices[i]);
1542       if (!xd) {
1543           clib_warning("invalid vhost-user interface hw_if_index %d", hw_if_indices[i]);
1544           continue;
1545       }
1546
1547       vui = xd->vu_intf;
1548       ASSERT(vui != NULL);
1549       vhost_dev = &xd->vu_vhost_dev;
1550       u32 virtio_net_hdr_sz = (vui->num_vrings > 0 ?
1551             vhost_dev->virtqueue[0]->vhost_hlen : 0);
1552
1553       vec_add2(r_vuids, vuid, 1);
1554       vuid->sw_if_index = xd->vlib_sw_if_index;
1555       vuid->virtio_net_hdr_sz = virtio_net_hdr_sz;
1556       vuid->features = vhost_dev->features;
1557       vuid->is_server = vui->sock_is_server;
1558       vuid->num_regions = (vhost_dev->mem != NULL ? vhost_dev->mem->nregions : 0);
1559       vuid->sock_errno = vui->sock_errno;
1560       strncpy((char *)vuid->sock_filename, (char *)vui->sock_filename,
1561               ARRAY_LEN(vuid->sock_filename)-1);
1562
1563       s = format (s, "%v%c", hi->name, 0);
1564
1565       strncpy((char *)vuid->if_name, (char *)s,
1566               ARRAY_LEN(vuid->if_name)-1);
1567       _vec_len(s) = 0;
1568     }
1569
1570     vec_free (s);
1571     vec_free (hw_if_indices);
1572
1573     *out_vuids = r_vuids;
1574
1575     return rv;
1576 }
1577
1578 /*
1579  * Processing functions called from dpdk process fn
1580  */
1581
1582 typedef struct {
1583     struct sockaddr_un sun;
1584     int sockfd;
1585     unix_file_t template;
1586     uword *event_data;
1587 } dpdk_vu_process_state;
1588
1589 void dpdk_vhost_user_process_init (void **ctx)
1590 {
1591     dpdk_vu_process_state *state = clib_mem_alloc (sizeof(dpdk_vu_process_state));
1592     memset(state, 0, sizeof(*state));
1593     state->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1594     state->sun.sun_family = AF_UNIX;
1595     state->template.read_function = dpdk_vhost_user_socket_read;
1596     state->template.error_function = dpdk_vhost_user_socket_error;
1597     state->event_data = 0;
1598     *ctx = state;
1599 }
1600
1601 void dpdk_vhost_user_process_cleanup (void *ctx)
1602 {
1603     clib_mem_free(ctx);
1604 }
1605
1606 uword dpdk_vhost_user_process_if (vlib_main_t *vm, dpdk_device_t *xd, void *ctx)
1607 {
1608     dpdk_main_t * dm = &dpdk_main;
1609     dpdk_vu_process_state *state = (dpdk_vu_process_state *)ctx;
1610     dpdk_vu_intf_t *vui = xd->vu_intf;
1611
1612     if (vui->sock_is_server || !vui->active)
1613         return 0;
1614
1615     if (vui->unix_fd == -1) {
1616         /* try to connect */
1617         strncpy(state->sun.sun_path,  (char *) vui->sock_filename, sizeof(state->sun.sun_path) - 1);
1618
1619         if (connect(state->sockfd, (struct sockaddr *) &(state->sun), sizeof(struct sockaddr_un)) == 0) {
1620             vui->sock_errno = 0;
1621             vui->unix_fd = state->sockfd;
1622             state->template.file_descriptor = state->sockfd;
1623             vui->unix_file_index = unix_file_add (&unix_main, &(state->template));
1624             hash_set (dm->vu_sw_if_index_by_sock_fd, state->sockfd, xd->vlib_sw_if_index);
1625
1626             state->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1627             if (state->sockfd < 0)
1628                 return -1;
1629         } else {
1630             vui->sock_errno = errno;
1631         }
1632     } else {
1633         /* check if socket is alive */
1634         int error = 0;
1635         socklen_t len = sizeof (error);
1636         int retval = getsockopt(vui->unix_fd, SOL_SOCKET, SO_ERROR, &error, &len);
1637
1638         if (retval)
1639             dpdk_vhost_user_if_disconnect(xd);
1640     }
1641     return 0;
1642 }
1643
1644 /*
1645  * CLI functions
1646  */
1647
1648 static clib_error_t *
1649 dpdk_vhost_user_connect_command_fn (vlib_main_t * vm,
1650                  unformat_input_t * input,
1651                  vlib_cli_command_t * cmd)
1652 {
1653   dpdk_main_t * dm = &dpdk_main;
1654   unformat_input_t _line_input, * line_input = &_line_input;
1655   u8 * sock_filename = NULL;
1656   u32 sw_if_index;
1657   u8 is_server = 0;
1658   u64 feature_mask = (u64)~0;
1659   u8 renumber = 0;
1660   u32 custom_dev_instance = ~0;
1661   u8 hwaddr[6];
1662   u8 *hw = NULL;
1663
1664   if (dm->conf->use_virtio_vhost) {
1665       return vhost_user_connect_command_fn(vm, input, cmd);
1666   }
1667
1668   /* Get a line of input. */
1669   if (! unformat_user (input, unformat_line_input, line_input))
1670     return 0;
1671
1672   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
1673     if (unformat (line_input, "socket %s", &sock_filename))
1674       ;
1675     else if (unformat (line_input, "server"))
1676       is_server = 1;
1677     else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
1678       ;
1679     else if (unformat (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
1680       hw = hwaddr;
1681     else if (unformat (line_input, "renumber %d", &custom_dev_instance)) {
1682         renumber = 1;
1683     }
1684     else
1685       return clib_error_return (0, "unknown input `%U'",
1686                                 format_unformat_error, input);
1687   }
1688   unformat_free (line_input);
1689
1690   vnet_main_t *vnm = vnet_get_main();
1691   if (sock_filename == NULL)
1692       return clib_error_return (0, "missing socket file");
1693
1694   dpdk_vhost_user_create_if(vnm, vm, (char *)sock_filename,
1695                             is_server, &sw_if_index, feature_mask,
1696                             renumber, custom_dev_instance, hw);
1697
1698   vec_free(sock_filename);
1699   vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
1700   return 0;
1701 }
1702
1703 VLIB_CLI_COMMAND (dpdk_vhost_user_connect_command, static) = {
1704     .path = "create vhost-user",
1705     .short_help = "create vhost-user socket <socket-filename> [server] [feature-mask <hex>] [renumber <dev_instance>]",
1706     .function = dpdk_vhost_user_connect_command_fn,
1707 };
1708
1709 static clib_error_t *
1710 dpdk_vhost_user_delete_command_fn (vlib_main_t * vm,
1711                  unformat_input_t * input,
1712                  vlib_cli_command_t * cmd)
1713 {
1714   dpdk_main_t * dm = &dpdk_main;
1715   clib_error_t * error = 0;
1716   unformat_input_t _line_input, * line_input = &_line_input;
1717   u32 sw_if_index = ~0;
1718
1719   if (dm->conf->use_virtio_vhost) {
1720       return vhost_user_delete_command_fn(vm, input, cmd);
1721   }
1722
1723   /* Get a line of input. */
1724   if (! unformat_user (input, unformat_line_input, line_input))
1725     return 0;
1726
1727   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
1728     if (unformat (line_input, "sw_if_index %d", &sw_if_index))
1729       ;
1730     else
1731       return clib_error_return (0, "unknown input `%U'",
1732                                 format_unformat_error, input);
1733   }
1734   unformat_free (line_input);
1735
1736   if (sw_if_index == ~0) {
1737       error = clib_error_return (0, "invalid sw_if_index",
1738                                  format_unformat_error, input);
1739       return error;
1740   }
1741
1742   vnet_main_t *vnm = vnet_get_main();
1743
1744   dpdk_vhost_user_delete_if(vnm, vm, sw_if_index);
1745
1746   return 0;
1747 }
1748
1749 VLIB_CLI_COMMAND (dpdk_vhost_user_delete_command, static) = {
1750     .path = "delete vhost-user",
1751     .short_help = "delete vhost-user sw_if_index <nn>",
1752     .function = dpdk_vhost_user_delete_command_fn,
1753 };
1754
1755 #define foreach_dpdk_vhost_feature      \
1756  _ (VIRTIO_NET_F_MRG_RXBUF)             \
1757  _ (VIRTIO_NET_F_CTRL_VQ)               \
1758  _ (VIRTIO_NET_F_CTRL_RX)
1759
1760 static clib_error_t *
1761 show_dpdk_vhost_user_command_fn (vlib_main_t * vm,
1762                  unformat_input_t * input,
1763                  vlib_cli_command_t * cmd)
1764 {
1765   clib_error_t * error = 0;
1766   dpdk_main_t * dm = &dpdk_main;
1767   vnet_main_t * vnm = vnet_get_main();
1768   dpdk_device_t * xd;
1769   dpdk_vu_intf_t * vui;
1770   struct virtio_net * vhost_dev;
1771   u32 hw_if_index, * hw_if_indices = 0;
1772   vnet_hw_interface_t * hi;
1773   int i, j, q;
1774   int show_descr = 0;
1775   struct virtio_memory * mem;
1776   struct feat_struct { u8 bit; char *str;};
1777   struct feat_struct *feat_entry;
1778
1779   static struct feat_struct feat_array[] = {
1780 #define _(f) { .str = #f, .bit = f, },
1781   foreach_dpdk_vhost_feature
1782 #undef _
1783   { .str = NULL }
1784   };
1785
1786   if (dm->conf->use_virtio_vhost) {
1787     return show_vhost_user_command_fn(vm, input, cmd);
1788   }
1789
1790   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1791     if (unformat (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) {
1792       vec_add1 (hw_if_indices, hw_if_index);
1793       vlib_cli_output(vm, "add %d", hw_if_index);
1794     }
1795     else if (unformat (input, "descriptors") || unformat (input, "desc") )
1796       show_descr = 1;
1797     else {
1798       error = clib_error_return (0, "unknown input `%U'",
1799                                      format_unformat_error, input);
1800       goto done;
1801     }
1802   }
1803   if (vec_len (hw_if_indices) == 0) {
1804     vec_foreach (xd, dm->devices) {
1805       if (xd->dev_type == VNET_DPDK_DEV_VHOST_USER && xd->vu_intf->active)
1806         vec_add1(hw_if_indices, xd->vlib_hw_if_index);
1807     }
1808   }
1809
1810   vlib_cli_output (vm, "DPDK vhost-user interfaces");
1811   vlib_cli_output (vm, "Global:\n  coalesce frames %d time %e\n\n",
1812                    dm->conf->vhost_coalesce_frames, dm->conf->vhost_coalesce_time);
1813
1814   for (i = 0; i < vec_len (hw_if_indices); i++) {
1815     hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
1816
1817     if (!(xd = dpdk_vhost_user_device_from_hw_if_index(hw_if_indices[i]))) {
1818         error = clib_error_return (0, "not dpdk vhost-user interface: '%s'",
1819                                        hi->name);
1820         goto done;
1821     }
1822     vui = xd->vu_intf;
1823     vhost_dev = &xd->vu_vhost_dev;
1824     mem = vhost_dev->mem;
1825     u32 virtio_net_hdr_sz = (vui->num_vrings > 0 ?
1826             vhost_dev->virtqueue[0]->vhost_hlen : 0);
1827
1828     vlib_cli_output (vm, "Interface: %v (ifindex %d)",
1829                          hi->name, hw_if_indices[i]);
1830
1831     vlib_cli_output (vm, "virtio_net_hdr_sz %d\n features (0x%llx): \n",
1832                          virtio_net_hdr_sz, xd->vu_vhost_dev.features);
1833
1834     feat_entry = (struct feat_struct *) &feat_array;
1835     while(feat_entry->str) {
1836       if (xd->vu_vhost_dev.features & (1 << feat_entry->bit))
1837         vlib_cli_output (vm, "   %s (%d)", feat_entry->str, feat_entry->bit);
1838       feat_entry++;
1839     }
1840
1841     vlib_cli_output (vm, "\n");
1842
1843     vlib_cli_output (vm, " socket filename %s type %s errno \"%s\"\n\n",
1844                          vui->sock_filename, vui->sock_is_server ? "server" : "client",
1845                          strerror(vui->sock_errno));
1846
1847     vlib_cli_output (vm, " Memory regions (total %d)\n", mem->nregions);
1848
1849     if (mem->nregions){
1850       vlib_cli_output(vm, " region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr\n");
1851       vlib_cli_output(vm, " ====== ===== ================== ================== ================== ================== ==================\n");
1852     }
1853     for (j = 0; j < mem->nregions; j++) {
1854       vlib_cli_output(vm, "  %d     %-5d 0x%016lx 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n", j,
1855         vui->region_fd[j],
1856         mem->regions[j].guest_phys_address,
1857         mem->regions[j].memory_size,
1858         mem->regions[j].userspace_address,
1859         mem->regions[j].address_offset,
1860         vui->region_addr[j]);
1861     }
1862     for (q = 0; q < vui->num_vrings; q++) {
1863       struct vhost_virtqueue *vq = vhost_dev->virtqueue[q];
1864       const char *qtype = (q & 1) ? "TX" : "RX";
1865
1866       vlib_cli_output(vm, "\n Virtqueue %d (%s)\n", q/2, qtype);
1867
1868       vlib_cli_output(vm, "  qsz %d last_used_idx %d last_used_idx_res %d\n",
1869               vq->size, vq->last_used_idx, vq->last_used_idx_res);
1870
1871       if (vq->avail && vq->used)
1872         vlib_cli_output(vm, "  avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
1873           vq->avail->flags, vq->avail->idx, vq->used->flags, vq->used->idx);
1874
1875       vlib_cli_output(vm, "  kickfd %d callfd %d errfd %d enabled %d\n",
1876         vq->kickfd, vq->callfd, vui->vrings[q].errfd, vq->enabled);
1877
1878       if (show_descr && vq->enabled) {
1879         vlib_cli_output(vm, "\n  descriptor table:\n");
1880         vlib_cli_output(vm, "   id          addr         len  flags  next      user_addr\n");
1881         vlib_cli_output(vm, "  ===== ================== ===== ====== ===== ==================\n");
1882         for(j = 0; j < vq->size; j++) {
1883           vlib_cli_output(vm, "  %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
1884             j,
1885             vq->desc[j].addr,
1886             vq->desc[j].len,
1887             vq->desc[j].flags,
1888             vq->desc[j].next,
1889             pointer_to_uword(map_guest_mem(xd, vq->desc[j].addr)));}
1890       }
1891     }
1892     vlib_cli_output (vm, "\n");
1893   }
1894 done:
1895   vec_free (hw_if_indices);
1896   return error;
1897 }
1898
1899 VLIB_CLI_COMMAND (show_vhost_user_command, static) = {
1900     .path = "show vhost-user",
1901     .short_help = "show vhost-user interface",
1902     .function = show_dpdk_vhost_user_command_fn,
1903 };