vhost: Add event index for interrupt notification to driver
[vpp.git] / src / vnet / devices / virtio / vhost_user_output.c
1 /*
2  *------------------------------------------------------------------
3  * vhost-user-output
4  *
5  * Copyright (c) 2014-2018 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <stddef.h>
21 #include <fcntl.h>              /* for open */
22 #include <sys/ioctl.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/uio.h>            /* for iovec */
28 #include <netinet/in.h>
29 #include <sys/vfs.h>
30
31 #include <linux/if_arp.h>
32 #include <linux/if_tun.h>
33
34 #include <vlib/vlib.h>
35 #include <vlib/unix/unix.h>
36
37 #include <vnet/ethernet/ethernet.h>
38 #include <vnet/devices/devices.h>
39 #include <vnet/feature/feature.h>
40
41 #include <vnet/devices/virtio/vhost_user.h>
42 #include <vnet/devices/virtio/vhost_user_inline.h>
43
44 #include <vnet/gso/hdr_offset_parser.h>
45 /*
46  * On the transmit side, we keep processing the buffers from vlib in the while
47  * loop and prepare the copy order to be executed later. However, the static
48  * array which we keep the copy order is limited to VHOST_USER_COPY_ARRAY_N
49  * entries. In order to not corrupt memory, we have to do the copy when the
50  * static array reaches the copy threshold. We subtract 40 in case the code
51  * goes into the inner loop for a maximum of 64k frames which may require
52  * more array entries. We subtract 200 because our default buffer size is
53  * 2048 and the default desc len is likely 1536. While it takes less than 40
54  * vlib buffers for the jumbo frame, it may take twice as much descriptors
55  * for the same jumbo frame. Use 200 for the extra head room.
56  */
57 #define VHOST_USER_TX_COPY_THRESHOLD (VHOST_USER_COPY_ARRAY_N - 200)
58
59 extern vnet_device_class_t vhost_user_device_class;
60
61 #define foreach_vhost_user_tx_func_error      \
62   _(NONE, "no error")  \
63   _(NOT_READY, "vhost vring not ready")  \
64   _(DOWN, "vhost interface is down")  \
65   _(PKT_DROP_NOBUF, "tx packet drops (no available descriptors)")  \
66   _(PKT_DROP_NOMRG, "tx packet drops (cannot merge descriptors)")  \
67   _(MMAP_FAIL, "mmap failure") \
68   _(INDIRECT_OVERFLOW, "indirect descriptor table overflow")
69
70 typedef enum
71 {
72 #define _(f,s) VHOST_USER_TX_FUNC_ERROR_##f,
73   foreach_vhost_user_tx_func_error
74 #undef _
75     VHOST_USER_TX_FUNC_N_ERROR,
76 } vhost_user_tx_func_error_t;
77
78 static __clib_unused char *vhost_user_tx_func_error_strings[] = {
79 #define _(n,s) s,
80   foreach_vhost_user_tx_func_error
81 #undef _
82 };
83
84 static __clib_unused u8 *
85 format_vhost_user_interface_name (u8 * s, va_list * args)
86 {
87   u32 i = va_arg (*args, u32);
88   u32 show_dev_instance = ~0;
89   vhost_user_main_t *vum = &vhost_user_main;
90
91   if (i < vec_len (vum->show_dev_instance_by_real_dev_instance))
92     show_dev_instance = vum->show_dev_instance_by_real_dev_instance[i];
93
94   if (show_dev_instance != ~0)
95     i = show_dev_instance;
96
97   s = format (s, "VirtualEthernet0/0/%d", i);
98   return s;
99 }
100
101 static __clib_unused int
102 vhost_user_name_renumber (vnet_hw_interface_t * hi, u32 new_dev_instance)
103 {
104   // FIXME: check if the new dev instance is already used
105   vhost_user_main_t *vum = &vhost_user_main;
106   vhost_user_intf_t *vui = pool_elt_at_index (vum->vhost_user_interfaces,
107                                               hi->dev_instance);
108
109   vec_validate_init_empty (vum->show_dev_instance_by_real_dev_instance,
110                            hi->dev_instance, ~0);
111
112   vum->show_dev_instance_by_real_dev_instance[hi->dev_instance] =
113     new_dev_instance;
114
115   vu_log_debug (vui, "renumbered vhost-user interface dev_instance %d to %d",
116                 hi->dev_instance, new_dev_instance);
117
118   return 0;
119 }
120
121 /**
122  * @brief Spin until the vring is successfully locked
123  */
124 static_always_inline void
125 vhost_user_vring_lock (vhost_user_intf_t * vui, u32 qid)
126 {
127   clib_spinlock_lock_if_init (&vui->vrings[qid].vring_lock);
128 }
129
130 /**
131  * @brief Unlock the vring lock
132  */
133 static_always_inline void
134 vhost_user_vring_unlock (vhost_user_intf_t * vui, u32 qid)
135 {
136   clib_spinlock_unlock_if_init (&vui->vrings[qid].vring_lock);
137 }
138
139 static_always_inline void
140 vhost_user_tx_trace (vhost_trace_t * t,
141                      vhost_user_intf_t * vui, u16 qid,
142                      vlib_buffer_t * b, vhost_user_vring_t * rxvq)
143 {
144   vhost_user_main_t *vum = &vhost_user_main;
145   u32 last_avail_idx = rxvq->last_avail_idx;
146   u32 desc_current = rxvq->avail->ring[last_avail_idx & rxvq->qsz_mask];
147   vring_desc_t *hdr_desc = 0;
148   u32 hint = 0;
149
150   clib_memset (t, 0, sizeof (*t));
151   t->device_index = vui - vum->vhost_user_interfaces;
152   t->qid = qid;
153
154   hdr_desc = &rxvq->desc[desc_current];
155   if (rxvq->desc[desc_current].flags & VRING_DESC_F_INDIRECT)
156     {
157       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_INDIRECT;
158       /* Header is the first here */
159       hdr_desc = map_guest_mem (vui, rxvq->desc[desc_current].addr, &hint);
160     }
161   if (rxvq->desc[desc_current].flags & VRING_DESC_F_NEXT)
162     {
163       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_SIMPLE_CHAINED;
164     }
165   if (!(rxvq->desc[desc_current].flags & VRING_DESC_F_NEXT) &&
166       !(rxvq->desc[desc_current].flags & VRING_DESC_F_INDIRECT))
167     {
168       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_SINGLE_DESC;
169     }
170
171   t->first_desc_len = hdr_desc ? hdr_desc->len : 0;
172 }
173
174 static_always_inline u32
175 vhost_user_tx_copy (vhost_user_intf_t * vui, vhost_copy_t * cpy,
176                     u16 copy_len, u32 * map_hint)
177 {
178   void *dst0, *dst1, *dst2, *dst3;
179   if (PREDICT_TRUE (copy_len >= 4))
180     {
181       if (PREDICT_FALSE (!(dst2 = map_guest_mem (vui, cpy[0].dst, map_hint))))
182         return 1;
183       if (PREDICT_FALSE (!(dst3 = map_guest_mem (vui, cpy[1].dst, map_hint))))
184         return 1;
185       while (PREDICT_TRUE (copy_len >= 4))
186         {
187           dst0 = dst2;
188           dst1 = dst3;
189
190           if (PREDICT_FALSE
191               (!(dst2 = map_guest_mem (vui, cpy[2].dst, map_hint))))
192             return 1;
193           if (PREDICT_FALSE
194               (!(dst3 = map_guest_mem (vui, cpy[3].dst, map_hint))))
195             return 1;
196
197           CLIB_PREFETCH ((void *) cpy[2].src, 64, LOAD);
198           CLIB_PREFETCH ((void *) cpy[3].src, 64, LOAD);
199
200           clib_memcpy_fast (dst0, (void *) cpy[0].src, cpy[0].len);
201           clib_memcpy_fast (dst1, (void *) cpy[1].src, cpy[1].len);
202
203           vhost_user_log_dirty_pages_2 (vui, cpy[0].dst, cpy[0].len, 1);
204           vhost_user_log_dirty_pages_2 (vui, cpy[1].dst, cpy[1].len, 1);
205           copy_len -= 2;
206           cpy += 2;
207         }
208     }
209   while (copy_len)
210     {
211       if (PREDICT_FALSE (!(dst0 = map_guest_mem (vui, cpy->dst, map_hint))))
212         return 1;
213       clib_memcpy_fast (dst0, (void *) cpy->src, cpy->len);
214       vhost_user_log_dirty_pages_2 (vui, cpy->dst, cpy->len, 1);
215       copy_len -= 1;
216       cpy += 1;
217     }
218   return 0;
219 }
220
221 static_always_inline void
222 vhost_user_handle_tx_offload (vhost_user_intf_t * vui, vlib_buffer_t * b,
223                               virtio_net_hdr_t * hdr)
224 {
225   generic_header_offset_t gho = { 0 };
226   int is_ip4 = b->flags & VNET_BUFFER_F_IS_IP4;
227   int is_ip6 = b->flags & VNET_BUFFER_F_IS_IP6;
228
229   ASSERT (!(is_ip4 && is_ip6));
230   vnet_generic_header_offset_parser (b, &gho, 1 /* l2 */ , is_ip4, is_ip6);
231   if (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM)
232     {
233       ip4_header_t *ip4;
234
235       ip4 =
236         (ip4_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
237       ip4->checksum = ip4_header_checksum (ip4);
238     }
239
240   /* checksum offload */
241   if (b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)
242     {
243       hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
244       hdr->csum_start = gho.l4_hdr_offset;
245       hdr->csum_offset = offsetof (udp_header_t, checksum);
246     }
247   else if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
248     {
249       hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
250       hdr->csum_start = gho.l4_hdr_offset;
251       hdr->csum_offset = offsetof (tcp_header_t, checksum);
252     }
253
254   /* GSO offload */
255   if (b->flags & VNET_BUFFER_F_GSO)
256     {
257       if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
258         {
259           if (is_ip4 &&
260               (vui->features & VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO4)))
261             {
262               hdr->gso_size = vnet_buffer2 (b)->gso_size;
263               hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
264             }
265           else if (is_ip6 &&
266                    (vui->features & VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO6)))
267             {
268               hdr->gso_size = vnet_buffer2 (b)->gso_size;
269               hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
270             }
271         }
272       else if ((vui->features & VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_UFO)) &&
273                (b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
274         {
275           hdr->gso_size = vnet_buffer2 (b)->gso_size;
276           hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
277         }
278     }
279 }
280
281 static_always_inline void
282 vhost_user_mark_desc_available (vlib_main_t * vm, vhost_user_intf_t * vui,
283                                 vhost_user_vring_t * rxvq,
284                                 u16 * n_descs_processed, u8 chained,
285                                 vlib_frame_t * frame, u32 n_left)
286 {
287   u16 desc_idx, flags;
288   vring_packed_desc_t *desc_table = rxvq->packed_desc;
289   u16 last_used_idx = rxvq->last_used_idx;
290
291   if (PREDICT_FALSE (*n_descs_processed == 0))
292     return;
293
294   if (rxvq->used_wrap_counter)
295     flags = desc_table[last_used_idx & rxvq->qsz_mask].flags |
296       (VRING_DESC_F_AVAIL | VRING_DESC_F_USED);
297   else
298     flags = desc_table[last_used_idx & rxvq->qsz_mask].flags &
299       ~(VRING_DESC_F_AVAIL | VRING_DESC_F_USED);
300
301   vhost_user_advance_last_used_idx (rxvq);
302
303   for (desc_idx = 1; desc_idx < *n_descs_processed; desc_idx++)
304     {
305       if (rxvq->used_wrap_counter)
306         desc_table[rxvq->last_used_idx & rxvq->qsz_mask].flags |=
307           (VRING_DESC_F_AVAIL | VRING_DESC_F_USED);
308       else
309         desc_table[rxvq->last_used_idx & rxvq->qsz_mask].flags &=
310           ~(VRING_DESC_F_AVAIL | VRING_DESC_F_USED);
311       vhost_user_advance_last_used_idx (rxvq);
312     }
313
314   desc_table[last_used_idx & rxvq->qsz_mask].flags = flags;
315
316   *n_descs_processed = 0;
317
318   if (chained)
319     {
320       vring_packed_desc_t *desc_table = rxvq->packed_desc;
321
322       while (desc_table[rxvq->last_used_idx & rxvq->qsz_mask].flags &
323              VRING_DESC_F_NEXT)
324         vhost_user_advance_last_used_idx (rxvq);
325
326       /* Advance past the current chained table entries */
327       vhost_user_advance_last_used_idx (rxvq);
328     }
329
330   /* interrupt (call) handling */
331   if ((rxvq->callfd_idx != ~0) &&
332       (rxvq->avail_event->flags != VRING_EVENT_F_DISABLE))
333     {
334       vhost_user_main_t *vum = &vhost_user_main;
335
336       rxvq->n_since_last_int += frame->n_vectors - n_left;
337       if (rxvq->n_since_last_int > vum->coalesce_frames)
338         vhost_user_send_call (vm, vui, rxvq);
339     }
340 }
341
342 static_always_inline void
343 vhost_user_tx_trace_packed (vhost_trace_t * t, vhost_user_intf_t * vui,
344                             u16 qid, vlib_buffer_t * b,
345                             vhost_user_vring_t * rxvq)
346 {
347   vhost_user_main_t *vum = &vhost_user_main;
348   u32 last_avail_idx = rxvq->last_avail_idx;
349   u32 desc_current = last_avail_idx & rxvq->qsz_mask;
350   vring_packed_desc_t *hdr_desc = 0;
351   u32 hint = 0;
352
353   clib_memset (t, 0, sizeof (*t));
354   t->device_index = vui - vum->vhost_user_interfaces;
355   t->qid = qid;
356
357   hdr_desc = &rxvq->packed_desc[desc_current];
358   if (rxvq->packed_desc[desc_current].flags & VRING_DESC_F_INDIRECT)
359     {
360       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_INDIRECT;
361       /* Header is the first here */
362       hdr_desc = map_guest_mem (vui, rxvq->packed_desc[desc_current].addr,
363                                 &hint);
364     }
365   if (rxvq->packed_desc[desc_current].flags & VRING_DESC_F_NEXT)
366     {
367       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_SIMPLE_CHAINED;
368     }
369   if (!(rxvq->packed_desc[desc_current].flags & VRING_DESC_F_NEXT) &&
370       !(rxvq->packed_desc[desc_current].flags & VRING_DESC_F_INDIRECT))
371     {
372       t->virtio_ring_flags |= 1 << VIRTIO_TRACE_F_SINGLE_DESC;
373     }
374
375   t->first_desc_len = hdr_desc ? hdr_desc->len : 0;
376 }
377
378 static_always_inline uword
379 vhost_user_device_class_packed (vlib_main_t * vm, vlib_node_runtime_t * node,
380                                 vlib_frame_t * frame)
381 {
382   u32 *buffers = vlib_frame_vector_args (frame);
383   u32 n_left = frame->n_vectors;
384   vhost_user_main_t *vum = &vhost_user_main;
385   vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
386   vhost_user_intf_t *vui =
387     pool_elt_at_index (vum->vhost_user_interfaces, rd->dev_instance);
388   u32 qid;
389   vhost_user_vring_t *rxvq;
390   u8 error;
391   u32 thread_index = vm->thread_index;
392   vhost_cpu_t *cpu = &vum->cpus[thread_index];
393   u32 map_hint = 0;
394   u8 retry = 8;
395   u16 copy_len;
396   u16 tx_headers_len;
397   vring_packed_desc_t *desc_table;
398   u32 or_flags;
399   u16 desc_head, desc_index, desc_len;
400   u16 n_descs_processed;
401   u8 indirect, chained;
402
403   qid = VHOST_VRING_IDX_RX (*vec_elt_at_index (vui->per_cpu_tx_qid,
404                                                thread_index));
405   rxvq = &vui->vrings[qid];
406
407 retry:
408   error = VHOST_USER_TX_FUNC_ERROR_NONE;
409   tx_headers_len = 0;
410   copy_len = 0;
411   n_descs_processed = 0;
412
413   while (n_left > 0)
414     {
415       vlib_buffer_t *b0, *current_b0;
416       uword buffer_map_addr;
417       u32 buffer_len;
418       u16 bytes_left;
419       u32 total_desc_len = 0;
420       u16 n_entries = 0;
421
422       indirect = 0;
423       chained = 0;
424       if (PREDICT_TRUE (n_left > 1))
425         vlib_prefetch_buffer_with_index (vm, buffers[1], LOAD);
426
427       b0 = vlib_get_buffer (vm, buffers[0]);
428       if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
429         {
430           cpu->current_trace = vlib_add_trace (vm, node, b0,
431                                                sizeof (*cpu->current_trace));
432           vhost_user_tx_trace_packed (cpu->current_trace, vui, qid / 2, b0,
433                                       rxvq);
434         }
435
436       desc_table = rxvq->packed_desc;
437       desc_head = desc_index = rxvq->last_avail_idx & rxvq->qsz_mask;
438       if (PREDICT_FALSE (!vhost_user_packed_desc_available (rxvq, desc_head)))
439         {
440           error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
441           goto done;
442         }
443       /*
444        * Go deeper in case of indirect descriptor.
445        * To test it, turn off mrg_rxbuf.
446        */
447       if (desc_table[desc_head].flags & VRING_DESC_F_INDIRECT)
448         {
449           indirect = 1;
450           if (PREDICT_FALSE (desc_table[desc_head].len <
451                              sizeof (vring_packed_desc_t)))
452             {
453               error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
454               goto done;
455             }
456           n_entries = desc_table[desc_head].len >> 4;
457           desc_table = map_guest_mem (vui, desc_table[desc_index].addr,
458                                       &map_hint);
459           if (PREDICT_FALSE (desc_table == 0))
460             {
461               error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
462               goto done;
463             }
464           desc_index = 0;
465         }
466       else if (rxvq->packed_desc[desc_head].flags & VRING_DESC_F_NEXT)
467         chained = 1;
468
469       desc_len = vui->virtio_net_hdr_sz;
470       buffer_map_addr = desc_table[desc_index].addr;
471       buffer_len = desc_table[desc_index].len;
472
473       /* Get a header from the header array */
474       virtio_net_hdr_mrg_rxbuf_t *hdr = &cpu->tx_headers[tx_headers_len];
475       tx_headers_len++;
476       hdr->hdr.flags = 0;
477       hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE;
478       hdr->num_buffers = 1;
479
480       or_flags = (b0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM) ||
481         (b0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM) ||
482         (b0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM);
483
484       /* Guest supports csum offload and buffer requires checksum offload? */
485       if (or_flags &&
486           (vui->features & VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM)))
487         vhost_user_handle_tx_offload (vui, b0, &hdr->hdr);
488
489       /* Prepare a copy order executed later for the header */
490       ASSERT (copy_len < VHOST_USER_COPY_ARRAY_N);
491       vhost_copy_t *cpy = &cpu->copy[copy_len];
492       copy_len++;
493       cpy->len = vui->virtio_net_hdr_sz;
494       cpy->dst = buffer_map_addr;
495       cpy->src = (uword) hdr;
496
497       buffer_map_addr += vui->virtio_net_hdr_sz;
498       buffer_len -= vui->virtio_net_hdr_sz;
499       bytes_left = b0->current_length;
500       current_b0 = b0;
501       while (1)
502         {
503           if (buffer_len == 0)
504             {
505               /* Get new output */
506               if (chained)
507                 {
508                   /*
509                    * Next one is chained
510                    * Test it with both indirect and mrg_rxbuf off
511                    */
512                   if (PREDICT_FALSE (!(desc_table[desc_index].flags &
513                                        VRING_DESC_F_NEXT)))
514                     {
515                       /*
516                        * Last descriptor in chain.
517                        * Dequeue queued descriptors for this packet
518                        */
519                       vhost_user_dequeue_chained_descs (rxvq,
520                                                         &n_descs_processed);
521                       error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
522                       goto done;
523                     }
524                   vhost_user_advance_last_avail_idx (rxvq);
525                   desc_index = rxvq->last_avail_idx & rxvq->qsz_mask;
526                   n_descs_processed++;
527                   buffer_map_addr = desc_table[desc_index].addr;
528                   buffer_len = desc_table[desc_index].len;
529                   total_desc_len += desc_len;
530                   desc_len = 0;
531                 }
532               else if (indirect)
533                 {
534                   /*
535                    * Indirect table
536                    * Test it with mrg_rxnuf off
537                    */
538                   if (PREDICT_TRUE (n_entries > 0))
539                     n_entries--;
540                   else
541                     {
542                       /* Dequeue queued descriptors for this packet */
543                       vhost_user_dequeue_chained_descs (rxvq,
544                                                         &n_descs_processed);
545                       error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
546                       goto done;
547                     }
548                   total_desc_len += desc_len;
549                   desc_index = (desc_index + 1) & rxvq->qsz_mask;
550                   buffer_map_addr = desc_table[desc_index].addr;
551                   buffer_len = desc_table[desc_index].len;
552                   desc_len = 0;
553                 }
554               else if (vui->virtio_net_hdr_sz == 12)
555                 {
556                   /*
557                    * MRG is available
558                    * This is the default setting for the guest VM
559                    */
560                   virtio_net_hdr_mrg_rxbuf_t *hdr =
561                     &cpu->tx_headers[tx_headers_len - 1];
562
563                   desc_table[desc_index].len = desc_len;
564                   vhost_user_advance_last_avail_idx (rxvq);
565                   desc_head = desc_index =
566                     rxvq->last_avail_idx & rxvq->qsz_mask;
567                   hdr->num_buffers++;
568                   n_descs_processed++;
569                   desc_len = 0;
570
571                   if (PREDICT_FALSE (!vhost_user_packed_desc_available
572                                      (rxvq, desc_index)))
573                     {
574                       /* Dequeue queued descriptors for this packet */
575                       vhost_user_dequeue_descs (rxvq, hdr,
576                                                 &n_descs_processed);
577                       error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
578                       goto done;
579                     }
580
581                   buffer_map_addr = desc_table[desc_index].addr;
582                   buffer_len = desc_table[desc_index].len;
583                 }
584               else
585                 {
586                   error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOMRG;
587                   goto done;
588                 }
589             }
590
591           ASSERT (copy_len < VHOST_USER_COPY_ARRAY_N);
592           vhost_copy_t *cpy = &cpu->copy[copy_len];
593           copy_len++;
594           cpy->len = bytes_left;
595           cpy->len = (cpy->len > buffer_len) ? buffer_len : cpy->len;
596           cpy->dst = buffer_map_addr;
597           cpy->src = (uword) vlib_buffer_get_current (current_b0) +
598             current_b0->current_length - bytes_left;
599
600           bytes_left -= cpy->len;
601           buffer_len -= cpy->len;
602           buffer_map_addr += cpy->len;
603           desc_len += cpy->len;
604
605           CLIB_PREFETCH (&rxvq->packed_desc, CLIB_CACHE_LINE_BYTES, LOAD);
606
607           /* Check if vlib buffer has more data. If not, get more or break */
608           if (PREDICT_TRUE (!bytes_left))
609             {
610               if (PREDICT_FALSE
611                   (current_b0->flags & VLIB_BUFFER_NEXT_PRESENT))
612                 {
613                   current_b0 = vlib_get_buffer (vm, current_b0->next_buffer);
614                   bytes_left = current_b0->current_length;
615                 }
616               else
617                 {
618                   /* End of packet */
619                   break;
620                 }
621             }
622         }
623
624       /* Move from available to used ring */
625       total_desc_len += desc_len;
626       rxvq->packed_desc[desc_head].len = total_desc_len;
627
628       vhost_user_advance_last_avail_table_idx (vui, rxvq, chained);
629       n_descs_processed++;
630
631       if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
632         cpu->current_trace->hdr = cpu->tx_headers[tx_headers_len - 1];
633
634       n_left--;
635
636       /*
637        * Do the copy periodically to prevent
638        * cpu->copy array overflow and corrupt memory
639        */
640       if (PREDICT_FALSE (copy_len >= VHOST_USER_TX_COPY_THRESHOLD) || chained)
641         {
642           if (PREDICT_FALSE (vhost_user_tx_copy (vui, cpu->copy, copy_len,
643                                                  &map_hint)))
644             vlib_error_count (vm, node->node_index,
645                               VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
646           copy_len = 0;
647
648           /* give buffers back to driver */
649           vhost_user_mark_desc_available (vm, vui, rxvq, &n_descs_processed,
650                                           chained, frame, n_left);
651         }
652
653       buffers++;
654     }
655
656 done:
657   if (PREDICT_TRUE (copy_len))
658     {
659       if (PREDICT_FALSE (vhost_user_tx_copy (vui, cpu->copy, copy_len,
660                                              &map_hint)))
661         vlib_error_count (vm, node->node_index,
662                           VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
663
664       vhost_user_mark_desc_available (vm, vui, rxvq, &n_descs_processed,
665                                       chained, frame, n_left);
666     }
667
668   /*
669    * When n_left is set, error is always set to something too.
670    * In case error is due to lack of remaining buffers, we go back up and
671    * retry.
672    * The idea is that it is better to waste some time on packets
673    * that have been processed already than dropping them and get
674    * more fresh packets with a good likelyhood that they will be dropped too.
675    * This technique also gives more time to VM driver to pick-up packets.
676    * In case the traffic flows from physical to virtual interfaces, this
677    * technique will end-up leveraging the physical NIC buffer in order to
678    * absorb the VM's CPU jitter.
679    */
680   if (n_left && (error == VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF) && retry)
681     {
682       retry--;
683       goto retry;
684     }
685
686   vhost_user_vring_unlock (vui, qid);
687
688   if (PREDICT_FALSE (n_left && error != VHOST_USER_TX_FUNC_ERROR_NONE))
689     {
690       vlib_error_count (vm, node->node_index, error, n_left);
691       vlib_increment_simple_counter
692         (vnet_main.interface_main.sw_if_counters +
693          VNET_INTERFACE_COUNTER_DROP, thread_index, vui->sw_if_index, n_left);
694     }
695
696   vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
697   return frame->n_vectors;
698 }
699
700 VNET_DEVICE_CLASS_TX_FN (vhost_user_device_class) (vlib_main_t * vm,
701                                                    vlib_node_runtime_t *
702                                                    node, vlib_frame_t * frame)
703 {
704   u32 *buffers = vlib_frame_vector_args (frame);
705   u32 n_left = frame->n_vectors;
706   vhost_user_main_t *vum = &vhost_user_main;
707   vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
708   vhost_user_intf_t *vui =
709     pool_elt_at_index (vum->vhost_user_interfaces, rd->dev_instance);
710   u32 qid = ~0;
711   vhost_user_vring_t *rxvq;
712   u8 error;
713   u32 thread_index = vm->thread_index;
714   vhost_cpu_t *cpu = &vum->cpus[thread_index];
715   u32 map_hint = 0;
716   u8 retry = 8;
717   u16 copy_len;
718   u16 tx_headers_len;
719   u32 or_flags;
720
721   if (PREDICT_FALSE (!vui->admin_up))
722     {
723       error = VHOST_USER_TX_FUNC_ERROR_DOWN;
724       goto done3;
725     }
726
727   if (PREDICT_FALSE (!vui->is_ready))
728     {
729       error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
730       goto done3;
731     }
732
733   qid = VHOST_VRING_IDX_RX (*vec_elt_at_index (vui->per_cpu_tx_qid,
734                                                thread_index));
735   rxvq = &vui->vrings[qid];
736   if (PREDICT_FALSE (rxvq->avail == 0))
737     {
738       error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
739       goto done3;
740     }
741
742   if (PREDICT_FALSE (vui->use_tx_spinlock))
743     vhost_user_vring_lock (vui, qid);
744
745   if (vhost_user_is_packed_ring_supported (vui))
746     return (vhost_user_device_class_packed (vm, node, frame));
747
748 retry:
749   error = VHOST_USER_TX_FUNC_ERROR_NONE;
750   tx_headers_len = 0;
751   copy_len = 0;
752   while (n_left > 0)
753     {
754       vlib_buffer_t *b0, *current_b0;
755       u16 desc_head, desc_index, desc_len;
756       vring_desc_t *desc_table;
757       uword buffer_map_addr;
758       u32 buffer_len;
759       u16 bytes_left;
760
761       if (PREDICT_TRUE (n_left > 1))
762         vlib_prefetch_buffer_with_index (vm, buffers[1], LOAD);
763
764       b0 = vlib_get_buffer (vm, buffers[0]);
765
766       if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
767         {
768           cpu->current_trace = vlib_add_trace (vm, node, b0,
769                                                sizeof (*cpu->current_trace));
770           vhost_user_tx_trace (cpu->current_trace, vui, qid / 2, b0, rxvq);
771         }
772
773       if (PREDICT_FALSE (rxvq->last_avail_idx == rxvq->avail->idx))
774         {
775           error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
776           goto done;
777         }
778
779       desc_table = rxvq->desc;
780       desc_head = desc_index =
781         rxvq->avail->ring[rxvq->last_avail_idx & rxvq->qsz_mask];
782
783       /* Go deeper in case of indirect descriptor
784        * I don't know of any driver providing indirect for RX. */
785       if (PREDICT_FALSE (rxvq->desc[desc_head].flags & VRING_DESC_F_INDIRECT))
786         {
787           if (PREDICT_FALSE
788               (rxvq->desc[desc_head].len < sizeof (vring_desc_t)))
789             {
790               error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
791               goto done;
792             }
793           if (PREDICT_FALSE
794               (!(desc_table =
795                  map_guest_mem (vui, rxvq->desc[desc_index].addr,
796                                 &map_hint))))
797             {
798               error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
799               goto done;
800             }
801           desc_index = 0;
802         }
803
804       desc_len = vui->virtio_net_hdr_sz;
805       buffer_map_addr = desc_table[desc_index].addr;
806       buffer_len = desc_table[desc_index].len;
807
808       {
809         // Get a header from the header array
810         virtio_net_hdr_mrg_rxbuf_t *hdr = &cpu->tx_headers[tx_headers_len];
811         tx_headers_len++;
812         hdr->hdr.flags = 0;
813         hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE;
814         hdr->num_buffers = 1;   //This is local, no need to check
815
816         or_flags = (b0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM) ||
817           (b0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM) ||
818           (b0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM);
819
820         /* Guest supports csum offload and buffer requires checksum offload? */
821         if (or_flags
822             && (vui->features & VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM)))
823           vhost_user_handle_tx_offload (vui, b0, &hdr->hdr);
824
825         // Prepare a copy order executed later for the header
826         ASSERT (copy_len < VHOST_USER_COPY_ARRAY_N);
827         vhost_copy_t *cpy = &cpu->copy[copy_len];
828         copy_len++;
829         cpy->len = vui->virtio_net_hdr_sz;
830         cpy->dst = buffer_map_addr;
831         cpy->src = (uword) hdr;
832       }
833
834       buffer_map_addr += vui->virtio_net_hdr_sz;
835       buffer_len -= vui->virtio_net_hdr_sz;
836       bytes_left = b0->current_length;
837       current_b0 = b0;
838       while (1)
839         {
840           if (buffer_len == 0)
841             {                   //Get new output
842               if (desc_table[desc_index].flags & VRING_DESC_F_NEXT)
843                 {
844                   //Next one is chained
845                   desc_index = desc_table[desc_index].next;
846                   buffer_map_addr = desc_table[desc_index].addr;
847                   buffer_len = desc_table[desc_index].len;
848                 }
849               else if (vui->virtio_net_hdr_sz == 12)    //MRG is available
850                 {
851                   virtio_net_hdr_mrg_rxbuf_t *hdr =
852                     &cpu->tx_headers[tx_headers_len - 1];
853
854                   //Move from available to used buffer
855                   rxvq->used->ring[rxvq->last_used_idx & rxvq->qsz_mask].id =
856                     desc_head;
857                   rxvq->used->ring[rxvq->last_used_idx & rxvq->qsz_mask].len =
858                     desc_len;
859                   vhost_user_log_dirty_ring (vui, rxvq,
860                                              ring[rxvq->last_used_idx &
861                                                   rxvq->qsz_mask]);
862
863                   rxvq->last_avail_idx++;
864                   rxvq->last_used_idx++;
865                   hdr->num_buffers++;
866                   desc_len = 0;
867
868                   if (PREDICT_FALSE
869                       (rxvq->last_avail_idx == rxvq->avail->idx))
870                     {
871                       //Dequeue queued descriptors for this packet
872                       rxvq->last_used_idx -= hdr->num_buffers - 1;
873                       rxvq->last_avail_idx -= hdr->num_buffers - 1;
874                       error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
875                       goto done;
876                     }
877
878                   desc_table = rxvq->desc;
879                   desc_head = desc_index =
880                     rxvq->avail->ring[rxvq->last_avail_idx & rxvq->qsz_mask];
881                   if (PREDICT_FALSE
882                       (rxvq->desc[desc_head].flags & VRING_DESC_F_INDIRECT))
883                     {
884                       //It is seriously unlikely that a driver will put indirect descriptor
885                       //after non-indirect descriptor.
886                       if (PREDICT_FALSE
887                           (rxvq->desc[desc_head].len < sizeof (vring_desc_t)))
888                         {
889                           error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
890                           goto done;
891                         }
892                       if (PREDICT_FALSE
893                           (!(desc_table =
894                              map_guest_mem (vui,
895                                             rxvq->desc[desc_index].addr,
896                                             &map_hint))))
897                         {
898                           error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
899                           goto done;
900                         }
901                       desc_index = 0;
902                     }
903                   buffer_map_addr = desc_table[desc_index].addr;
904                   buffer_len = desc_table[desc_index].len;
905                 }
906               else
907                 {
908                   error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOMRG;
909                   goto done;
910                 }
911             }
912
913           {
914             ASSERT (copy_len < VHOST_USER_COPY_ARRAY_N);
915             vhost_copy_t *cpy = &cpu->copy[copy_len];
916             copy_len++;
917             cpy->len = bytes_left;
918             cpy->len = (cpy->len > buffer_len) ? buffer_len : cpy->len;
919             cpy->dst = buffer_map_addr;
920             cpy->src = (uword) vlib_buffer_get_current (current_b0) +
921               current_b0->current_length - bytes_left;
922
923             bytes_left -= cpy->len;
924             buffer_len -= cpy->len;
925             buffer_map_addr += cpy->len;
926             desc_len += cpy->len;
927
928             CLIB_PREFETCH (&rxvq->desc, CLIB_CACHE_LINE_BYTES, LOAD);
929           }
930
931           // Check if vlib buffer has more data. If not, get more or break.
932           if (PREDICT_TRUE (!bytes_left))
933             {
934               if (PREDICT_FALSE
935                   (current_b0->flags & VLIB_BUFFER_NEXT_PRESENT))
936                 {
937                   current_b0 = vlib_get_buffer (vm, current_b0->next_buffer);
938                   bytes_left = current_b0->current_length;
939                 }
940               else
941                 {
942                   //End of packet
943                   break;
944                 }
945             }
946         }
947
948       //Move from available to used ring
949       rxvq->used->ring[rxvq->last_used_idx & rxvq->qsz_mask].id = desc_head;
950       rxvq->used->ring[rxvq->last_used_idx & rxvq->qsz_mask].len = desc_len;
951       vhost_user_log_dirty_ring (vui, rxvq,
952                                  ring[rxvq->last_used_idx & rxvq->qsz_mask]);
953       rxvq->last_avail_idx++;
954       rxvq->last_used_idx++;
955
956       if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
957         {
958           cpu->current_trace->hdr = cpu->tx_headers[tx_headers_len - 1];
959         }
960
961       n_left--;                 //At the end for error counting when 'goto done' is invoked
962
963       /*
964        * Do the copy periodically to prevent
965        * cpu->copy array overflow and corrupt memory
966        */
967       if (PREDICT_FALSE (copy_len >= VHOST_USER_TX_COPY_THRESHOLD))
968         {
969           if (PREDICT_FALSE (vhost_user_tx_copy (vui, cpu->copy, copy_len,
970                                                  &map_hint)))
971             {
972               vlib_error_count (vm, node->node_index,
973                                 VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
974             }
975           copy_len = 0;
976
977           /* give buffers back to driver */
978           CLIB_MEMORY_BARRIER ();
979           rxvq->used->idx = rxvq->last_used_idx;
980           vhost_user_log_dirty_ring (vui, rxvq, idx);
981         }
982       buffers++;
983     }
984
985 done:
986   //Do the memory copies
987   if (PREDICT_FALSE (vhost_user_tx_copy (vui, cpu->copy, copy_len,
988                                          &map_hint)))
989     {
990       vlib_error_count (vm, node->node_index,
991                         VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
992     }
993
994   CLIB_MEMORY_BARRIER ();
995   rxvq->used->idx = rxvq->last_used_idx;
996   vhost_user_log_dirty_ring (vui, rxvq, idx);
997
998   /*
999    * When n_left is set, error is always set to something too.
1000    * In case error is due to lack of remaining buffers, we go back up and
1001    * retry.
1002    * The idea is that it is better to waste some time on packets
1003    * that have been processed already than dropping them and get
1004    * more fresh packets with a good likelihood that they will be dropped too.
1005    * This technique also gives more time to VM driver to pick-up packets.
1006    * In case the traffic flows from physical to virtual interfaces, this
1007    * technique will end-up leveraging the physical NIC buffer in order to
1008    * absorb the VM's CPU jitter.
1009    */
1010   if (n_left && (error == VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF) && retry)
1011     {
1012       retry--;
1013       goto retry;
1014     }
1015
1016   /* interrupt (call) handling */
1017   if ((rxvq->callfd_idx != ~0) &&
1018       !(rxvq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
1019     {
1020       rxvq->n_since_last_int += frame->n_vectors - n_left;
1021
1022       if (rxvq->n_since_last_int > vum->coalesce_frames)
1023         vhost_user_send_call (vm, vui, rxvq);
1024     }
1025
1026   vhost_user_vring_unlock (vui, qid);
1027
1028 done3:
1029   if (PREDICT_FALSE (n_left && error != VHOST_USER_TX_FUNC_ERROR_NONE))
1030     {
1031       vlib_error_count (vm, node->node_index, error, n_left);
1032       vlib_increment_simple_counter
1033         (vnet_main.interface_main.sw_if_counters
1034          + VNET_INTERFACE_COUNTER_DROP,
1035          thread_index, vui->sw_if_index, n_left);
1036     }
1037
1038   vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
1039   return frame->n_vectors;
1040 }
1041
1042 static __clib_unused clib_error_t *
1043 vhost_user_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index,
1044                                      u32 qid, vnet_hw_if_rx_mode mode)
1045 {
1046   vlib_main_t *vm = vnm->vlib_main;
1047   vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
1048   vhost_user_main_t *vum = &vhost_user_main;
1049   vhost_user_intf_t *vui =
1050     pool_elt_at_index (vum->vhost_user_interfaces, hif->dev_instance);
1051   vhost_user_vring_t *txvq = &vui->vrings[VHOST_VRING_IDX_TX (qid)];
1052
1053   if ((mode == VNET_HW_IF_RX_MODE_INTERRUPT) ||
1054       (mode == VNET_HW_IF_RX_MODE_ADAPTIVE))
1055     {
1056       if (txvq->kickfd_idx == ~0)
1057         {
1058           // We cannot support interrupt mode if the driver opts out
1059           return clib_error_return (0, "Driver does not support interrupt");
1060         }
1061       if (txvq->mode == VNET_HW_IF_RX_MODE_POLLING)
1062         {
1063           vum->ifq_count++;
1064           // Start the timer if this is the first encounter on interrupt
1065           // interface/queue
1066           if ((vum->ifq_count == 1) &&
1067               (vum->coalesce_time > 0.0) && (vum->coalesce_frames > 0))
1068             vlib_process_signal_event (vm,
1069                                        vhost_user_send_interrupt_node.index,
1070                                        VHOST_USER_EVENT_START_TIMER, 0);
1071         }
1072     }
1073   else if (mode == VNET_HW_IF_RX_MODE_POLLING)
1074     {
1075       if (((txvq->mode == VNET_HW_IF_RX_MODE_INTERRUPT) ||
1076            (txvq->mode == VNET_HW_IF_RX_MODE_ADAPTIVE)) && vum->ifq_count)
1077         {
1078           vum->ifq_count--;
1079           // Stop the timer if there is no more interrupt interface/queue
1080           if ((vum->ifq_count == 0) &&
1081               (vum->coalesce_time > 0.0) && (vum->coalesce_frames > 0))
1082             vlib_process_signal_event (vm,
1083                                        vhost_user_send_interrupt_node.index,
1084                                        VHOST_USER_EVENT_STOP_TIMER, 0);
1085         }
1086     }
1087
1088   txvq->mode = mode;
1089   if (mode == VNET_HW_IF_RX_MODE_POLLING)
1090     txvq->used->flags = VRING_USED_F_NO_NOTIFY;
1091   else if ((mode == VNET_HW_IF_RX_MODE_ADAPTIVE) ||
1092            (mode == VNET_HW_IF_RX_MODE_INTERRUPT))
1093     txvq->used->flags = 0;
1094   else
1095     {
1096       vu_log_err (vui, "unhandled mode %d changed for if %d queue %d", mode,
1097                   hw_if_index, qid);
1098       return clib_error_return (0, "unsupported");
1099     }
1100
1101   return 0;
1102 }
1103
1104 static __clib_unused clib_error_t *
1105 vhost_user_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
1106                                     u32 flags)
1107 {
1108   vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
1109   vhost_user_main_t *vum = &vhost_user_main;
1110   vhost_user_intf_t *vui =
1111     pool_elt_at_index (vum->vhost_user_interfaces, hif->dev_instance);
1112   u8 link_old, link_new;
1113
1114   link_old = vui_is_link_up (vui);
1115
1116   vui->admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
1117
1118   link_new = vui_is_link_up (vui);
1119
1120   if (link_old != link_new)
1121     vnet_hw_interface_set_flags (vnm, vui->hw_if_index, link_new ?
1122                                  VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
1123
1124   return /* no error */ 0;
1125 }
1126
1127 /* *INDENT-OFF* */
1128 VNET_DEVICE_CLASS (vhost_user_device_class) = {
1129   .name = "vhost-user",
1130   .tx_function_n_errors = VHOST_USER_TX_FUNC_N_ERROR,
1131   .tx_function_error_strings = vhost_user_tx_func_error_strings,
1132   .format_device_name = format_vhost_user_interface_name,
1133   .name_renumber = vhost_user_name_renumber,
1134   .admin_up_down_function = vhost_user_interface_admin_up_down,
1135   .rx_mode_change_function = vhost_user_interface_rx_mode_change,
1136   .format_tx_trace = format_vhost_trace,
1137 };
1138
1139 /* *INDENT-ON* */
1140
1141 /*
1142  * fd.io coding-style-patch-verification: ON
1143  *
1144  * Local Variables:
1145  * eval: (c-set-style "gnu")
1146  * End:
1147  */