2d1edfecb6773d5473103fe7045bad4205ddff20
[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   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 (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 (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 (vring_used_t) + sz * sizeof (vring_used_elem_t);
101   i = round_pow2 (i, CLIB_CACHE_LINE_BYTES);
102   vring->used = clib_mem_alloc_aligned (i, CLIB_CACHE_LINE_BYTES);
103   clib_memset (vring->used, 0, i);
104
105   vring->queue_id = idx;
106   ASSERT (vring->buffers == 0);
107   vec_validate_aligned (vring->buffers, sz, CLIB_CACHE_LINE_BYTES);
108
109   if (idx & 1)
110     {
111       clib_memset_u32 (vring->buffers, ~0, sz);
112       // tx path: suppress the interrupts from kernel
113       vring->call_fd = -1;
114     }
115   else
116     vring->call_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
117
118   vring->size = sz;
119   vring->kick_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
120   virtio_log_debug (vif, "vring %u size %u call_fd %d kick_fd %d", idx,
121                     vring->size, vring->call_fd, vring->kick_fd);
122
123   return 0;
124 }
125
126 inline void
127 virtio_free_buffers (vlib_main_t * vm, virtio_vring_t * vring)
128 {
129   u16 used = vring->desc_in_use;
130   u16 last = vring->last_used_idx;
131   u16 mask = vring->size - 1;
132
133   while (used)
134     {
135       vlib_buffer_free (vm, &vring->buffers[last & mask], 1);
136       last++;
137       used--;
138     }
139 }
140
141 clib_error_t *
142 virtio_vring_free_rx (vlib_main_t * vm, virtio_if_t * vif, u32 idx)
143 {
144   virtio_vring_t *vring =
145     vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (idx));
146
147   clib_file_del_by_index (&file_main, vring->call_file_index);
148   close (vring->kick_fd);
149   close (vring->call_fd);
150   if (vring->used)
151     {
152       virtio_free_buffers (vm, vring);
153       clib_mem_free (vring->used);
154     }
155   if (vring->desc)
156     clib_mem_free (vring->desc);
157   if (vring->avail)
158     clib_mem_free (vring->avail);
159   vec_free (vring->buffers);
160   return 0;
161 }
162
163 clib_error_t *
164 virtio_vring_free_tx (vlib_main_t * vm, virtio_if_t * vif, u32 idx)
165 {
166   virtio_vring_t *vring =
167     vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (idx));
168
169   close (vring->kick_fd);
170   if (vring->used)
171     {
172       virtio_free_buffers (vm, vring);
173       clib_mem_free (vring->used);
174     }
175   if (vring->desc)
176     clib_mem_free (vring->desc);
177   if (vring->avail)
178     clib_mem_free (vring->avail);
179   vec_free (vring->buffers);
180   gro_flow_table_free (vring->flow_table);
181   virtio_vring_buffering_free (vm, vring->buffering);
182   clib_spinlock_free (&vring->lockp);
183   return 0;
184 }
185
186 void
187 virtio_set_packet_coalesce (virtio_if_t * vif)
188 {
189   vnet_main_t *vnm = vnet_get_main ();
190   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
191   virtio_vring_t *vring;
192   vif->packet_coalesce = 1;
193   vec_foreach (vring, vif->txq_vrings)
194   {
195     gro_flow_table_init (&vring->flow_table,
196                          vif->type & (VIRTIO_IF_TYPE_TAP |
197                                       VIRTIO_IF_TYPE_PCI), hw->tx_node_index);
198   }
199 }
200
201 clib_error_t *
202 virtio_set_packet_buffering (virtio_if_t * vif, u16 buffering_size)
203 {
204   vnet_main_t *vnm = vnet_get_main ();
205   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
206   virtio_vring_t *vring;
207   clib_error_t *error = 0;
208   vif->packet_buffering = 1;
209
210   vec_foreach (vring, vif->txq_vrings)
211   {
212     if ((error =
213          virtio_vring_buffering_init (&vring->buffering, hw->tx_node_index,
214                                       buffering_size)))
215       {
216         break;
217       }
218   }
219
220   return error;
221 }
222
223 static void
224 virtio_vring_fill (vlib_main_t *vm, virtio_if_t *vif, virtio_vring_t *vring)
225 {
226   if (vif->is_packed)
227     virtio_refill_vring_packed (vm, vif, vif->type, vring,
228                                 vif->virtio_net_hdr_sz,
229                                 virtio_input_node.index);
230   else
231     virtio_refill_vring_split (vm, vif, vif->type, vring,
232                                vif->virtio_net_hdr_sz,
233                                virtio_input_node.index);
234 }
235
236 void
237 virtio_vring_set_rx_queues (vlib_main_t *vm, virtio_if_t *vif)
238 {
239   vnet_main_t *vnm = vnet_get_main ();
240   virtio_vring_t *vring;
241   u32 i = 0;
242
243   vnet_hw_if_set_input_node (vnm, vif->hw_if_index, virtio_input_node.index);
244
245   vec_foreach (vring, vif->rxq_vrings)
246     {
247       vring->queue_index = vnet_hw_if_register_rx_queue (
248         vnm, vif->hw_if_index, RX_QUEUE_ACCESS (vring->queue_id),
249         VNET_HW_IF_RXQ_THREAD_ANY);
250       vring->buffer_pool_index = vlib_buffer_pool_get_default_for_numa (
251         vm, vnet_hw_if_get_rx_queue_numa_node (vnm, vring->queue_index));
252       if (vif->type == VIRTIO_IF_TYPE_TAP || vif->type == VIRTIO_IF_TYPE_TUN)
253         {
254
255           clib_file_t f = {
256             .read_function = call_read_ready,
257             .flags = UNIX_FILE_EVENT_EDGE_TRIGGERED,
258             .file_descriptor = vring->call_fd,
259             .private_data = vring->queue_index,
260             .description = format (0, "%U vring %u", format_virtio_device_name,
261                                    vif->dev_instance, vring->queue_id),
262           };
263
264           vring->call_file_index = clib_file_add (&file_main, &f);
265           vnet_hw_if_set_rx_queue_file_index (vnm, vring->queue_index,
266                                               vring->call_file_index);
267         }
268       else if ((vif->type == VIRTIO_IF_TYPE_PCI) && (vif->support_int_mode) &&
269                (vif->msix_enabled == VIRTIO_MSIX_ENABLED))
270         {
271           u32 file_index;
272           file_index =
273             vlib_pci_get_msix_file_index (vm, vif->pci_dev_handle, i + 1);
274           vnet_hw_if_set_rx_queue_file_index (vnm, vring->queue_index,
275                                               file_index);
276           i++;
277         }
278       vnet_hw_if_set_rx_queue_mode (vnm, vring->queue_index,
279                                     VNET_HW_IF_RX_MODE_POLLING);
280       vring->mode = VNET_HW_IF_RX_MODE_POLLING;
281       virtio_vring_fill (vm, vif, vring);
282     }
283   vnet_hw_if_update_runtime_data (vnm, vif->hw_if_index);
284 }
285
286 void
287 virtio_vring_set_tx_queues (vlib_main_t *vm, virtio_if_t *vif)
288 {
289   vnet_main_t *vnm = vnet_get_main ();
290   virtio_vring_t *vring;
291
292   vec_foreach (vring, vif->txq_vrings)
293     {
294       vring->queue_index = vnet_hw_if_register_tx_queue (
295         vnm, vif->hw_if_index, TX_QUEUE_ACCESS (vring->queue_id));
296     }
297
298   for (u32 j = 0; j < vlib_get_n_threads (); j++)
299     {
300       u32 qi = vif->txq_vrings[j % vif->num_txqs].queue_index;
301       vnet_hw_if_tx_queue_assign_thread (vnm, qi, j);
302     }
303
304   vnet_hw_if_update_runtime_data (vnm, vif->hw_if_index);
305 }
306
307 inline void
308 virtio_set_net_hdr_size (virtio_if_t * vif)
309 {
310   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF) ||
311       vif->features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1))
312     vif->virtio_net_hdr_sz = sizeof (virtio_net_hdr_v1_t);
313   else
314     vif->virtio_net_hdr_sz = sizeof (virtio_net_hdr_t);
315 }
316
317 inline void
318 virtio_show (vlib_main_t *vm, u32 *hw_if_indices, u8 show_descr,
319              virtio_if_type_t type)
320 {
321   u32 i, j, hw_if_index;
322   virtio_if_t *vif;
323   vnet_main_t *vnm = &vnet_main;
324   virtio_main_t *mm = &virtio_main;
325   virtio_vring_t *vring;
326   struct feat_struct
327   {
328     u8 bit;
329     char *str;
330   };
331   struct feat_struct *feat_entry;
332
333   static struct feat_struct feat_array[] = {
334 #define _(s,b) { .str = #s, .bit = b, },
335     foreach_virtio_net_features
336 #undef _
337     {.str = NULL}
338   };
339
340   struct feat_struct *flag_entry;
341   static struct feat_struct flags_array[] = {
342 #define _(b,e,s) { .bit = b, .str = s, },
343     foreach_virtio_if_flag
344 #undef _
345     {.str = NULL}
346   };
347
348   if (!hw_if_indices)
349     return;
350
351   for (hw_if_index = 0; hw_if_index < vec_len (hw_if_indices); hw_if_index++)
352     {
353       vnet_hw_interface_t *hi =
354         vnet_get_hw_interface (vnm, hw_if_indices[hw_if_index]);
355       vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
356       if (vif->type != type)
357         continue;
358       vlib_cli_output (vm, "Interface: %U (ifindex %d)",
359                        format_vnet_hw_if_index_name, vnm,
360                        hw_if_indices[hw_if_index], vif->hw_if_index);
361       if (type == VIRTIO_IF_TYPE_PCI)
362         {
363           vlib_cli_output (vm, "  PCI Address: %U", format_vlib_pci_addr,
364                            &vif->pci_addr);
365         }
366       if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
367         {
368           u8 *str = 0;
369           if (vif->host_if_name)
370             vlib_cli_output (vm, "  name \"%s\"", vif->host_if_name);
371           if (vif->net_ns)
372             vlib_cli_output (vm, "  host-ns \"%s\"", vif->net_ns);
373           if (vif->host_mtu_size)
374             vlib_cli_output (vm, "  host-mtu-size \"%d\"",
375                              vif->host_mtu_size);
376           if (type == VIRTIO_IF_TYPE_TAP)
377             vlib_cli_output (vm, "  host-mac-addr: %U",
378                              format_ethernet_address, vif->host_mac_addr);
379           vlib_cli_output (vm, "  host-carrier-up: %u", vif->host_carrier_up);
380
381           vec_foreach_index (i, vif->vhost_fds)
382             str = format (str, " %d", vif->vhost_fds[i]);
383           vlib_cli_output (vm, "  vhost-fds%v", str);
384           vec_free (str);
385           vec_foreach_index (i, vif->tap_fds)
386             str = format (str, " %d", vif->tap_fds[i]);
387           vlib_cli_output (vm, "  tap-fds%v", str);
388           vec_free (str);
389         }
390       vlib_cli_output (vm, "  gso-enabled %d", vif->gso_enabled);
391       vlib_cli_output (vm, "  csum-enabled %d", vif->csum_offload_enabled);
392       vlib_cli_output (vm, "  packet-coalesce %d", vif->packet_coalesce);
393       vlib_cli_output (vm, "  packet-buffering %d", vif->packet_buffering);
394       if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_PCI))
395         vlib_cli_output (vm, "  Mac Address: %U", format_ethernet_address,
396                          vif->mac_addr);
397       vlib_cli_output (vm, "  Device instance: %u", vif->dev_instance);
398       vlib_cli_output (vm, "  flags 0x%x", vif->flags);
399       flag_entry = (struct feat_struct *) &flags_array;
400       while (flag_entry->str)
401         {
402           if (vif->flags & (1ULL << flag_entry->bit))
403             vlib_cli_output (vm, "    %s (%d)", flag_entry->str,
404                              flag_entry->bit);
405           flag_entry++;
406         }
407       if (type == VIRTIO_IF_TYPE_PCI)
408         {
409           device_status (vm, vif);
410         }
411       vlib_cli_output (vm, "  features 0x%lx", vif->features);
412       feat_entry = (struct feat_struct *) &feat_array;
413       while (feat_entry->str)
414         {
415           if (vif->features & (1ULL << feat_entry->bit))
416             vlib_cli_output (vm, "    %s (%d)", feat_entry->str,
417                              feat_entry->bit);
418           feat_entry++;
419         }
420       vlib_cli_output (vm, "  remote-features 0x%lx", vif->remote_features);
421       feat_entry = (struct feat_struct *) &feat_array;
422       while (feat_entry->str)
423         {
424           if (vif->remote_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, "  Number of RX Virtqueue  %u", vif->num_rxqs);
430       vlib_cli_output (vm, "  Number of TX Virtqueue  %u", vif->num_txqs);
431       if (type == VIRTIO_IF_TYPE_PCI && vif->cxq_vring != NULL &&
432           vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
433         vlib_cli_output (vm, "  Number of CTRL Virtqueue 1");
434       vec_foreach_index (i, vif->rxq_vrings)
435       {
436         vring = vec_elt_at_index (vif->rxq_vrings, i);
437         vlib_cli_output (vm, "  Virtqueue (RX) %d", vring->queue_id);
438         vlib_cli_output (vm,
439                          "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
440                          vring->size, vring->last_used_idx, vring->desc_next,
441                          vring->desc_in_use);
442         if (vif->is_packed)
443           {
444             vlib_cli_output (vm,
445                              "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
446                              vring->driver_event->flags,
447                              vring->driver_event->off_wrap,
448                              vring->device_event->flags,
449                              vring->device_event->off_wrap);
450             vlib_cli_output (vm,
451                              "    avail wrap counter %d, used wrap counter %d",
452                              vring->avail_wrap_counter,
453                              vring->used_wrap_counter);
454           }
455         else
456           vlib_cli_output (vm,
457                            "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
458                            vring->avail->flags, vring->avail->idx,
459                            vring->used->flags, vring->used->idx);
460         if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
461           {
462             vlib_cli_output (vm, "    kickfd %d, callfd %d", vring->kick_fd,
463                              vring->call_fd);
464           }
465         if (show_descr)
466           {
467             vlib_cli_output (vm, "\n  descriptor table:\n");
468             vlib_cli_output (vm,
469                              "   id          addr         len  flags  next/id      user_addr\n");
470             vlib_cli_output (vm,
471                              "  ===== ================== ===== ====== ======= ==================\n");
472             for (j = 0; j < vring->size; j++)
473               {
474                 if (vif->is_packed)
475                   {
476                     vring_packed_desc_t *desc = &vring->packed_desc[j];
477                     vlib_cli_output (vm,
478                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
479                                      j, desc->addr,
480                                      desc->len,
481                                      desc->flags, desc->id, desc->addr);
482                   }
483                 else
484                   {
485                     vring_desc_t *desc = &vring->desc[j];
486                     vlib_cli_output (vm,
487                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
488                                      j, desc->addr,
489                                      desc->len,
490                                      desc->flags, desc->next, desc->addr);
491                   }
492               }
493           }
494       }
495       vec_foreach_index (i, vif->txq_vrings)
496       {
497         vring = vec_elt_at_index (vif->txq_vrings, i);
498         vlib_cli_output (vm, "  Virtqueue (TX) %d", vring->queue_id);
499         vlib_cli_output (vm,
500                          "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
501                          vring->size, vring->last_used_idx, vring->desc_next,
502                          vring->desc_in_use);
503         if (vif->is_packed)
504           {
505             vlib_cli_output (vm,
506                              "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
507                              vring->driver_event->flags,
508                              vring->driver_event->off_wrap,
509                              vring->device_event->flags,
510                              vring->device_event->off_wrap);
511             vlib_cli_output (vm,
512                              "    avail wrap counter %d, used wrap counter %d",
513                              vring->avail_wrap_counter,
514                              vring->used_wrap_counter);
515           }
516         else
517           vlib_cli_output (vm,
518                            "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
519                            vring->avail->flags, vring->avail->idx,
520                            vring->used->flags, vring->used->idx);
521         if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
522           {
523             vlib_cli_output (vm, "    kickfd %d, callfd %d", vring->kick_fd,
524                              vring->call_fd);
525           }
526         if (vring->flow_table)
527           {
528             vlib_cli_output (vm, "    %U", gro_flow_table_format,
529                              vring->flow_table);
530           }
531         if (vif->packet_buffering)
532           {
533             vlib_cli_output (vm, "    %U", virtio_vring_buffering_format,
534                              vring->buffering);
535           }
536         if (show_descr)
537           {
538             vlib_cli_output (vm, "\n  descriptor table:\n");
539             vlib_cli_output (vm,
540                              "   id          addr         len  flags  next/id      user_addr\n");
541             vlib_cli_output (vm,
542                              "  ===== ================== ===== ====== ======== ==================\n");
543             for (j = 0; j < vring->size; j++)
544               {
545                 if (vif->is_packed)
546                   {
547                     vring_packed_desc_t *desc = &vring->packed_desc[j];
548                     vlib_cli_output (vm,
549                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
550                                      j, desc->addr,
551                                      desc->len,
552                                      desc->flags, desc->id, desc->addr);
553                   }
554                 else
555                   {
556                     vring_desc_t *desc = &vring->desc[j];
557                     vlib_cli_output (vm,
558                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
559                                      j, desc->addr,
560                                      desc->len,
561                                      desc->flags, desc->next, desc->addr);
562                   }
563               }
564           }
565       }
566       if (type == VIRTIO_IF_TYPE_PCI && vif->cxq_vring != NULL &&
567           vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
568         {
569           vring = vif->cxq_vring;
570           vlib_cli_output (vm, "  Virtqueue (CTRL) %d", vring->queue_id);
571           vlib_cli_output (vm,
572                            "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
573                            vring->size, vring->last_used_idx,
574                            vring->desc_next, vring->desc_in_use);
575           if (vif->is_packed)
576             {
577               vlib_cli_output (vm,
578                                "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
579                                vring->driver_event->flags,
580                                vring->driver_event->off_wrap,
581                                vring->device_event->flags,
582                                vring->device_event->off_wrap);
583               vlib_cli_output (vm,
584                                "    avail wrap counter %d, used wrap counter %d",
585                                vring->avail_wrap_counter,
586                                vring->used_wrap_counter);
587             }
588           else
589             {
590               vlib_cli_output (vm,
591                                "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
592                                vring->avail->flags, vring->avail->idx,
593                                vring->used->flags, vring->used->idx);
594             }
595           if (show_descr)
596             {
597               vlib_cli_output (vm, "\n  descriptor table:\n");
598               vlib_cli_output (vm,
599                                "   id          addr         len  flags  next/id      user_addr\n");
600               vlib_cli_output (vm,
601                                "  ===== ================== ===== ====== ======== ==================\n");
602               for (j = 0; j < vring->size; j++)
603                 {
604                   if (vif->is_packed)
605                     {
606                       vring_packed_desc_t *desc = &vring->packed_desc[j];
607                       vlib_cli_output (vm,
608                                        "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
609                                        j, desc->addr,
610                                        desc->len,
611                                        desc->flags, desc->id, desc->addr);
612                     }
613                   else
614                     {
615                       vring_desc_t *desc = &vring->desc[j];
616                       vlib_cli_output (vm,
617                                        "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
618                                        j, desc->addr,
619                                        desc->len,
620                                        desc->flags, desc->next, desc->addr);
621                     }
622                 }
623             }
624         }
625     }
626
627 }
628
629 static clib_error_t *
630 virtio_init (vlib_main_t * vm)
631 {
632   virtio_main_t *vim = &virtio_main;
633   clib_error_t *error = 0;
634
635   vim->log_default = vlib_log_register_class ("virtio", 0);
636   vlib_log_debug (vim->log_default, "initialized");
637
638   return error;
639 }
640
641 VLIB_INIT_FUNCTION (virtio_init);
642
643 /*
644  * fd.io coding-style-patch-verification: ON
645  *
646  * Local Variables:
647  * eval: (c-set-style "gnu")
648  * End:
649  */