virtio: fix the packet buffering initialization order
[vpp.git] / src / vnet / devices / virtio / virtio.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <net/if.h>
22 #include <linux/if_tun.h>
23 #include <sys/ioctl.h>
24 #include <sys/eventfd.h>
25
26 #include <vlib/vlib.h>
27 #include <vlib/pci/pci.h>
28 #include <vlib/unix/unix.h>
29 #include <vnet/ethernet/ethernet.h>
30 #include <vnet/ip/ip4_packet.h>
31 #include <vnet/ip/ip6_packet.h>
32 #include <vnet/devices/virtio/virtio.h>
33 #include <vnet/devices/virtio/virtio_inline.h>
34 #include <vnet/devices/virtio/pci.h>
35 #include <vnet/interface/rx_queue_funcs.h>
36 #include <vnet/interface/tx_queue_funcs.h>
37
38 virtio_main_t virtio_main;
39
40 #define _IOCTL(fd,a,...) \
41   if (ioctl (fd, a, __VA_ARGS__) < 0) \
42     { \
43       err = clib_error_return_unix (0, "ioctl(" #a ")"); \
44       goto error; \
45     }
46
47 static clib_error_t *
48 call_read_ready (clib_file_t * uf)
49 {
50   vnet_main_t *vnm = vnet_get_main ();
51   u64 b;
52
53   CLIB_UNUSED (ssize_t size) = read (uf->file_descriptor, &b, sizeof (b));
54   vnet_hw_if_rx_queue_set_int_pending (vnm, uf->private_data);
55
56   return 0;
57 }
58
59
60 clib_error_t *
61 virtio_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 idx, u16 sz)
62 {
63   vnet_virtio_vring_t *vring;
64   int i;
65
66   if (!is_pow2 (sz))
67     return clib_error_return (0, "ring size must be power of 2");
68
69   if (sz > 32768)
70     return clib_error_return (0, "ring size must be 32768 or lower");
71
72   if (sz == 0)
73     sz = 256;
74
75   if (idx % 2)
76     {
77       vec_validate_aligned (vif->txq_vrings, TX_QUEUE_ACCESS (idx),
78                             CLIB_CACHE_LINE_BYTES);
79       vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (idx));
80       clib_spinlock_init (&vring->lockp);
81     }
82   else
83     {
84       vec_validate_aligned (vif->rxq_vrings, RX_QUEUE_ACCESS (idx),
85                             CLIB_CACHE_LINE_BYTES);
86       vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (idx));
87     }
88   i = sizeof (vnet_virtio_vring_desc_t) * sz;
89   i = round_pow2 (i, CLIB_CACHE_LINE_BYTES);
90   vring->desc = clib_mem_alloc_aligned (i, CLIB_CACHE_LINE_BYTES);
91   clib_memset (vring->desc, 0, i);
92
93   i = sizeof (vnet_virtio_vring_avail_t) + sz * sizeof (vring->avail->ring[0]);
94   i = round_pow2 (i, CLIB_CACHE_LINE_BYTES);
95   vring->avail = clib_mem_alloc_aligned (i, CLIB_CACHE_LINE_BYTES);
96   clib_memset (vring->avail, 0, i);
97   // tell kernel that we don't need interrupt
98   vring->avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
99
100   i = sizeof (vnet_virtio_vring_used_t) +
101       sz * sizeof (vnet_virtio_vring_used_elem_t);
102   i = round_pow2 (i, CLIB_CACHE_LINE_BYTES);
103   vring->used = clib_mem_alloc_aligned (i, CLIB_CACHE_LINE_BYTES);
104   clib_memset (vring->used, 0, i);
105
106   vring->queue_id = idx;
107   ASSERT (vring->buffers == 0);
108   vec_validate_aligned (vring->buffers, sz, CLIB_CACHE_LINE_BYTES);
109
110   if (idx & 1)
111     {
112       clib_memset_u32 (vring->buffers, ~0, sz);
113       // tx path: suppress the interrupts from kernel
114       vring->call_fd = -1;
115     }
116   else
117     vring->call_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
118
119   vring->total_packets = 0;
120   vring->queue_size = sz;
121   vring->kick_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
122   virtio_log_debug (vif, "vring %u size %u call_fd %d kick_fd %d", idx,
123                     vring->queue_size, vring->call_fd, vring->kick_fd);
124
125   return 0;
126 }
127
128 inline void
129 virtio_free_buffers (vlib_main_t *vm, vnet_virtio_vring_t *vring)
130 {
131   u16 used = vring->desc_in_use;
132   u16 last = vring->last_used_idx;
133   u16 mask = vring->queue_size - 1;
134
135   while (used)
136     {
137       vlib_buffer_free (vm, &vring->buffers[last & mask], 1);
138       last++;
139       used--;
140     }
141 }
142
143 clib_error_t *
144 virtio_vring_free_rx (vlib_main_t * vm, virtio_if_t * vif, u32 idx)
145 {
146   vnet_virtio_vring_t *vring =
147     vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (idx));
148
149   clib_file_del_by_index (&file_main, vring->call_file_index);
150   close (vring->kick_fd);
151   close (vring->call_fd);
152   if (vring->used)
153     {
154       virtio_free_buffers (vm, vring);
155       clib_mem_free (vring->used);
156     }
157   if (vring->desc)
158     clib_mem_free (vring->desc);
159   if (vring->avail)
160     clib_mem_free (vring->avail);
161   vec_free (vring->buffers);
162   return 0;
163 }
164
165 clib_error_t *
166 virtio_vring_free_tx (vlib_main_t * vm, virtio_if_t * vif, u32 idx)
167 {
168   vnet_virtio_vring_t *vring =
169     vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (idx));
170
171   close (vring->kick_fd);
172   if (vring->used)
173     {
174       virtio_free_buffers (vm, vring);
175       clib_mem_free (vring->used);
176     }
177   if (vring->desc)
178     clib_mem_free (vring->desc);
179   if (vring->avail)
180     clib_mem_free (vring->avail);
181   vec_free (vring->buffers);
182   gro_flow_table_free (vring->flow_table);
183   virtio_vring_buffering_free (vm, vring->buffering);
184   clib_spinlock_free (&vring->lockp);
185   return 0;
186 }
187
188 void
189 virtio_set_packet_coalesce (virtio_if_t * vif)
190 {
191   vnet_main_t *vnm = vnet_get_main ();
192   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
193   vnet_virtio_vring_t *vring;
194   vif->packet_coalesce = 1;
195   vec_foreach (vring, vif->txq_vrings)
196   {
197     gro_flow_table_init (&vring->flow_table,
198                          vif->type & (VIRTIO_IF_TYPE_TAP |
199                                       VIRTIO_IF_TYPE_PCI), hw->tx_node_index);
200   }
201 }
202
203 clib_error_t *
204 virtio_set_packet_buffering (virtio_if_t * vif, u16 buffering_size)
205 {
206   vnet_main_t *vnm = vnet_get_main ();
207   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
208   vnet_virtio_vring_t *vring;
209   clib_error_t *error = 0;
210
211   vec_foreach (vring, vif->txq_vrings)
212   {
213     if ((error =
214          virtio_vring_buffering_init (&vring->buffering, hw->tx_node_index,
215                                       buffering_size)))
216       {
217         break;
218       }
219   }
220
221   return error;
222 }
223
224 static void
225 virtio_vring_fill (vlib_main_t *vm, virtio_if_t *vif,
226                    vnet_virtio_vring_t *vring)
227 {
228   if (vif->is_packed)
229     virtio_refill_vring_packed (vm, vif, vif->type, vring,
230                                 vif->virtio_net_hdr_sz,
231                                 virtio_input_node.index);
232   else
233     virtio_refill_vring_split (vm, vif, vif->type, vring,
234                                vif->virtio_net_hdr_sz,
235                                virtio_input_node.index);
236 }
237
238 void
239 virtio_vring_set_rx_queues (vlib_main_t *vm, virtio_if_t *vif)
240 {
241   vnet_main_t *vnm = vnet_get_main ();
242   vnet_virtio_vring_t *vring;
243   u32 i = 0;
244
245   vnet_hw_if_set_input_node (vnm, vif->hw_if_index, virtio_input_node.index);
246
247   vec_foreach (vring, vif->rxq_vrings)
248     {
249       vring->queue_index = vnet_hw_if_register_rx_queue (
250         vnm, vif->hw_if_index, RX_QUEUE_ACCESS (vring->queue_id),
251         VNET_HW_IF_RXQ_THREAD_ANY);
252       vring->buffer_pool_index = vlib_buffer_pool_get_default_for_numa (
253         vm, vnet_hw_if_get_rx_queue_numa_node (vnm, vring->queue_index));
254       if (vif->type == VIRTIO_IF_TYPE_TAP || vif->type == VIRTIO_IF_TYPE_TUN)
255         {
256
257           clib_file_t f = {
258             .read_function = call_read_ready,
259             .flags = UNIX_FILE_EVENT_EDGE_TRIGGERED,
260             .file_descriptor = vring->call_fd,
261             .private_data = vring->queue_index,
262             .description = format (0, "%U vring %u", format_virtio_device_name,
263                                    vif->dev_instance, vring->queue_id),
264           };
265
266           vring->call_file_index = clib_file_add (&file_main, &f);
267           vnet_hw_if_set_rx_queue_file_index (vnm, vring->queue_index,
268                                               vring->call_file_index);
269         }
270       else if ((vif->type == VIRTIO_IF_TYPE_PCI) && (vif->support_int_mode) &&
271                (vif->msix_enabled == VIRTIO_MSIX_ENABLED))
272         {
273           u32 file_index;
274           file_index =
275             vlib_pci_get_msix_file_index (vm, vif->pci_dev_handle, i + 1);
276           vnet_hw_if_set_rx_queue_file_index (vnm, vring->queue_index,
277                                               file_index);
278           i++;
279         }
280       vnet_hw_if_set_rx_queue_mode (vnm, vring->queue_index,
281                                     VNET_HW_IF_RX_MODE_POLLING);
282       vring->mode = VNET_HW_IF_RX_MODE_POLLING;
283       virtio_vring_fill (vm, vif, vring);
284     }
285   vnet_hw_if_update_runtime_data (vnm, vif->hw_if_index);
286 }
287
288 void
289 virtio_vring_set_tx_queues (vlib_main_t *vm, virtio_if_t *vif)
290 {
291   vnet_main_t *vnm = vnet_get_main ();
292   vnet_virtio_vring_t *vring;
293
294   vec_foreach (vring, vif->txq_vrings)
295     {
296       vring->queue_index = vnet_hw_if_register_tx_queue (
297         vnm, vif->hw_if_index, TX_QUEUE_ACCESS (vring->queue_id));
298     }
299
300   if (vif->num_txqs == 0)
301     {
302       virtio_log_error (vif, "Interface %U has 0 txq",
303                         format_vnet_hw_if_index_name, vnm, vif->hw_if_index);
304       return;
305     }
306
307   for (u32 j = 0; j < vlib_get_n_threads (); j++)
308     {
309       u32 qi = vif->txq_vrings[j % vif->num_txqs].queue_index;
310       vnet_hw_if_tx_queue_assign_thread (vnm, qi, j);
311     }
312
313   vnet_hw_if_update_runtime_data (vnm, vif->hw_if_index);
314 }
315
316 inline void
317 virtio_set_net_hdr_size (virtio_if_t * vif)
318 {
319   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF) ||
320       vif->features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1))
321     vif->virtio_net_hdr_sz = sizeof (vnet_virtio_net_hdr_v1_t);
322   else
323     vif->virtio_net_hdr_sz = sizeof (vnet_virtio_net_hdr_t);
324 }
325
326 inline void
327 virtio_show (vlib_main_t *vm, u32 *hw_if_indices, u8 show_descr,
328              virtio_if_type_t type)
329 {
330   u32 i, j, hw_if_index;
331   virtio_if_t *vif;
332   vnet_main_t *vnm = &vnet_main;
333   virtio_main_t *mm = &virtio_main;
334   vnet_virtio_vring_t *vring;
335   struct feat_struct
336   {
337     u8 bit;
338     char *str;
339   };
340   struct feat_struct *feat_entry;
341
342   static struct feat_struct feat_array[] = {
343 #define _(s,b) { .str = #s, .bit = b, },
344     foreach_virtio_net_features
345 #undef _
346     {.str = NULL}
347   };
348
349   struct feat_struct *flag_entry;
350   static struct feat_struct flags_array[] = {
351 #define _(b,e,s) { .bit = b, .str = s, },
352     foreach_virtio_if_flag
353 #undef _
354     {.str = NULL}
355   };
356
357   if (!hw_if_indices)
358     return;
359
360   for (hw_if_index = 0; hw_if_index < vec_len (hw_if_indices); hw_if_index++)
361     {
362       vnet_hw_interface_t *hi =
363         vnet_get_hw_interface (vnm, hw_if_indices[hw_if_index]);
364       vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
365       if (vif->type != type)
366         continue;
367       vlib_cli_output (vm, "Interface: %U (ifindex %d)",
368                        format_vnet_hw_if_index_name, vnm,
369                        hw_if_indices[hw_if_index], vif->hw_if_index);
370       if (type == VIRTIO_IF_TYPE_PCI)
371         {
372           vlib_cli_output (vm, "  PCI Address: %U", format_vlib_pci_addr,
373                            &vif->pci_addr);
374         }
375       if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
376         {
377           u8 *str = 0;
378           if (vif->host_if_name)
379             vlib_cli_output (vm, "  name \"%s\"", vif->host_if_name);
380           if (vif->net_ns)
381             vlib_cli_output (vm, "  host-ns \"%s\"", vif->net_ns);
382           if (vif->host_mtu_size)
383             vlib_cli_output (vm, "  host-mtu-size \"%d\"",
384                              vif->host_mtu_size);
385           if (type == VIRTIO_IF_TYPE_TAP)
386             vlib_cli_output (vm, "  host-mac-addr: %U",
387                              format_ethernet_address, vif->host_mac_addr);
388           vlib_cli_output (vm, "  host-carrier-up: %u", vif->host_carrier_up);
389
390           vec_foreach_index (i, vif->vhost_fds)
391             str = format (str, " %d", vif->vhost_fds[i]);
392           vlib_cli_output (vm, "  vhost-fds%v", str);
393           vec_free (str);
394           vec_foreach_index (i, vif->tap_fds)
395             str = format (str, " %d", vif->tap_fds[i]);
396           vlib_cli_output (vm, "  tap-fds%v", str);
397           vec_free (str);
398         }
399       vlib_cli_output (vm, "  gso-enabled %d", vif->gso_enabled);
400       vlib_cli_output (vm, "  csum-enabled %d", vif->csum_offload_enabled);
401       vlib_cli_output (vm, "  packet-coalesce %d", vif->packet_coalesce);
402       vlib_cli_output (vm, "  packet-buffering %d", vif->packet_buffering);
403       if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_PCI))
404         vlib_cli_output (vm, "  Mac Address: %U", format_ethernet_address,
405                          vif->mac_addr);
406       vlib_cli_output (vm, "  Device instance: %u", vif->dev_instance);
407       vlib_cli_output (vm, "  flags 0x%x", vif->flags);
408       flag_entry = (struct feat_struct *) &flags_array;
409       while (flag_entry->str)
410         {
411           if (vif->flags & (1ULL << flag_entry->bit))
412             vlib_cli_output (vm, "    %s (%d)", flag_entry->str,
413                              flag_entry->bit);
414           flag_entry++;
415         }
416       if (type == VIRTIO_IF_TYPE_PCI)
417         {
418           device_status (vm, vif);
419         }
420       vlib_cli_output (vm, "  features 0x%lx", vif->features);
421       feat_entry = (struct feat_struct *) &feat_array;
422       while (feat_entry->str)
423         {
424           if (vif->features & (1ULL << feat_entry->bit))
425             vlib_cli_output (vm, "    %s (%d)", feat_entry->str,
426                              feat_entry->bit);
427           feat_entry++;
428         }
429       vlib_cli_output (vm, "  remote-features 0x%lx", vif->remote_features);
430       feat_entry = (struct feat_struct *) &feat_array;
431       while (feat_entry->str)
432         {
433           if (vif->remote_features & (1ULL << feat_entry->bit))
434             vlib_cli_output (vm, "    %s (%d)", feat_entry->str,
435                              feat_entry->bit);
436           feat_entry++;
437         }
438       vlib_cli_output (vm, "  Number of RX Virtqueue  %u", vif->num_rxqs);
439       vlib_cli_output (vm, "  Number of TX Virtqueue  %u", vif->num_txqs);
440       if (type == VIRTIO_IF_TYPE_PCI && vif->cxq_vring != NULL &&
441           vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
442         vlib_cli_output (vm, "  Number of CTRL Virtqueue 1");
443       vec_foreach_index (i, vif->rxq_vrings)
444       {
445         vring = vec_elt_at_index (vif->rxq_vrings, i);
446         vlib_cli_output (vm, "  Virtqueue (RX) %d", vring->queue_id);
447         vlib_cli_output (
448           vm, "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
449           vring->queue_size, vring->last_used_idx, vring->desc_next,
450           vring->desc_in_use);
451         if (vif->is_packed)
452           {
453             vlib_cli_output (vm,
454                              "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
455                              vring->driver_event->flags,
456                              vring->driver_event->off_wrap,
457                              vring->device_event->flags,
458                              vring->device_event->off_wrap);
459             vlib_cli_output (vm,
460                              "    avail wrap counter %d, used wrap counter %d",
461                              vring->avail_wrap_counter,
462                              vring->used_wrap_counter);
463           }
464         else
465           vlib_cli_output (vm,
466                            "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
467                            vring->avail->flags, vring->avail->idx,
468                            vring->used->flags, vring->used->idx);
469         if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
470           {
471             vlib_cli_output (vm, "    kickfd %d, callfd %d", vring->kick_fd,
472                              vring->call_fd);
473           }
474         if (show_descr)
475           {
476             vlib_cli_output (vm, "\n  descriptor table:\n");
477             vlib_cli_output (vm,
478                              "   id          addr         len  flags  next/id      user_addr\n");
479             vlib_cli_output (vm,
480                              "  ===== ================== ===== ====== ======= ==================\n");
481             for (j = 0; j < vring->queue_size; j++)
482               {
483                 if (vif->is_packed)
484                   {
485                     vnet_virtio_vring_packed_desc_t *desc =
486                       &vring->packed_desc[j];
487                     vlib_cli_output (vm,
488                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
489                                      j, desc->addr,
490                                      desc->len,
491                                      desc->flags, desc->id, desc->addr);
492                   }
493                 else
494                   {
495                     vnet_virtio_vring_desc_t *desc = &vring->desc[j];
496                     vlib_cli_output (vm,
497                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
498                                      j, desc->addr,
499                                      desc->len,
500                                      desc->flags, desc->next, desc->addr);
501                   }
502               }
503           }
504       }
505       vec_foreach_index (i, vif->txq_vrings)
506       {
507         vring = vec_elt_at_index (vif->txq_vrings, i);
508         vlib_cli_output (vm, "  Virtqueue (TX) %d", vring->queue_id);
509         vlib_cli_output (
510           vm, "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
511           vring->queue_size, vring->last_used_idx, vring->desc_next,
512           vring->desc_in_use);
513         if (vif->is_packed)
514           {
515             vlib_cli_output (vm,
516                              "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
517                              vring->driver_event->flags,
518                              vring->driver_event->off_wrap,
519                              vring->device_event->flags,
520                              vring->device_event->off_wrap);
521             vlib_cli_output (vm,
522                              "    avail wrap counter %d, used wrap counter %d",
523                              vring->avail_wrap_counter,
524                              vring->used_wrap_counter);
525           }
526         else
527           vlib_cli_output (vm,
528                            "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
529                            vring->avail->flags, vring->avail->idx,
530                            vring->used->flags, vring->used->idx);
531         if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
532           {
533             vlib_cli_output (vm, "    kickfd %d, callfd %d", vring->kick_fd,
534                              vring->call_fd);
535           }
536         if (vring->flow_table)
537           {
538             vlib_cli_output (vm, "    %U", gro_flow_table_format,
539                              vring->flow_table);
540           }
541         if (vif->packet_buffering)
542           {
543             vlib_cli_output (vm, "    %U", virtio_vring_buffering_format,
544                              vring->buffering);
545           }
546         if (show_descr)
547           {
548             vlib_cli_output (vm, "\n  descriptor table:\n");
549             vlib_cli_output (vm,
550                              "   id          addr         len  flags  next/id      user_addr\n");
551             vlib_cli_output (vm,
552                              "  ===== ================== ===== ====== ======== ==================\n");
553             for (j = 0; j < vring->queue_size; j++)
554               {
555                 if (vif->is_packed)
556                   {
557                     vnet_virtio_vring_packed_desc_t *desc =
558                       &vring->packed_desc[j];
559                     vlib_cli_output (vm,
560                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
561                                      j, desc->addr,
562                                      desc->len,
563                                      desc->flags, desc->id, desc->addr);
564                   }
565                 else
566                   {
567                     vnet_virtio_vring_desc_t *desc = &vring->desc[j];
568                     vlib_cli_output (vm,
569                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
570                                      j, desc->addr,
571                                      desc->len,
572                                      desc->flags, desc->next, desc->addr);
573                   }
574               }
575           }
576       }
577       if (type == VIRTIO_IF_TYPE_PCI && vif->cxq_vring != NULL &&
578           vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
579         {
580           vring = vif->cxq_vring;
581           vlib_cli_output (vm, "  Virtqueue (CTRL) %d", vring->queue_id);
582           vlib_cli_output (
583             vm, "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
584             vring->queue_size, vring->last_used_idx, vring->desc_next,
585             vring->desc_in_use);
586           if (vif->is_packed)
587             {
588               vlib_cli_output (vm,
589                                "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
590                                vring->driver_event->flags,
591                                vring->driver_event->off_wrap,
592                                vring->device_event->flags,
593                                vring->device_event->off_wrap);
594               vlib_cli_output (vm,
595                                "    avail wrap counter %d, used wrap counter %d",
596                                vring->avail_wrap_counter,
597                                vring->used_wrap_counter);
598             }
599           else
600             {
601               vlib_cli_output (vm,
602                                "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
603                                vring->avail->flags, vring->avail->idx,
604                                vring->used->flags, vring->used->idx);
605             }
606           if (show_descr)
607             {
608               vlib_cli_output (vm, "\n  descriptor table:\n");
609               vlib_cli_output (vm,
610                                "   id          addr         len  flags  next/id      user_addr\n");
611               vlib_cli_output (vm,
612                                "  ===== ================== ===== ====== ======== ==================\n");
613               for (j = 0; j < vring->queue_size; j++)
614                 {
615                   if (vif->is_packed)
616                     {
617                       vnet_virtio_vring_packed_desc_t *desc =
618                         &vring->packed_desc[j];
619                       vlib_cli_output (vm,
620                                        "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
621                                        j, desc->addr,
622                                        desc->len,
623                                        desc->flags, desc->id, desc->addr);
624                     }
625                   else
626                     {
627                       vnet_virtio_vring_desc_t *desc = &vring->desc[j];
628                       vlib_cli_output (vm,
629                                        "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
630                                        j, desc->addr,
631                                        desc->len,
632                                        desc->flags, desc->next, desc->addr);
633                     }
634                 }
635             }
636         }
637     }
638
639 }
640
641 static clib_error_t *
642 virtio_init (vlib_main_t * vm)
643 {
644   virtio_main_t *vim = &virtio_main;
645   clib_error_t *error = 0;
646
647   vim->log_default = vlib_log_register_class ("virtio", 0);
648   vlib_log_debug (vim->log_default, "initialized");
649
650   return error;
651 }
652
653 VLIB_INIT_FUNCTION (virtio_init);
654
655 /*
656  * fd.io coding-style-patch-verification: ON
657  *
658  * Local Variables:
659  * eval: (c-set-style "gnu")
660  * End:
661  */