vlib: add format_vnet_buffer_no_chain
[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/vnet.h>
25 #include <vnet/ethernet/ethernet.h>
26 #include <vnet/gso/gro_func.h>
27 #include <vnet/gso/hdr_offset_parser.h>
28 #include <vnet/ip/ip4_packet.h>
29 #include <vnet/ip/ip6_packet.h>
30 #include <vnet/tcp/tcp_packet.h>
31 #include <vnet/udp/udp_packet.h>
32 #include <vnet/devices/virtio/virtio.h>
33
34 #define VIRTIO_TX_MAX_CHAIN_LEN 127
35
36 #define foreach_virtio_tx_func_error           \
37 _(NO_FREE_SLOTS, "no free tx slots")           \
38 _(TRUNC_PACKET, "packet > buffer size -- truncated in tx ring") \
39 _(PENDING_MSGS, "pending msgs in tx ring") \
40 _(INDIRECT_DESC_ALLOC_FAILED, "indirect descriptor allocation failed - packet drop") \
41 _(OUT_OF_ORDER, "out-of-order buffers in used ring") \
42 _(GSO_PACKET_DROP, "gso disabled on itf  -- gso packet drop") \
43 _(CSUM_OFFLOAD_PACKET_DROP, "checksum offload disabled on itf -- csum offload packet drop")
44
45 typedef enum
46 {
47 #define _(f,s) VIRTIO_TX_ERROR_##f,
48   foreach_virtio_tx_func_error
49 #undef _
50     VIRTIO_TX_N_ERROR,
51 } virtio_tx_func_error_t;
52
53 static char *virtio_tx_func_error_strings[] = {
54 #define _(n,s) s,
55   foreach_virtio_tx_func_error
56 #undef _
57 };
58
59 static u8 *
60 format_virtio_device (u8 * s, va_list * args)
61 {
62   u32 dev_instance = va_arg (*args, u32);
63   int verbose = va_arg (*args, int);
64   u32 indent = format_get_indent (s);
65
66   s = format (s, "VIRTIO interface");
67   if (verbose)
68     {
69       s = format (s, "\n%U instance %u", format_white_space, indent + 2,
70                   dev_instance);
71     }
72   return s;
73 }
74
75 typedef struct
76 {
77   u32 buffer_index;
78   u32 sw_if_index;
79   generic_header_offset_t gho;
80   vlib_buffer_t buffer;
81 } virtio_tx_trace_t;
82
83 static u8 *
84 format_virtio_tx_trace (u8 * s, va_list * va)
85 {
86   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
87   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
88   virtio_tx_trace_t *t = va_arg (*va, virtio_tx_trace_t *);
89   u32 indent = format_get_indent (s);
90
91   s = format (s, "%Ubuffer 0x%x: %U\n", format_white_space, indent,
92               t->buffer_index, format_vnet_buffer_no_chain, &t->buffer);
93   s =
94     format (s, "%U%U\n", format_white_space, indent,
95             format_generic_header_offset, &t->gho);
96   s =
97     format (s, "%U%U", format_white_space, indent,
98             format_ethernet_header_with_length, t->buffer.pre_data,
99             sizeof (t->buffer.pre_data));
100   return s;
101 }
102
103 static void
104 virtio_tx_trace (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b0,
105                  u32 bi, int is_tun)
106 {
107   virtio_tx_trace_t *t;
108   t = vlib_add_trace (vm, node, b0, sizeof (t[0]));
109   t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
110   t->buffer_index = bi;
111   if (is_tun)
112     {
113       int is_ip4 = 0, is_ip6 = 0;
114
115       switch (((u8 *) vlib_buffer_get_current (b0))[0] & 0xf0)
116         {
117         case 0x40:
118           is_ip4 = 1;
119           break;
120         case 0x60:
121           is_ip6 = 1;
122           break;
123         default:
124           break;
125         }
126       vnet_generic_header_offset_parser (b0, &t->gho, 0, is_ip4, is_ip6);
127     }
128   else
129     vnet_generic_header_offset_parser (b0, &t->gho, 1,
130                                        b0->flags &
131                                        VNET_BUFFER_F_IS_IP4,
132                                        b0->flags & VNET_BUFFER_F_IS_IP6);
133
134   clib_memcpy_fast (&t->buffer, b0, sizeof (*b0) - sizeof (b0->pre_data));
135   clib_memcpy_fast (t->buffer.pre_data, vlib_buffer_get_current (b0),
136                     sizeof (t->buffer.pre_data));
137 }
138
139 static void
140 virtio_interface_drop_inline (vlib_main_t *vm, virtio_if_t *vif,
141                               uword node_index, u32 *buffers, u16 n,
142                               virtio_tx_func_error_t error)
143 {
144   vlib_error_count (vm, node_index, error, n);
145   vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
146                                    VNET_INTERFACE_COUNTER_DROP,
147                                  vm->thread_index, vif->sw_if_index, n);
148   vlib_buffer_free (vm, buffers, n);
149 }
150
151 static void
152 virtio_memset_ring_u32 (u32 *ring, u32 start, u32 ring_size, u32 n_buffers)
153 {
154   ASSERT (n_buffers <= ring_size);
155
156   if (PREDICT_TRUE (start + n_buffers <= ring_size))
157     {
158       clib_memset_u32 (ring + start, ~0, n_buffers);
159     }
160   else
161     {
162       clib_memset_u32 (ring + start, ~0, ring_size - start);
163       clib_memset_u32 (ring, ~0, n_buffers - (ring_size - start));
164     }
165 }
166
167 static void
168 virtio_free_used_device_desc_split (vlib_main_t *vm, virtio_vring_t *vring,
169                                     uword node_index)
170 {
171   u16 used = vring->desc_in_use;
172   u16 sz = vring->size;
173   u16 mask = sz - 1;
174   u16 last = vring->last_used_idx;
175   u16 n_left = vring->used->idx - last;
176   u16 out_of_order_count = 0;
177
178   if (n_left == 0)
179     return;
180
181   while (n_left)
182     {
183       vring_used_elem_t *e = &vring->used->ring[last & mask];
184       u16 slot, n_buffers;
185       slot = n_buffers = e->id;
186
187       while (e->id == (n_buffers & mask))
188         {
189           n_left--;
190           last++;
191           n_buffers++;
192           vring_desc_t *d = &vring->desc[e->id];
193           u16 next;
194           while (d->flags & VRING_DESC_F_NEXT)
195             {
196               n_buffers++;
197               next = d->next;
198               d = &vring->desc[next];
199             }
200           if (n_left == 0)
201             break;
202           e = &vring->used->ring[last & mask];
203         }
204       vlib_buffer_free_from_ring (vm, vring->buffers, slot,
205                                   sz, (n_buffers - slot));
206       virtio_memset_ring_u32 (vring->buffers, slot, sz, (n_buffers - slot));
207       used -= (n_buffers - slot);
208
209       if (n_left > 0)
210         {
211           vlib_buffer_free (vm, &vring->buffers[e->id], 1);
212           vring->buffers[e->id] = ~0;
213           used--;
214           last++;
215           n_left--;
216           out_of_order_count++;
217           vring->flags |= VRING_TX_OUT_OF_ORDER;
218         }
219     }
220
221   /*
222    * Some vhost-backends give buffers back in out-of-order fashion in used ring.
223    * It impacts the overall virtio-performance.
224    */
225   if (out_of_order_count)
226     vlib_error_count (vm, node_index, VIRTIO_TX_ERROR_OUT_OF_ORDER,
227                       out_of_order_count);
228
229   vring->desc_in_use = used;
230   vring->last_used_idx = last;
231 }
232
233 static void
234 virtio_free_used_device_desc_packed (vlib_main_t *vm, virtio_vring_t *vring,
235                                      uword node_index)
236 {
237   vring_packed_desc_t *d;
238   u16 sz = vring->size;
239   u16 last = vring->last_used_idx;
240   u16 n_buffers = 0, start;
241   u16 flags;
242
243   if (vring->desc_in_use == 0)
244     return;
245
246   d = &vring->packed_desc[last];
247   flags = d->flags;
248   start = d->id;
249
250   while ((flags & VRING_DESC_F_AVAIL) == (vring->used_wrap_counter << 7) &&
251          (flags & VRING_DESC_F_USED) == (vring->used_wrap_counter << 15))
252     {
253       last++;
254       n_buffers++;
255
256       if (last >= sz)
257         {
258           last = 0;
259           vring->used_wrap_counter ^= 1;
260         }
261       d = &vring->packed_desc[last];
262       flags = d->flags;
263     }
264
265   if (n_buffers)
266     {
267       vlib_buffer_free_from_ring (vm, vring->buffers, start, sz, n_buffers);
268       virtio_memset_ring_u32 (vring->buffers, start, sz, n_buffers);
269       vring->desc_in_use -= n_buffers;
270       vring->last_used_idx = last;
271     }
272 }
273
274 static void
275 virtio_free_used_device_desc (vlib_main_t *vm, virtio_vring_t *vring,
276                               uword node_index, int packed)
277 {
278   if (packed)
279     virtio_free_used_device_desc_packed (vm, vring, node_index);
280   else
281     virtio_free_used_device_desc_split (vm, vring, node_index);
282
283 }
284
285 static void
286 set_checksum_offsets (vlib_buffer_t *b, virtio_net_hdr_v1_t *hdr,
287                       const int is_l2)
288 {
289   vnet_buffer_oflags_t oflags = vnet_buffer (b)->oflags;
290
291   if (b->flags & VNET_BUFFER_F_IS_IP4)
292     {
293       ip4_header_t *ip4;
294       generic_header_offset_t gho = { 0 };
295       vnet_generic_header_offset_parser (b, &gho, is_l2, 1 /* ip4 */ ,
296                                          0 /* ip6 */ );
297       hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
298       hdr->csum_start = gho.l4_hdr_offset;      // 0x22;
299       if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
300         {
301           hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
302         }
303       else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
304         {
305           hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
306         }
307
308       /*
309        * virtio devices do not support IP4 checksum offload. So driver takes care
310        * of it while doing tx.
311        */
312       ip4 =
313         (ip4_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
314       if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
315         ip4->checksum = ip4_header_checksum (ip4);
316     }
317   else if (b->flags & VNET_BUFFER_F_IS_IP6)
318     {
319       generic_header_offset_t gho = { 0 };
320       vnet_generic_header_offset_parser (b, &gho, is_l2, 0 /* ip4 */ ,
321                                          1 /* ip6 */ );
322       hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
323       hdr->csum_start = gho.l4_hdr_offset;      // 0x36;
324       if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
325         {
326           hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
327         }
328       else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
329         {
330           hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
331         }
332     }
333 }
334
335 static void
336 set_gso_offsets (vlib_buffer_t *b, virtio_net_hdr_v1_t *hdr, const int is_l2)
337 {
338   vnet_buffer_oflags_t oflags = vnet_buffer (b)->oflags;
339
340   if (b->flags & VNET_BUFFER_F_IS_IP4)
341     {
342       ip4_header_t *ip4;
343       generic_header_offset_t gho = { 0 };
344       vnet_generic_header_offset_parser (b, &gho, is_l2, 1 /* ip4 */ ,
345                                          0 /* ip6 */ );
346       hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
347       hdr->gso_size = vnet_buffer2 (b)->gso_size;
348       hdr->hdr_len = gho.hdr_sz;
349       hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
350       hdr->csum_start = gho.l4_hdr_offset;      // 0x22;
351       hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
352       ip4 =
353         (ip4_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
354       /*
355        * virtio devices do not support IP4 checksum offload. So driver takes care
356        * of it while doing tx.
357        */
358       if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
359         ip4->checksum = ip4_header_checksum (ip4);
360     }
361   else if (b->flags & VNET_BUFFER_F_IS_IP6)
362     {
363       generic_header_offset_t gho = { 0 };
364       vnet_generic_header_offset_parser (b, &gho, is_l2, 0 /* ip4 */ ,
365                                          1 /* ip6 */ );
366       hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
367       hdr->gso_size = vnet_buffer2 (b)->gso_size;
368       hdr->hdr_len = gho.hdr_sz;
369       hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
370       hdr->csum_start = gho.l4_hdr_offset;      // 0x36;
371       hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
372     }
373 }
374
375 static u16
376 add_buffer_to_slot (vlib_main_t *vm, vlib_node_runtime_t *node,
377                     virtio_if_t *vif, virtio_vring_t *vring, u32 bi,
378                     u16 free_desc_count, u16 avail, u16 next, u16 mask,
379                     int hdr_sz, int do_gso, int csum_offload, int is_pci,
380                     int is_tun, int is_indirect, int is_any_layout)
381 {
382   u16 n_added = 0;
383   vring_desc_t *d;
384   int is_l2 = !is_tun;
385   d = &vring->desc[next];
386   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
387   virtio_net_hdr_v1_t *hdr = vlib_buffer_get_current (b) - hdr_sz;
388   u32 drop_inline = ~0;
389
390   clib_memset_u8 (hdr, 0, hdr_sz);
391
392   if (b->flags & VNET_BUFFER_F_GSO)
393     {
394       if (do_gso)
395         set_gso_offsets (b, hdr, is_l2);
396       else
397         {
398           drop_inline = VIRTIO_TX_ERROR_GSO_PACKET_DROP;
399           goto done;
400         }
401     }
402   else if (b->flags & VNET_BUFFER_F_OFFLOAD)
403     {
404       if (csum_offload)
405         set_checksum_offsets (b, hdr, is_l2);
406       else
407         {
408           drop_inline = VIRTIO_TX_ERROR_CSUM_OFFLOAD_PACKET_DROP;
409           goto done;
410         }
411     }
412
413   if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
414     {
415       virtio_tx_trace (vm, node, b, bi, is_tun);
416     }
417
418   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
419     {
420       d->addr = ((is_pci) ? vlib_buffer_get_current_pa (vm, b) :
421                  pointer_to_uword (vlib_buffer_get_current (b))) - hdr_sz;
422       d->len = b->current_length + hdr_sz;
423       d->flags = 0;
424     }
425   else if (is_indirect)
426     {
427       /*
428        * We are using single vlib_buffer_t for indirect descriptor(s)
429        * chain. Single descriptor is 16 bytes and vlib_buffer_t
430        * has 2048 bytes space. So maximum long chain can have 128
431        * (=2048/16) indirect descriptors.
432        * It can easily support 65535 bytes of Jumbo frames with
433        * each data buffer size of 512 bytes minimum.
434        */
435       u32 indirect_buffer = 0;
436       if (PREDICT_FALSE (vlib_buffer_alloc (vm, &indirect_buffer, 1) == 0))
437         {
438           drop_inline = VIRTIO_TX_ERROR_INDIRECT_DESC_ALLOC_FAILED;
439           goto done;
440         }
441
442       vlib_buffer_t *indirect_desc = vlib_get_buffer (vm, indirect_buffer);
443       indirect_desc->current_data = 0;
444       indirect_desc->flags |= VLIB_BUFFER_NEXT_PRESENT;
445       indirect_desc->next_buffer = bi;
446       bi = indirect_buffer;
447
448       vring_desc_t *id =
449         (vring_desc_t *) vlib_buffer_get_current (indirect_desc);
450       u32 count = 1;
451       if (is_pci)
452         {
453           d->addr = vlib_physmem_get_pa (vm, id);
454           id->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
455
456           /*
457            * If VIRTIO_F_ANY_LAYOUT is not negotiated, then virtio_net_hdr
458            * should be presented in separate descriptor and data will start
459            * from next descriptor.
460            */
461           if (is_any_layout)
462             id->len = b->current_length + hdr_sz;
463           else
464             {
465               id->len = hdr_sz;
466               id->flags = VRING_DESC_F_NEXT;
467               id->next = count;
468               count++;
469               id++;
470               id->addr = vlib_buffer_get_current_pa (vm, b);
471               id->len = b->current_length;
472             }
473           while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
474             {
475               id->flags = VRING_DESC_F_NEXT;
476               id->next = count;
477               count++;
478               id++;
479               b = vlib_get_buffer (vm, b->next_buffer);
480               id->addr = vlib_buffer_get_current_pa (vm, b);
481               id->len = b->current_length;
482               if (PREDICT_FALSE (count == VIRTIO_TX_MAX_CHAIN_LEN))
483                 {
484                   if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
485                     vlib_error_count (vm, node->node_index,
486                                       VIRTIO_TX_ERROR_TRUNC_PACKET, 1);
487                   break;
488                 }
489             }
490         }
491       else                      /* VIRTIO_IF_TYPE_[TAP | TUN] */
492         {
493           d->addr = pointer_to_uword (id);
494           /* first buffer in chain */
495           id->addr = pointer_to_uword (vlib_buffer_get_current (b)) - hdr_sz;
496           id->len = b->current_length + hdr_sz;
497
498           while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
499             {
500               id->flags = VRING_DESC_F_NEXT;
501               id->next = count;
502               count++;
503               id++;
504               b = vlib_get_buffer (vm, b->next_buffer);
505               id->addr = pointer_to_uword (vlib_buffer_get_current (b));
506               id->len = b->current_length;
507               if (PREDICT_FALSE (count == VIRTIO_TX_MAX_CHAIN_LEN))
508                 {
509                   if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
510                     vlib_error_count (vm, node->node_index,
511                                       VIRTIO_TX_ERROR_TRUNC_PACKET, 1);
512                   break;
513                 }
514             }
515         }
516       id->flags = 0;
517       id->next = 0;
518       d->len = count * sizeof (vring_desc_t);
519       d->flags = VRING_DESC_F_INDIRECT;
520     }
521   else if (is_pci)
522     {
523       u16 count = next;
524       vlib_buffer_t *b_temp = b;
525       u16 n_buffers_in_chain = 1;
526
527       /*
528        * Check the length of the chain for the required number of
529        * descriptors. Return from here, retry to get more descriptors,
530        * if chain length is greater than available descriptors.
531        */
532       while (b_temp->flags & VLIB_BUFFER_NEXT_PRESENT)
533         {
534           n_buffers_in_chain++;
535           b_temp = vlib_get_buffer (vm, b_temp->next_buffer);
536         }
537
538       if (n_buffers_in_chain > free_desc_count)
539         return n_buffers_in_chain;
540
541       d->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
542       d->len = b->current_length + hdr_sz;
543
544       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
545         {
546           d->flags = VRING_DESC_F_NEXT;
547           vring->buffers[count] = bi;
548           b->flags &=
549             ~(VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID);
550           bi = b->next_buffer;
551           b->next_buffer = 0;
552           n_added++;
553           count = (count + 1) & mask;
554           d->next = count;
555           d = &vring->desc[count];
556           b = vlib_get_buffer (vm, bi);
557           d->addr = vlib_buffer_get_current_pa (vm, b);
558           d->len = b->current_length;
559         }
560       d->flags = 0;
561       vring->buffers[count] = bi;
562       vring->avail->ring[avail & mask] = next;
563       n_added++;
564       return n_added;
565     }
566   else
567     {
568       ASSERT (0);
569     }
570   vring->buffers[next] = bi;
571   vring->avail->ring[avail & mask] = next;
572   n_added++;
573
574 done:
575   if (drop_inline != ~0)
576     virtio_interface_drop_inline (vm, vif, node->node_index, &bi, 1,
577                                   drop_inline);
578
579   return n_added;
580 }
581
582 static u16
583 add_buffer_to_slot_packed (vlib_main_t *vm, vlib_node_runtime_t *node,
584                            virtio_if_t *vif, virtio_vring_t *vring, u32 bi,
585                            u16 next, int hdr_sz, int do_gso, int csum_offload,
586                            int is_pci, int is_tun, int is_indirect,
587                            int is_any_layout)
588 {
589   u16 n_added = 0, flags = 0;
590   int is_l2 = !is_tun;
591   vring_packed_desc_t *d = &vring->packed_desc[next];
592   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
593   virtio_net_hdr_v1_t *hdr = vlib_buffer_get_current (b) - hdr_sz;
594   u32 drop_inline = ~0;
595
596   clib_memset (hdr, 0, hdr_sz);
597
598   if (b->flags & VNET_BUFFER_F_GSO)
599     {
600       if (do_gso)
601         set_gso_offsets (b, hdr, is_l2);
602       else
603         {
604           drop_inline = VIRTIO_TX_ERROR_GSO_PACKET_DROP;
605           goto done;
606         }
607     }
608   else if (b->flags & VNET_BUFFER_F_OFFLOAD)
609     {
610       if (csum_offload)
611         set_checksum_offsets (b, hdr, is_l2);
612       else
613         {
614           drop_inline = VIRTIO_TX_ERROR_CSUM_OFFLOAD_PACKET_DROP;
615           goto done;
616         }
617     }
618   if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
619     {
620       virtio_tx_trace (vm, node, b, bi, is_tun);
621     }
622
623   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
624     {
625       d->addr =
626         ((is_pci) ? vlib_buffer_get_current_pa (vm,
627                                                 b) :
628          pointer_to_uword (vlib_buffer_get_current (b))) - hdr_sz;
629       d->len = b->current_length + hdr_sz;
630     }
631   else if (is_indirect)
632     {
633       /*
634        * We are using single vlib_buffer_t for indirect descriptor(s)
635        * chain. Single descriptor is 16 bytes and vlib_buffer_t
636        * has 2048 bytes space. So maximum long chain can have 128
637        * (=2048/16) indirect descriptors.
638        * It can easily support 65535 bytes of Jumbo frames with
639        * each data buffer size of 512 bytes minimum.
640        */
641       u32 indirect_buffer = 0;
642       if (PREDICT_FALSE (vlib_buffer_alloc (vm, &indirect_buffer, 1) == 0))
643         {
644           drop_inline = VIRTIO_TX_ERROR_INDIRECT_DESC_ALLOC_FAILED;
645           goto done;
646         }
647
648       vlib_buffer_t *indirect_desc = vlib_get_buffer (vm, indirect_buffer);
649       indirect_desc->current_data = 0;
650       indirect_desc->flags |= VLIB_BUFFER_NEXT_PRESENT;
651       indirect_desc->next_buffer = bi;
652       bi = indirect_buffer;
653
654       vring_packed_desc_t *id =
655         (vring_packed_desc_t *) vlib_buffer_get_current (indirect_desc);
656       u32 count = 1;
657       if (is_pci)
658         {
659           d->addr = vlib_physmem_get_pa (vm, id);
660           id->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
661
662           /*
663            * If VIRTIO_F_ANY_LAYOUT is not negotiated, then virtio_net_hdr
664            * should be presented in separate descriptor and data will start
665            * from next descriptor.
666            */
667           if (is_any_layout)
668             id->len = b->current_length + hdr_sz;
669           else
670             {
671               id->len = hdr_sz;
672               id->flags = 0;
673               id->id = 0;
674               count++;
675               id++;
676               id->addr = vlib_buffer_get_current_pa (vm, b);
677               id->len = b->current_length;
678             }
679           while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
680             {
681               id->flags = 0;
682               id->id = 0;
683               count++;
684               id++;
685               b = vlib_get_buffer (vm, b->next_buffer);
686               id->addr = vlib_buffer_get_current_pa (vm, b);
687               id->len = b->current_length;
688               if (PREDICT_FALSE (count == VIRTIO_TX_MAX_CHAIN_LEN))
689                 {
690                   if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
691                     vlib_error_count (vm, node->node_index,
692                                       VIRTIO_TX_ERROR_TRUNC_PACKET, 1);
693                   break;
694                 }
695             }
696         }
697       id->flags = 0;
698       id->id = 0;
699       d->len = count * sizeof (vring_packed_desc_t);
700       flags = VRING_DESC_F_INDIRECT;
701     }
702   else
703     {
704       ASSERT (0);
705     }
706   if (vring->avail_wrap_counter)
707     {
708       flags |= VRING_DESC_F_AVAIL;
709       flags &= ~VRING_DESC_F_USED;
710     }
711   else
712     {
713       flags &= ~VRING_DESC_F_AVAIL;
714       flags |= VRING_DESC_F_USED;
715     }
716
717   d->id = next;
718   d->flags = flags;
719   vring->buffers[next] = bi;
720   n_added++;
721
722 done:
723   if (drop_inline != ~0)
724     virtio_interface_drop_inline (vm, vif, node->node_index, &bi, 1,
725                                   drop_inline);
726
727   return n_added;
728 }
729
730 static uword
731 virtio_interface_tx_packed_gso_inline (vlib_main_t *vm,
732                                        vlib_node_runtime_t *node,
733                                        virtio_if_t *vif, virtio_if_type_t type,
734                                        virtio_vring_t *vring, u32 *buffers,
735                                        u16 n_left, const int do_gso,
736                                        const int csum_offload)
737 {
738   int is_pci = (type == VIRTIO_IF_TYPE_PCI);
739   int is_tun = (type == VIRTIO_IF_TYPE_TUN);
740   int is_indirect =
741     ((vif->features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) != 0);
742   int is_any_layout =
743     ((vif->features & VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)) != 0);
744   const int hdr_sz = vif->virtio_net_hdr_sz;
745   u16 sz = vring->size;
746   u16 used, next, n_buffers = 0, n_buffers_left = 0;
747   u16 n_vectors = n_left;
748
749
750   used = vring->desc_in_use;
751   next = vring->desc_next;
752
753   if (vif->packet_buffering)
754     {
755       n_buffers = n_buffers_left = virtio_vring_n_buffers (vring->buffering);
756
757       while (n_buffers_left && used < sz)
758         {
759           u16 n_added = 0;
760
761           u32 bi = virtio_vring_buffering_read_from_front (vring->buffering);
762           if (bi == ~0)
763             break;
764           n_added = add_buffer_to_slot_packed (
765             vm, node, vif, vring, bi, next, hdr_sz, do_gso, csum_offload,
766             is_pci, is_tun, is_indirect, is_any_layout);
767           n_buffers_left--;
768           if (PREDICT_FALSE (n_added == 0))
769             continue;
770
771           used++;
772           next++;
773           if (next >= sz)
774             {
775               next = 0;
776               vring->avail_wrap_counter ^= 1;
777             }
778         }
779     }
780
781   while (n_left && used < sz)
782     {
783       u16 n_added = 0;
784
785       n_added = add_buffer_to_slot_packed (
786         vm, node, vif, vring, buffers[0], next, hdr_sz, do_gso, csum_offload,
787         is_pci, is_tun, is_indirect, is_any_layout);
788       buffers++;
789       n_left--;
790       if (PREDICT_FALSE (n_added == 0))
791         continue;
792
793       used++;
794       next++;
795       if (next >= sz)
796         {
797           next = 0;
798           vring->avail_wrap_counter ^= 1;
799         }
800     }
801
802   if (n_left != n_vectors || n_buffers != n_buffers_left)
803     {
804       CLIB_MEMORY_STORE_BARRIER ();
805       vring->desc_next = next;
806       vring->desc_in_use = used;
807       CLIB_MEMORY_BARRIER ();
808       if (vring->device_event->flags != VRING_EVENT_F_DISABLE)
809         virtio_kick (vm, vring, vif);
810     }
811
812   return n_left;
813 }
814
815 static void
816 virtio_find_free_desc (virtio_vring_t *vring, u16 size, u16 mask, u16 req,
817                        u16 next, u32 *first_free_desc_index,
818                        u16 *free_desc_count)
819 {
820   u16 start = 0;
821   /* next is used as hint: from where to start looking */
822   for (u16 i = 0; i < size; i++, next++)
823     {
824       if (vring->buffers[next & mask] == ~0)
825         {
826           if (*first_free_desc_index == ~0)
827             {
828               *first_free_desc_index = (next & mask);
829               start = i;
830               (*free_desc_count)++;
831               req--;
832               if (req == 0)
833                 break;
834             }
835           else
836             {
837               if (start + *free_desc_count == i)
838                 {
839                   (*free_desc_count)++;
840                   req--;
841                   if (req == 0)
842                     break;
843                 }
844               else
845                 break;
846             }
847         }
848     }
849 }
850
851 static u16
852 virtio_interface_tx_split_gso_inline (vlib_main_t *vm,
853                                       vlib_node_runtime_t *node,
854                                       virtio_if_t *vif, virtio_if_type_t type,
855                                       virtio_vring_t *vring, u32 *buffers,
856                                       u16 n_left, int do_gso, int csum_offload)
857 {
858   u16 used, next, avail, n_buffers = 0, n_buffers_left = 0;
859   int is_pci = (type == VIRTIO_IF_TYPE_PCI);
860   int is_tun = (type == VIRTIO_IF_TYPE_TUN);
861   int is_indirect =
862     ((vif->features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) != 0);
863   int is_any_layout =
864     ((vif->features & VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)) != 0);
865   u16 sz = vring->size;
866   int hdr_sz = vif->virtio_net_hdr_sz;
867   u16 mask = sz - 1;
868   u16 n_vectors = n_left;
869
870   used = vring->desc_in_use;
871   next = vring->desc_next;
872   avail = vring->avail->idx;
873
874   u16 free_desc_count = 0;
875
876   if (PREDICT_FALSE (vring->flags & VRING_TX_OUT_OF_ORDER))
877     {
878       u32 first_free_desc_index = ~0;
879
880       virtio_find_free_desc (vring, sz, mask, n_left, next,
881                              &first_free_desc_index, &free_desc_count);
882
883       if (free_desc_count)
884         next = first_free_desc_index;
885     }
886   else
887     free_desc_count = sz - used;
888
889   if (vif->packet_buffering)
890     {
891       n_buffers = n_buffers_left = virtio_vring_n_buffers (vring->buffering);
892
893       while (n_buffers_left && free_desc_count)
894         {
895           u16 n_added = 0;
896
897           u32 bi = virtio_vring_buffering_read_from_front (vring->buffering);
898           if (bi == ~0)
899             break;
900
901           n_added = add_buffer_to_slot (vm, node, vif, vring, bi,
902                                         free_desc_count, avail, next, mask,
903                                         hdr_sz, do_gso, csum_offload, is_pci,
904                                         is_tun, is_indirect, is_any_layout);
905           if (PREDICT_FALSE (n_added == 0))
906             {
907               n_buffers_left--;
908               continue;
909             }
910           else if (PREDICT_FALSE (n_added > free_desc_count))
911             break;
912
913           avail++;
914           next = (next + n_added) & mask;
915           used += n_added;
916           n_buffers_left--;
917           free_desc_count -= n_added;
918         }
919     }
920
921   while (n_left && free_desc_count)
922     {
923       u16 n_added = 0;
924
925       n_added =
926         add_buffer_to_slot (vm, node, vif, vring, buffers[0], free_desc_count,
927                             avail, next, mask, hdr_sz, do_gso, csum_offload,
928                             is_pci, is_tun, is_indirect, is_any_layout);
929
930       if (PREDICT_FALSE (n_added == 0))
931         {
932           buffers++;
933           n_left--;
934           continue;
935         }
936       else if (PREDICT_FALSE (n_added > free_desc_count))
937         break;
938
939       avail++;
940       next = (next + n_added) & mask;
941       used += n_added;
942       buffers++;
943       n_left--;
944       free_desc_count -= n_added;
945     }
946
947   if (n_left != n_vectors || n_buffers != n_buffers_left)
948     {
949       clib_atomic_store_seq_cst (&vring->avail->idx, avail);
950       vring->desc_next = next;
951       vring->desc_in_use = used;
952       if ((clib_atomic_load_seq_cst (&vring->used->flags) &
953            VRING_USED_F_NO_NOTIFY) == 0)
954         virtio_kick (vm, vring, vif);
955     }
956
957   return n_left;
958 }
959
960 static u16
961 virtio_interface_tx_gso_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
962                                 virtio_if_t *vif, virtio_if_type_t type,
963                                 virtio_vring_t *vring, u32 *buffers,
964                                 u16 n_left, int packed, int do_gso,
965                                 int csum_offload)
966 {
967   if (packed)
968     return virtio_interface_tx_packed_gso_inline (vm, node, vif, type, vring,
969                                                   buffers, n_left,
970                                                   do_gso, csum_offload);
971   else
972     return virtio_interface_tx_split_gso_inline (vm, node, vif, type, vring,
973                                                  buffers, n_left,
974                                                  do_gso, csum_offload);
975 }
976
977 static u16
978 virtio_interface_tx_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
979                             virtio_if_t *vif, virtio_vring_t *vring,
980                             virtio_if_type_t type, u32 *buffers, u16 n_left,
981                             int packed)
982 {
983   vnet_main_t *vnm = vnet_get_main ();
984   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
985
986   if (hw->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO)
987     return virtio_interface_tx_gso_inline (vm, node, vif, type, vring,
988                                            buffers, n_left, packed,
989                                            1 /* do_gso */ ,
990                                            1 /* checksum offload */ );
991   else if (hw->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_L4_TX_CKSUM)
992     return virtio_interface_tx_gso_inline (vm, node, vif, type, vring,
993                                            buffers, n_left, packed,
994                                            0 /* no do_gso */ ,
995                                            1 /* checksum offload */ );
996   else
997     return virtio_interface_tx_gso_inline (vm, node, vif, type, vring,
998                                            buffers, n_left, packed,
999                                            0 /* no do_gso */ ,
1000                                            0 /* no checksum offload */ );
1001 }
1002
1003 VNET_DEVICE_CLASS_TX_FN (virtio_device_class) (vlib_main_t * vm,
1004                                                vlib_node_runtime_t * node,
1005                                                vlib_frame_t * frame)
1006 {
1007   virtio_main_t *nm = &virtio_main;
1008   vnet_interface_output_runtime_t *rund = (void *) node->runtime_data;
1009   virtio_if_t *vif = pool_elt_at_index (nm->interfaces, rund->dev_instance);
1010   u16 qid = vm->thread_index % vif->num_txqs;
1011   virtio_vring_t *vring = vec_elt_at_index (vif->txq_vrings, qid);
1012   u16 n_left = frame->n_vectors;
1013   u32 *buffers = vlib_frame_vector_args (frame);
1014   u32 to[GRO_TO_VECTOR_SIZE (n_left)];
1015   int packed = vif->is_packed;
1016   u16 n_vectors = frame->n_vectors;
1017
1018   clib_spinlock_lock_if_init (&vring->lockp);
1019
1020   if (vif->packet_coalesce)
1021     {
1022       n_vectors = n_left =
1023         vnet_gro_inline (vm, vring->flow_table, buffers, n_left, to);
1024       buffers = to;
1025     }
1026
1027   u16 retry_count = 2;
1028
1029 retry:
1030   /* free consumed buffers */
1031   virtio_free_used_device_desc (vm, vring, node->node_index, packed);
1032
1033   if (vif->type == VIRTIO_IF_TYPE_TAP)
1034     n_left = virtio_interface_tx_inline (vm, node, vif, vring,
1035                                          VIRTIO_IF_TYPE_TAP,
1036                                          &buffers[n_vectors - n_left],
1037                                          n_left, packed);
1038   else if (vif->type == VIRTIO_IF_TYPE_PCI)
1039     n_left = virtio_interface_tx_inline (vm, node, vif, vring,
1040                                          VIRTIO_IF_TYPE_PCI,
1041                                          &buffers[n_vectors - n_left],
1042                                          n_left, packed);
1043   else if (vif->type == VIRTIO_IF_TYPE_TUN)
1044     n_left = virtio_interface_tx_inline (vm, node, vif, vring,
1045                                          VIRTIO_IF_TYPE_TUN,
1046                                          &buffers[n_vectors - n_left],
1047                                          n_left, packed);
1048   else
1049     ASSERT (0);
1050
1051   if (n_left && retry_count--)
1052     goto retry;
1053
1054   if (vif->packet_buffering && n_left)
1055     {
1056       u16 n_buffered = virtio_vring_buffering_store_packets (vring->buffering,
1057                                                              &buffers
1058                                                              [n_vectors
1059                                                               - n_left],
1060                                                              n_left);
1061       n_left -= n_buffered;
1062     }
1063   if (n_left)
1064     virtio_interface_drop_inline (vm, vif, node->node_index,
1065                                   &buffers[n_vectors - n_left], n_left,
1066                                   VIRTIO_TX_ERROR_NO_FREE_SLOTS);
1067
1068   clib_spinlock_unlock_if_init (&vring->lockp);
1069
1070   return frame->n_vectors - n_left;
1071 }
1072
1073 static void
1074 virtio_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
1075                                 u32 node_index)
1076 {
1077   virtio_main_t *apm = &virtio_main;
1078   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1079   virtio_if_t *vif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
1080
1081   /* Shut off redirection */
1082   if (node_index == ~0)
1083     {
1084       vif->per_interface_next_index = node_index;
1085       return;
1086     }
1087
1088   vif->per_interface_next_index =
1089     vlib_node_add_next (vlib_get_main (), virtio_input_node.index,
1090                         node_index);
1091 }
1092
1093 static void
1094 virtio_clear_hw_interface_counters (u32 instance)
1095 {
1096   /* Nothing for now */
1097 }
1098
1099 static void
1100 virtio_set_rx_interrupt (virtio_if_t *vif, virtio_vring_t *vring)
1101 {
1102   if (vif->is_packed)
1103     vring->driver_event->flags &= ~VRING_EVENT_F_DISABLE;
1104   else
1105     vring->avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
1106 }
1107
1108 static void
1109 virtio_set_rx_polling (virtio_if_t *vif, virtio_vring_t *vring)
1110 {
1111   if (vif->is_packed)
1112     vring->driver_event->flags |= VRING_EVENT_F_DISABLE;
1113   else
1114     vring->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
1115 }
1116
1117 static clib_error_t *
1118 virtio_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid,
1119                                  vnet_hw_if_rx_mode mode)
1120 {
1121   vlib_main_t *vm = vnm->vlib_main;
1122   virtio_main_t *mm = &virtio_main;
1123   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1124   virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
1125   virtio_vring_t *rx_vring = vec_elt_at_index (vif->rxq_vrings, qid);
1126
1127   if (vif->type == VIRTIO_IF_TYPE_PCI && !(vif->support_int_mode))
1128     {
1129       virtio_set_rx_polling (vif, rx_vring);
1130       return clib_error_return (0, "interrupt mode is not supported");
1131     }
1132
1133   if (mode == VNET_HW_IF_RX_MODE_POLLING)
1134     {
1135       if (vif->packet_coalesce || vif->packet_buffering)
1136         {
1137           if (mm->interrupt_queues_count > 0)
1138             mm->interrupt_queues_count--;
1139           if (mm->interrupt_queues_count == 0)
1140             vlib_process_signal_event (vm,
1141                                        virtio_send_interrupt_node.index,
1142                                        VIRTIO_EVENT_STOP_TIMER, 0);
1143         }
1144       virtio_set_rx_polling (vif, rx_vring);
1145     }
1146   else
1147     {
1148       if (vif->packet_coalesce || vif->packet_buffering)
1149         {
1150           mm->interrupt_queues_count++;
1151           if (mm->interrupt_queues_count == 1)
1152             vlib_process_signal_event (vm,
1153                                        virtio_send_interrupt_node.index,
1154                                        VIRTIO_EVENT_START_TIMER, 0);
1155         }
1156       virtio_set_rx_interrupt (vif, rx_vring);
1157     }
1158
1159   rx_vring->mode = mode;
1160
1161   return 0;
1162 }
1163
1164 static clib_error_t *
1165 virtio_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
1166 {
1167   virtio_main_t *mm = &virtio_main;
1168   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1169   virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
1170
1171   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1172     {
1173       vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
1174       vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
1175                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
1176     }
1177   else
1178     {
1179       vif->flags &= ~VIRTIO_IF_FLAG_ADMIN_UP;
1180       vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
1181     }
1182   return 0;
1183 }
1184
1185 static clib_error_t *
1186 virtio_subif_add_del_function (vnet_main_t * vnm,
1187                                u32 hw_if_index,
1188                                struct vnet_sw_interface_t *st, int is_add)
1189 {
1190   /* Nothing for now */
1191   return 0;
1192 }
1193
1194 /* *INDENT-OFF* */
1195 VNET_DEVICE_CLASS (virtio_device_class) = {
1196   .name = "virtio",
1197   .format_device_name = format_virtio_device_name,
1198   .format_device = format_virtio_device,
1199   .format_tx_trace = format_virtio_tx_trace,
1200   .tx_function_n_errors = VIRTIO_TX_N_ERROR,
1201   .tx_function_error_strings = virtio_tx_func_error_strings,
1202   .rx_redirect_to_node = virtio_set_interface_next_node,
1203   .clear_counters = virtio_clear_hw_interface_counters,
1204   .admin_up_down_function = virtio_interface_admin_up_down,
1205   .subif_add_del_function = virtio_subif_add_del_function,
1206   .rx_mode_change_function = virtio_interface_rx_mode_change,
1207 };
1208
1209 /* *INDENT-ON* */
1210
1211 /*
1212  * fd.io coding-style-patch-verification: ON
1213  *
1214  * Local Variables:
1215  * eval: (c-set-style "gnu")
1216  * End:
1217  */