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