virtio: Add support for multiqueue
[vpp.git] / src / vnet / devices / virtio / device.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2016 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
22 #include <vlib/vlib.h>
23 #include <vlib/unix/unix.h>
24 #include <vnet/ethernet/ethernet.h>
25 #include <vnet/ip/ip4_packet.h>
26 #include <vnet/ip/ip6_packet.h>
27 #include <vnet/devices/virtio/virtio.h>
28
29 #define foreach_virtio_tx_func_error           \
30 _(NO_FREE_SLOTS, "no free tx slots")           \
31 _(TRUNC_PACKET, "packet > buffer size -- truncated in tx ring") \
32 _(PENDING_MSGS, "pending msgs in tx ring") \
33 _(NO_TX_QUEUES, "no tx queues")
34
35 typedef enum
36 {
37 #define _(f,s) VIRTIO_TX_ERROR_##f,
38   foreach_virtio_tx_func_error
39 #undef _
40     VIRTIO_TX_N_ERROR,
41 } virtio_tx_func_error_t;
42
43 static char *virtio_tx_func_error_strings[] = {
44 #define _(n,s) s,
45   foreach_virtio_tx_func_error
46 #undef _
47 };
48
49 #ifndef CLIB_MARCH_VARIANT
50 u8 *
51 format_virtio_device_name (u8 * s, va_list * args)
52 {
53   u32 dev_instance = va_arg (*args, u32);
54   virtio_main_t *mm = &virtio_main;
55   virtio_if_t *vif = pool_elt_at_index (mm->interfaces, dev_instance);
56
57   if (vif->type == VIRTIO_IF_TYPE_TAP)
58     s = format (s, "tap%u", vif->id);
59   else if (vif->type == VIRTIO_IF_TYPE_PCI)
60     s = format (s, "virtio-%x/%x/%x/%x", vif->pci_addr.domain,
61                 vif->pci_addr.bus, vif->pci_addr.slot,
62                 vif->pci_addr.function);
63   else
64     s = format (s, "virtio-%lu", vif->dev_instance);
65
66   return s;
67 }
68 #endif /* CLIB_MARCH_VARIANT */
69
70 static u8 *
71 format_virtio_device (u8 * s, va_list * args)
72 {
73   u32 dev_instance = va_arg (*args, u32);
74   int verbose = va_arg (*args, int);
75   u32 indent = format_get_indent (s);
76
77   s = format (s, "VIRTIO interface");
78   if (verbose)
79     {
80       s = format (s, "\n%U instance %u", format_white_space, indent + 2,
81                   dev_instance);
82     }
83   return s;
84 }
85
86 static u8 *
87 format_virtio_tx_trace (u8 * s, va_list * args)
88 {
89   s = format (s, "Unimplemented...");
90   return s;
91 }
92
93 #ifndef CLIB_MARCH_VARIANT
94 inline void
95 virtio_free_used_desc (vlib_main_t * vm, virtio_vring_t * vring)
96 {
97   u16 used = vring->desc_in_use;
98   u16 sz = vring->size;
99   u16 mask = sz - 1;
100   u16 last = vring->last_used_idx;
101   u16 n_left = vring->used->idx - last;
102
103   if (n_left == 0)
104     return;
105
106   while (n_left)
107     {
108       struct vring_used_elem *e = &vring->used->ring[last & mask];
109       u16 slot = e->id;
110
111       vlib_buffer_free (vm, &vring->buffers[slot], 1);
112       used--;
113       last++;
114       n_left--;
115     }
116   vring->desc_in_use = used;
117   vring->last_used_idx = last;
118 }
119 #endif /* CLIB_MARCH_VARIANT */
120
121 static_always_inline u16
122 add_buffer_to_slot (vlib_main_t * vm, virtio_if_t * vif,
123                     virtio_vring_t * vring, u32 bi, u16 avail, u16 next,
124                     u16 mask, int do_gso)
125 {
126   u16 n_added = 0;
127   int hdr_sz = vif->virtio_net_hdr_sz;
128   struct vring_desc *d;
129   d = &vring->desc[next];
130   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
131   struct virtio_net_hdr_v1 *hdr = vlib_buffer_get_current (b) - hdr_sz;
132
133   clib_memset (hdr, 0, hdr_sz);
134   if (do_gso && (b->flags & VNET_BUFFER_F_GSO))
135     {
136       if (b->flags & VNET_BUFFER_F_IS_IP4)
137         {
138           hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
139           hdr->gso_size = vnet_buffer2 (b)->gso_size;
140           hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
141           hdr->csum_start = vnet_buffer (b)->l4_hdr_offset;     // 0x22;
142           hdr->csum_offset = 0x10;
143         }
144       else
145         {
146           hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
147           hdr->gso_size = vnet_buffer2 (b)->gso_size;
148           hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
149           hdr->csum_start = vnet_buffer (b)->l4_hdr_offset;     // 0x36;
150           hdr->csum_offset = 0x10;
151         }
152     }
153
154   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
155     {
156       d->addr =
157         ((vif->type == VIRTIO_IF_TYPE_PCI) ? vlib_buffer_get_current_pa (vm,
158                                                                          b) :
159          pointer_to_uword (vlib_buffer_get_current (b))) - hdr_sz;
160       d->len = b->current_length + hdr_sz;
161       d->flags = 0;
162     }
163   else
164     {
165       /*
166        * We are using single vlib_buffer_t for indirect descriptor(s)
167        * chain. Single descriptor is 16 bytes and vlib_buffer_t
168        * has 2048 bytes space. So maximum long chain can have 128
169        * (=2048/16) indirect descriptors.
170        * It can easily support 65535 bytes of Jumbo frames with
171        * each data buffer size of 512 bytes minimum.
172        */
173       vlib_buffer_t *indirect_desc =
174         vlib_get_buffer (vm, vring->indirect_buffers[next]);
175       indirect_desc->current_data = 0;
176
177       struct vring_desc *id =
178         (struct vring_desc *) vlib_buffer_get_current (indirect_desc);
179       u32 count = 1;
180       if (vif->type == VIRTIO_IF_TYPE_PCI)
181         {
182           d->addr = vlib_physmem_get_pa (vm, id);
183           id->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
184
185           /*
186            * If VIRTIO_F_ANY_LAYOUT is not negotiated, then virtio_net_hdr
187            * should be presented in separate descriptor and data will start
188            * from next descriptor.
189            */
190           if (PREDICT_TRUE
191               (vif->features & VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)))
192             id->len = b->current_length + hdr_sz;
193           else
194             {
195               id->len = hdr_sz;
196               id->flags = VRING_DESC_F_NEXT;
197               id->next = count;
198               count++;
199               id++;
200               id->addr = vlib_buffer_get_current_pa (vm, b);
201               id->len = b->current_length;
202             }
203           while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
204             {
205               id->flags = VRING_DESC_F_NEXT;
206               id->next = count;
207               count++;
208               id++;
209               b = vlib_get_buffer (vm, b->next_buffer);
210               id->addr = vlib_buffer_get_current_pa (vm, b);
211               id->len = b->current_length;
212             }
213         }
214       else                      /* VIRTIO_IF_TYPE_TAP */
215         {
216           d->addr = pointer_to_uword (id);
217           /* first buffer in chain */
218           id->addr = pointer_to_uword (vlib_buffer_get_current (b)) - hdr_sz;
219           id->len = b->current_length + hdr_sz;
220
221           while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
222             {
223               id->flags = VRING_DESC_F_NEXT;
224               id->next = count;
225               count++;
226               id++;
227               b = vlib_get_buffer (vm, b->next_buffer);
228               id->addr = pointer_to_uword (vlib_buffer_get_current (b));
229               id->len = b->current_length;
230             }
231         }
232       id->flags = 0;
233       id->next = 0;
234       d->len = count * sizeof (struct vring_desc);
235       d->flags = VRING_DESC_F_INDIRECT;
236     }
237   vring->buffers[next] = bi;
238   vring->avail->ring[avail & mask] = next;
239   n_added++;
240   return n_added;
241 }
242
243 static_always_inline uword
244 virtio_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
245                             vlib_frame_t * frame, virtio_if_t * vif,
246                             int do_gso)
247 {
248   u16 n_left = frame->n_vectors;
249   virtio_vring_t *vring;
250   u16 qid = vm->thread_index % vif->num_txqs;
251   vring = vec_elt_at_index (vif->txq_vrings, qid);
252   u16 used, next, avail;
253   u16 sz = vring->size;
254   u16 mask = sz - 1;
255   u32 *buffers = vlib_frame_vector_args (frame);
256
257   clib_spinlock_lock_if_init (&vring->lockp);
258
259   if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0 &&
260       (vring->last_kick_avail_idx != vring->avail->idx))
261     virtio_kick (vm, vring, vif);
262
263   /* free consumed buffers */
264   virtio_free_used_desc (vm, vring);
265
266   used = vring->desc_in_use;
267   next = vring->desc_next;
268   avail = vring->avail->idx;
269
270   while (n_left && used < sz)
271     {
272       u16 n_added = 0;
273       n_added =
274         add_buffer_to_slot (vm, vif, vring, buffers[0], avail, next, mask,
275                             do_gso);
276       if (!n_added)
277         break;
278       avail += n_added;
279       next = (next + n_added) & mask;
280       used += n_added;
281       buffers++;
282       n_left--;
283     }
284
285   if (n_left != frame->n_vectors)
286     {
287       CLIB_MEMORY_STORE_BARRIER ();
288       vring->avail->idx = avail;
289       vring->desc_next = next;
290       vring->desc_in_use = used;
291       if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0)
292         virtio_kick (vm, vring, vif);
293     }
294
295   if (n_left)
296     {
297       vlib_error_count (vm, node->node_index, VIRTIO_TX_ERROR_NO_FREE_SLOTS,
298                         n_left);
299       vlib_buffer_free (vm, buffers, n_left);
300     }
301
302   clib_spinlock_unlock_if_init (&vring->lockp);
303
304   return frame->n_vectors - n_left;
305 }
306
307 VNET_DEVICE_CLASS_TX_FN (virtio_device_class) (vlib_main_t * vm,
308                                                vlib_node_runtime_t * node,
309                                                vlib_frame_t * frame)
310 {
311   virtio_main_t *nm = &virtio_main;
312   vnet_interface_output_runtime_t *rund = (void *) node->runtime_data;
313   virtio_if_t *vif = pool_elt_at_index (nm->interfaces, rund->dev_instance);
314   vnet_main_t *vnm = vnet_get_main ();
315
316   if (vnm->interface_main.gso_interface_count > 0)
317     return virtio_interface_tx_inline (vm, node, frame, vif, 1 /* do_gso */ );
318   else
319     return virtio_interface_tx_inline (vm, node, frame, vif,
320                                        0 /* no do_gso */ );
321 }
322
323 static void
324 virtio_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
325                                 u32 node_index)
326 {
327   virtio_main_t *apm = &virtio_main;
328   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
329   virtio_if_t *vif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
330
331   /* Shut off redirection */
332   if (node_index == ~0)
333     {
334       vif->per_interface_next_index = node_index;
335       return;
336     }
337
338   vif->per_interface_next_index =
339     vlib_node_add_next (vlib_get_main (), virtio_input_node.index,
340                         node_index);
341 }
342
343 static void
344 virtio_clear_hw_interface_counters (u32 instance)
345 {
346   /* Nothing for now */
347 }
348
349 static clib_error_t *
350 virtio_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid,
351                                  vnet_hw_interface_rx_mode mode)
352 {
353   virtio_main_t *mm = &virtio_main;
354   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
355   virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
356   virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, qid);
357
358   if (vif->type == VIRTIO_IF_TYPE_PCI && !(vif->support_int_mode))
359     {
360       vring->avail->flags |= VIRTIO_RING_FLAG_MASK_INT;
361       return clib_error_return (0, "interrupt mode is not supported");
362     }
363
364   if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
365     vring->avail->flags |= VIRTIO_RING_FLAG_MASK_INT;
366   else
367     vring->avail->flags &= ~VIRTIO_RING_FLAG_MASK_INT;
368
369   return 0;
370 }
371
372 static clib_error_t *
373 virtio_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
374 {
375   virtio_main_t *mm = &virtio_main;
376   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
377   virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
378
379   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
380     vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
381   else
382     vif->flags &= ~VIRTIO_IF_FLAG_ADMIN_UP;
383
384   return 0;
385 }
386
387 static clib_error_t *
388 virtio_subif_add_del_function (vnet_main_t * vnm,
389                                u32 hw_if_index,
390                                struct vnet_sw_interface_t *st, int is_add)
391 {
392   /* Nothing for now */
393   return 0;
394 }
395
396 /* *INDENT-OFF* */
397 VNET_DEVICE_CLASS (virtio_device_class) = {
398   .name = "virtio",
399   .format_device_name = format_virtio_device_name,
400   .format_device = format_virtio_device,
401   .format_tx_trace = format_virtio_tx_trace,
402   .tx_function_n_errors = VIRTIO_TX_N_ERROR,
403   .tx_function_error_strings = virtio_tx_func_error_strings,
404   .rx_redirect_to_node = virtio_set_interface_next_node,
405   .clear_counters = virtio_clear_hw_interface_counters,
406   .admin_up_down_function = virtio_interface_admin_up_down,
407   .subif_add_del_function = virtio_subif_add_del_function,
408   .rx_mode_change_function = virtio_interface_rx_mode_change,
409 };
410 /* *INDENT-ON* */
411
412 /*
413  * fd.io coding-style-patch-verification: ON
414  *
415  * Local Variables:
416  * eval: (c-set-style "gnu")
417  * End:
418  */