4f812b1e7aaadfeac37db1ddcc9b0289aee173ed
[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/pci.h>
34 #include <vnet/interface/rx_queue_funcs.h>
35
36 virtio_main_t virtio_main;
37
38 #define _IOCTL(fd,a,...) \
39   if (ioctl (fd, a, __VA_ARGS__) < 0) \
40     { \
41       err = clib_error_return_unix (0, "ioctl(" #a ")"); \
42       goto error; \
43     }
44
45 static clib_error_t *
46 call_read_ready (clib_file_t * uf)
47 {
48   vnet_main_t *vnm = vnet_get_main ();
49   u64 b;
50
51   CLIB_UNUSED (ssize_t size) = read (uf->file_descriptor, &b, sizeof (b));
52   vnet_hw_if_rx_queue_set_int_pending (vnm, uf->private_data);
53
54   return 0;
55 }
56
57
58 clib_error_t *
59 virtio_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 idx, u16 sz)
60 {
61   virtio_vring_t *vring;
62   int i;
63
64   if (!is_pow2 (sz))
65     return clib_error_return (0, "ring size must be power of 2");
66
67   if (sz > 32768)
68     return clib_error_return (0, "ring size must be 32768 or lower");
69
70   if (sz == 0)
71     sz = 256;
72
73   if (idx % 2)
74     {
75       vlib_thread_main_t *thm = vlib_get_thread_main ();
76       vec_validate_aligned (vif->txq_vrings, TX_QUEUE_ACCESS (idx),
77                             CLIB_CACHE_LINE_BYTES);
78       vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (idx));
79       if (thm->n_vlib_mains > vif->num_txqs)
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 void
224 virtio_vring_set_rx_queues (vlib_main_t *vm, virtio_if_t *vif)
225 {
226   vnet_main_t *vnm = vnet_get_main ();
227   virtio_vring_t *vring;
228   u32 i = 0;
229
230   vnet_hw_if_set_input_node (vnm, vif->hw_if_index, virtio_input_node.index);
231
232   vec_foreach (vring, vif->rxq_vrings)
233     {
234       vring->queue_index = vnet_hw_if_register_rx_queue (
235         vnm, vif->hw_if_index, RX_QUEUE_ACCESS (vring->queue_id),
236         VNET_HW_IF_RXQ_THREAD_ANY);
237       vring->buffer_pool_index = vlib_buffer_pool_get_default_for_numa (
238         vm, vnet_hw_if_get_rx_queue_numa_node (vnm, vring->queue_index));
239       if (vif->type == VIRTIO_IF_TYPE_TAP || vif->type == VIRTIO_IF_TYPE_TUN)
240         {
241
242           clib_file_t f = {
243             .read_function = call_read_ready,
244             .flags = UNIX_FILE_EVENT_EDGE_TRIGGERED,
245             .file_descriptor = vring->call_fd,
246             .private_data = vring->queue_index,
247             .description = format (0, "%U vring %u", format_virtio_device_name,
248                                    vif->dev_instance, vring->queue_id),
249           };
250
251           vring->call_file_index = clib_file_add (&file_main, &f);
252           vnet_hw_if_set_rx_queue_file_index (vnm, vring->queue_index,
253                                               vring->call_file_index);
254         }
255       else if ((vif->type == VIRTIO_IF_TYPE_PCI) && (vif->support_int_mode) &&
256                (vif->msix_enabled == VIRTIO_MSIX_ENABLED))
257         {
258           u32 file_index;
259           file_index =
260             vlib_pci_get_msix_file_index (vm, vif->pci_dev_handle, i + 1);
261           vnet_hw_if_set_rx_queue_file_index (vnm, vring->queue_index,
262                                               file_index);
263           i++;
264         }
265     }
266   vnet_hw_if_update_runtime_data (vnm, vif->hw_if_index);
267 }
268
269 inline void
270 virtio_set_net_hdr_size (virtio_if_t * vif)
271 {
272   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF) ||
273       vif->features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1))
274     vif->virtio_net_hdr_sz = sizeof (virtio_net_hdr_v1_t);
275   else
276     vif->virtio_net_hdr_sz = sizeof (virtio_net_hdr_t);
277 }
278
279 inline void
280 virtio_show (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr, u32 type)
281 {
282   u32 i, j, hw_if_index;
283   virtio_if_t *vif;
284   vnet_main_t *vnm = &vnet_main;
285   virtio_main_t *mm = &virtio_main;
286   virtio_vring_t *vring;
287   struct feat_struct
288   {
289     u8 bit;
290     char *str;
291   };
292   struct feat_struct *feat_entry;
293
294   static struct feat_struct feat_array[] = {
295 #define _(s,b) { .str = #s, .bit = b, },
296     foreach_virtio_net_features
297 #undef _
298     {.str = NULL}
299   };
300
301   struct feat_struct *flag_entry;
302   static struct feat_struct flags_array[] = {
303 #define _(b,e,s) { .bit = b, .str = s, },
304     foreach_virtio_if_flag
305 #undef _
306     {.str = NULL}
307   };
308
309   if (!hw_if_indices)
310     return;
311
312   for (hw_if_index = 0; hw_if_index < vec_len (hw_if_indices); hw_if_index++)
313     {
314       vnet_hw_interface_t *hi =
315         vnet_get_hw_interface (vnm, hw_if_indices[hw_if_index]);
316       vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
317       if (vif->type != type)
318         continue;
319       vlib_cli_output (vm, "Interface: %U (ifindex %d)",
320                        format_vnet_hw_if_index_name, vnm,
321                        hw_if_indices[hw_if_index], vif->hw_if_index);
322       if (type == VIRTIO_IF_TYPE_PCI)
323         {
324           vlib_cli_output (vm, "  PCI Address: %U", format_vlib_pci_addr,
325                            &vif->pci_addr);
326         }
327       if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
328         {
329           u8 *str = 0;
330           if (vif->host_if_name)
331             vlib_cli_output (vm, "  name \"%s\"", vif->host_if_name);
332           if (vif->net_ns)
333             vlib_cli_output (vm, "  host-ns \"%s\"", vif->net_ns);
334           if (vif->host_mtu_size)
335             vlib_cli_output (vm, "  host-mtu-size \"%d\"",
336                              vif->host_mtu_size);
337           if (type == VIRTIO_IF_TYPE_TAP)
338             vlib_cli_output (vm, "  host-mac-addr: %U",
339                              format_ethernet_address, vif->host_mac_addr);
340           vlib_cli_output (vm, "  host-carrier-up: %u", vif->host_carrier_up);
341
342           vec_foreach_index (i, vif->vhost_fds)
343             str = format (str, " %d", vif->vhost_fds[i]);
344           vlib_cli_output (vm, "  vhost-fds%v", str);
345           vec_free (str);
346           vec_foreach_index (i, vif->tap_fds)
347             str = format (str, " %d", vif->tap_fds[i]);
348           vlib_cli_output (vm, "  tap-fds%v", str);
349           vec_free (str);
350         }
351       vlib_cli_output (vm, "  gso-enabled %d", vif->gso_enabled);
352       vlib_cli_output (vm, "  csum-enabled %d", vif->csum_offload_enabled);
353       vlib_cli_output (vm, "  packet-coalesce %d", vif->packet_coalesce);
354       vlib_cli_output (vm, "  packet-buffering %d", vif->packet_buffering);
355       if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_PCI))
356         vlib_cli_output (vm, "  Mac Address: %U", format_ethernet_address,
357                          vif->mac_addr);
358       vlib_cli_output (vm, "  Device instance: %u", vif->dev_instance);
359       vlib_cli_output (vm, "  flags 0x%x", vif->flags);
360       flag_entry = (struct feat_struct *) &flags_array;
361       while (flag_entry->str)
362         {
363           if (vif->flags & (1ULL << flag_entry->bit))
364             vlib_cli_output (vm, "    %s (%d)", flag_entry->str,
365                              flag_entry->bit);
366           flag_entry++;
367         }
368       if (type == VIRTIO_IF_TYPE_PCI)
369         {
370           device_status (vm, vif);
371         }
372       vlib_cli_output (vm, "  features 0x%lx", vif->features);
373       feat_entry = (struct feat_struct *) &feat_array;
374       while (feat_entry->str)
375         {
376           if (vif->features & (1ULL << feat_entry->bit))
377             vlib_cli_output (vm, "    %s (%d)", feat_entry->str,
378                              feat_entry->bit);
379           feat_entry++;
380         }
381       vlib_cli_output (vm, "  remote-features 0x%lx", vif->remote_features);
382       feat_entry = (struct feat_struct *) &feat_array;
383       while (feat_entry->str)
384         {
385           if (vif->remote_features & (1ULL << feat_entry->bit))
386             vlib_cli_output (vm, "    %s (%d)", feat_entry->str,
387                              feat_entry->bit);
388           feat_entry++;
389         }
390       vlib_cli_output (vm, "  Number of RX Virtqueue  %u", vif->num_rxqs);
391       vlib_cli_output (vm, "  Number of TX Virtqueue  %u", vif->num_txqs);
392       if (vif->cxq_vring != NULL
393           && vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
394         vlib_cli_output (vm, "  Number of CTRL Virtqueue 1");
395       vec_foreach_index (i, vif->rxq_vrings)
396       {
397         vring = vec_elt_at_index (vif->rxq_vrings, i);
398         vlib_cli_output (vm, "  Virtqueue (RX) %d", vring->queue_id);
399         vlib_cli_output (vm,
400                          "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
401                          vring->size, vring->last_used_idx, vring->desc_next,
402                          vring->desc_in_use);
403         if (vif->is_packed)
404           {
405             vlib_cli_output (vm,
406                              "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
407                              vring->driver_event->flags,
408                              vring->driver_event->off_wrap,
409                              vring->device_event->flags,
410                              vring->device_event->off_wrap);
411             vlib_cli_output (vm,
412                              "    avail wrap counter %d, used wrap counter %d",
413                              vring->avail_wrap_counter,
414                              vring->used_wrap_counter);
415           }
416         else
417           vlib_cli_output (vm,
418                            "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
419                            vring->avail->flags, vring->avail->idx,
420                            vring->used->flags, vring->used->idx);
421         if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
422           {
423             vlib_cli_output (vm, "    kickfd %d, callfd %d", vring->kick_fd,
424                              vring->call_fd);
425           }
426         if (show_descr)
427           {
428             vlib_cli_output (vm, "\n  descriptor table:\n");
429             vlib_cli_output (vm,
430                              "   id          addr         len  flags  next/id      user_addr\n");
431             vlib_cli_output (vm,
432                              "  ===== ================== ===== ====== ======= ==================\n");
433             for (j = 0; j < vring->size; j++)
434               {
435                 if (vif->is_packed)
436                   {
437                     vring_packed_desc_t *desc = &vring->packed_desc[j];
438                     vlib_cli_output (vm,
439                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
440                                      j, desc->addr,
441                                      desc->len,
442                                      desc->flags, desc->id, desc->addr);
443                   }
444                 else
445                   {
446                     vring_desc_t *desc = &vring->desc[j];
447                     vlib_cli_output (vm,
448                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
449                                      j, desc->addr,
450                                      desc->len,
451                                      desc->flags, desc->next, desc->addr);
452                   }
453               }
454           }
455       }
456       vec_foreach_index (i, vif->txq_vrings)
457       {
458         vring = vec_elt_at_index (vif->txq_vrings, i);
459         vlib_cli_output (vm, "  Virtqueue (TX) %d", vring->queue_id);
460         vlib_cli_output (vm,
461                          "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
462                          vring->size, vring->last_used_idx, vring->desc_next,
463                          vring->desc_in_use);
464         if (vif->is_packed)
465           {
466             vlib_cli_output (vm,
467                              "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
468                              vring->driver_event->flags,
469                              vring->driver_event->off_wrap,
470                              vring->device_event->flags,
471                              vring->device_event->off_wrap);
472             vlib_cli_output (vm,
473                              "    avail wrap counter %d, used wrap counter %d",
474                              vring->avail_wrap_counter,
475                              vring->used_wrap_counter);
476           }
477         else
478           vlib_cli_output (vm,
479                            "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
480                            vring->avail->flags, vring->avail->idx,
481                            vring->used->flags, vring->used->idx);
482         if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
483           {
484             vlib_cli_output (vm, "    kickfd %d, callfd %d", vring->kick_fd,
485                              vring->call_fd);
486           }
487         if (vring->flow_table)
488           {
489             vlib_cli_output (vm, "    %U", gro_flow_table_format,
490                              vring->flow_table);
491           }
492         if (vif->packet_buffering)
493           {
494             vlib_cli_output (vm, "    %U", virtio_vring_buffering_format,
495                              vring->buffering);
496           }
497         if (show_descr)
498           {
499             vlib_cli_output (vm, "\n  descriptor table:\n");
500             vlib_cli_output (vm,
501                              "   id          addr         len  flags  next/id      user_addr\n");
502             vlib_cli_output (vm,
503                              "  ===== ================== ===== ====== ======== ==================\n");
504             for (j = 0; j < vring->size; j++)
505               {
506                 if (vif->is_packed)
507                   {
508                     vring_packed_desc_t *desc = &vring->packed_desc[j];
509                     vlib_cli_output (vm,
510                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
511                                      j, desc->addr,
512                                      desc->len,
513                                      desc->flags, desc->id, desc->addr);
514                   }
515                 else
516                   {
517                     vring_desc_t *desc = &vring->desc[j];
518                     vlib_cli_output (vm,
519                                      "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
520                                      j, desc->addr,
521                                      desc->len,
522                                      desc->flags, desc->next, desc->addr);
523                   }
524               }
525           }
526       }
527       if (vif->cxq_vring != NULL
528           && vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
529         {
530           vring = vif->cxq_vring;
531           vlib_cli_output (vm, "  Virtqueue (CTRL) %d", vring->queue_id);
532           vlib_cli_output (vm,
533                            "    qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
534                            vring->size, vring->last_used_idx,
535                            vring->desc_next, vring->desc_in_use);
536           if (vif->is_packed)
537             {
538               vlib_cli_output (vm,
539                                "    driver_event.flags 0x%x driver_event.off_wrap %d device_event.flags 0x%x device_event.off_wrap %d",
540                                vring->driver_event->flags,
541                                vring->driver_event->off_wrap,
542                                vring->device_event->flags,
543                                vring->device_event->off_wrap);
544               vlib_cli_output (vm,
545                                "    avail wrap counter %d, used wrap counter %d",
546                                vring->avail_wrap_counter,
547                                vring->used_wrap_counter);
548             }
549           else
550             {
551               vlib_cli_output (vm,
552                                "    avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
553                                vring->avail->flags, vring->avail->idx,
554                                vring->used->flags, vring->used->idx);
555             }
556           if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_TUN))
557             {
558               vlib_cli_output (vm, "    kickfd %d, callfd %d", vring->kick_fd,
559                                vring->call_fd);
560             }
561           if (show_descr)
562             {
563               vlib_cli_output (vm, "\n  descriptor table:\n");
564               vlib_cli_output (vm,
565                                "   id          addr         len  flags  next/id      user_addr\n");
566               vlib_cli_output (vm,
567                                "  ===== ================== ===== ====== ======== ==================\n");
568               for (j = 0; j < vring->size; j++)
569                 {
570                   if (vif->is_packed)
571                     {
572                       vring_packed_desc_t *desc = &vring->packed_desc[j];
573                       vlib_cli_output (vm,
574                                        "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
575                                        j, desc->addr,
576                                        desc->len,
577                                        desc->flags, desc->id, desc->addr);
578                     }
579                   else
580                     {
581                       vring_desc_t *desc = &vring->desc[j];
582                       vlib_cli_output (vm,
583                                        "  %-5d 0x%016lx %-5d 0x%04x %-8d 0x%016lx\n",
584                                        j, desc->addr,
585                                        desc->len,
586                                        desc->flags, desc->next, desc->addr);
587                     }
588                 }
589             }
590         }
591
592     }
593
594 }
595
596 static clib_error_t *
597 virtio_init (vlib_main_t * vm)
598 {
599   virtio_main_t *vim = &virtio_main;
600   clib_error_t *error = 0;
601
602   vim->log_default = vlib_log_register_class ("virtio", 0);
603   vlib_log_debug (vim->log_default, "initialized");
604
605   return error;
606 }
607
608 VLIB_INIT_FUNCTION (virtio_init);
609
610 /*
611  * fd.io coding-style-patch-verification: ON
612  *
613  * Local Variables:
614  * eval: (c-set-style "gnu")
615  * End:
616  */