b329fdd771995d05188522f5c0a1dd3abc6492aa
[vpp.git] / src / vnet / devices / virtio / node.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 #include <net/if.h>
22 #ifdef __linux__
23 #include <linux/if_tun.h>
24 #elif __FreeBSD__
25 #include <net/if_tun.h>
26 #endif /* __linux */
27 #include <sys/ioctl.h>
28 #include <sys/eventfd.h>
29
30 #include <vlib/vlib.h>
31 #include <vlib/unix/unix.h>
32 #include <vnet/ethernet/ethernet.h>
33 #include <vnet/feature/feature.h>
34 #include <vnet/interface/rx_queue_funcs.h>
35 #include <vnet/ip/ip4_packet.h>
36 #include <vnet/ip/ip6_packet.h>
37 #include <vnet/udp/udp_packet.h>
38 #include <vnet/tcp/tcp_packet.h>
39 #include <vnet/devices/virtio/virtio.h>
40 #include <vnet/devices/virtio/virtio_inline.h>
41
42 static char *virtio_input_error_strings[] = {
43 #define _(n, s) s,
44   foreach_virtio_input_error
45 #undef _
46 };
47
48 typedef struct
49 {
50   u32 next_index;
51   u32 hw_if_index;
52   u16 ring;
53   u16 len;
54   vnet_virtio_net_hdr_v1_t hdr;
55 } virtio_input_trace_t;
56
57 static u8 *
58 format_virtio_input_trace (u8 * s, va_list * args)
59 {
60   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
61   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
62   virtio_input_trace_t *t = va_arg (*args, virtio_input_trace_t *);
63   u32 indent = format_get_indent (s);
64
65   s = format (s, "virtio: hw_if_index %d next-index %d vring %u len %u",
66               t->hw_if_index, t->next_index, t->ring, t->len);
67   s = format (s, "\n%Uhdr: flags 0x%02x gso_type 0x%02x hdr_len %u "
68               "gso_size %u csum_start %u csum_offset %u num_buffers %u",
69               format_white_space, indent + 2,
70               t->hdr.flags, t->hdr.gso_type, t->hdr.hdr_len, t->hdr.gso_size,
71               t->hdr.csum_start, t->hdr.csum_offset, t->hdr.num_buffers);
72   return s;
73 }
74
75 static_always_inline void
76 virtio_needs_csum (vlib_buffer_t *b0, vnet_virtio_net_hdr_v1_t *hdr,
77                    u8 *l4_proto, u8 *l4_hdr_sz, virtio_if_type_t type)
78 {
79   if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)
80     {
81       u16 ethertype = 0, l2hdr_sz = 0;
82       vnet_buffer_oflags_t oflags = 0;
83
84       if (type == VIRTIO_IF_TYPE_TUN)
85         {
86           switch (b0->data[0] & 0xf0)
87             {
88             case 0x40:
89               ethertype = ETHERNET_TYPE_IP4;
90               break;
91             case 0x60:
92               ethertype = ETHERNET_TYPE_IP6;
93               break;
94             }
95         }
96       else
97         {
98           ethernet_header_t *eh = (ethernet_header_t *) b0->data;
99           ethertype = clib_net_to_host_u16 (eh->type);
100           l2hdr_sz = sizeof (ethernet_header_t);
101
102           if (ethernet_frame_is_tagged (ethertype))
103             {
104               ethernet_vlan_header_t *vlan =
105                 (ethernet_vlan_header_t *) (eh + 1);
106
107               ethertype = clib_net_to_host_u16 (vlan->type);
108               l2hdr_sz += sizeof (*vlan);
109               if (ethertype == ETHERNET_TYPE_VLAN)
110                 {
111                   vlan++;
112                   ethertype = clib_net_to_host_u16 (vlan->type);
113                   l2hdr_sz += sizeof (*vlan);
114                 }
115             }
116         }
117
118       vnet_buffer (b0)->l2_hdr_offset = 0;
119       vnet_buffer (b0)->l3_hdr_offset = l2hdr_sz;
120
121       if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP4))
122         {
123           ip4_header_t *ip4 = (ip4_header_t *) (b0->data + l2hdr_sz);
124           vnet_buffer (b0)->l4_hdr_offset = l2hdr_sz + ip4_header_bytes (ip4);
125           *l4_proto = ip4->protocol;
126           oflags |= VNET_BUFFER_OFFLOAD_F_IP_CKSUM;
127           b0->flags |=
128             (VNET_BUFFER_F_IS_IP4 | VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
129              VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
130              VNET_BUFFER_F_L4_HDR_OFFSET_VALID);
131         }
132       else if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP6))
133         {
134           ip6_header_t *ip6 = (ip6_header_t *) (b0->data + l2hdr_sz);
135           vnet_buffer (b0)->l4_hdr_offset = l2hdr_sz + sizeof (ip6_header_t);
136           /* FIXME IPv6 EH traversal */
137           *l4_proto = ip6->protocol;
138           b0->flags |= (VNET_BUFFER_F_IS_IP6 |
139                         VNET_BUFFER_F_L2_HDR_OFFSET_VALID
140                         | VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
141                         VNET_BUFFER_F_L4_HDR_OFFSET_VALID);
142         }
143       if (*l4_proto == IP_PROTOCOL_TCP)
144         {
145           oflags |= VNET_BUFFER_OFFLOAD_F_TCP_CKSUM;
146           tcp_header_t *tcp =
147             (tcp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset);
148           *l4_hdr_sz = tcp_header_bytes (tcp);
149         }
150       else if (*l4_proto == IP_PROTOCOL_UDP)
151         {
152           oflags |= VNET_BUFFER_OFFLOAD_F_UDP_CKSUM;
153           *l4_hdr_sz = sizeof (udp_header_t);
154         }
155       if (oflags)
156         vnet_buffer_offload_flags_set (b0, oflags);
157     }
158 }
159
160 static_always_inline void
161 fill_gso_buffer_flags (vlib_buffer_t *b0, vnet_virtio_net_hdr_v1_t *hdr,
162                        u8 l4_proto, u8 l4_hdr_sz)
163 {
164   if (hdr->gso_type == VIRTIO_NET_HDR_GSO_TCPV4)
165     {
166       ASSERT (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM);
167       vnet_buffer2 (b0)->gso_size = hdr->gso_size;
168       vnet_buffer2 (b0)->gso_l4_hdr_sz = l4_hdr_sz;
169       b0->flags |= VNET_BUFFER_F_GSO | VNET_BUFFER_F_IS_IP4;
170     }
171   if (hdr->gso_type == VIRTIO_NET_HDR_GSO_TCPV6)
172     {
173       ASSERT (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM);
174       vnet_buffer2 (b0)->gso_size = hdr->gso_size;
175       vnet_buffer2 (b0)->gso_l4_hdr_sz = l4_hdr_sz;
176       b0->flags |= VNET_BUFFER_F_GSO | VNET_BUFFER_F_IS_IP6;
177     }
178 }
179
180 static_always_inline u16
181 virtio_n_left_to_process (vnet_virtio_vring_t *vring, const int packed)
182 {
183   if (packed)
184     return vring->desc_in_use;
185   else
186     return vring->used->idx - vring->last_used_idx;
187 }
188
189 static_always_inline u16
190 virtio_get_slot_id (vnet_virtio_vring_t *vring, const int packed, u16 last,
191                     u16 mask)
192 {
193   if (packed)
194     return vring->packed_desc[last].id;
195   else
196     return vring->used->ring[last & mask].id;
197 }
198
199 static_always_inline u16
200 virtio_get_len (vnet_virtio_vring_t *vring, const int packed, const int hdr_sz,
201                 u16 last, u16 mask)
202 {
203   if (packed)
204     return vring->packed_desc[last].len - hdr_sz;
205   else
206     return vring->used->ring[last & mask].len - hdr_sz;
207 }
208
209 #define increment_last(last, packed, vring)                                   \
210   do                                                                          \
211     {                                                                         \
212       last++;                                                                 \
213       if (packed && last >= vring->queue_size)                                \
214         {                                                                     \
215           last = 0;                                                           \
216           vring->used_wrap_counter ^= 1;                                      \
217         }                                                                     \
218     }                                                                         \
219   while (0)
220
221 static_always_inline void
222 virtio_device_input_ethernet (vlib_main_t *vm, vlib_node_runtime_t *node,
223                               const u32 next_index, const u32 sw_if_index,
224                               const u32 hw_if_index)
225 {
226   vlib_next_frame_t *nf;
227   vlib_frame_t *f;
228   ethernet_input_frame_t *ef;
229
230   if (PREDICT_FALSE (VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT != next_index))
231     return;
232
233   nf = vlib_node_runtime_get_next_frame (
234     vm, node, VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT);
235   f = vlib_get_frame (vm, nf->frame);
236   f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
237
238   ef = vlib_frame_scalar_args (f);
239   ef->sw_if_index = sw_if_index;
240   ef->hw_if_index = hw_if_index;
241   vlib_frame_no_append (f);
242 }
243
244 static_always_inline uword
245 virtio_device_input_gso_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
246                                 vlib_frame_t *frame, virtio_if_t *vif,
247                                 vnet_virtio_vring_t *vring,
248                                 virtio_if_type_t type, int gso_enabled,
249                                 int checksum_offload_enabled, int packed)
250 {
251   vnet_main_t *vnm = vnet_get_main ();
252   u32 thread_index = vm->thread_index;
253   uword n_trace = vlib_get_trace_count (vm, node);
254   u32 next_index;
255   const int hdr_sz = vif->virtio_net_hdr_sz;
256   u32 *to_next = 0;
257   u32 n_rx_packets = 0;
258   u32 n_rx_bytes = 0;
259   u16 mask = vring->queue_size - 1;
260   u16 last = vring->last_used_idx;
261   u16 n_left = virtio_n_left_to_process (vring, packed);
262   vlib_buffer_t bt = {};
263
264   if (n_left == 0)
265     return 0;
266
267   if (type == VIRTIO_IF_TYPE_TUN)
268     {
269       next_index = VNET_DEVICE_INPUT_NEXT_IP4_INPUT;
270     }
271   else
272     {
273       next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
274       if (PREDICT_FALSE (vif->per_interface_next_index != ~0))
275         next_index = vif->per_interface_next_index;
276
277       /* only for l2, redirect if feature path enabled */
278       vnet_feature_start_device_input (vif->sw_if_index, &next_index, &bt);
279     }
280
281   while (n_left)
282     {
283       u32 n_left_to_next;
284       u32 next0 = next_index;
285
286       vlib_get_new_next_frame (vm, node, next_index, to_next, n_left_to_next);
287
288       while (n_left && n_left_to_next)
289         {
290           if (packed)
291             {
292               vnet_virtio_vring_packed_desc_t *d = &vring->packed_desc[last];
293               u16 flags = d->flags;
294               if ((flags & VRING_DESC_F_AVAIL) !=
295                   (vring->used_wrap_counter << 7)
296                   || (flags & VRING_DESC_F_USED) !=
297                   (vring->used_wrap_counter << 15))
298                 {
299                   n_left = 0;
300                   break;
301                 }
302             }
303           u8 l4_proto = 0, l4_hdr_sz = 0;
304           u16 num_buffers = 1;
305           vnet_virtio_net_hdr_v1_t *hdr;
306           u16 slot = virtio_get_slot_id (vring, packed, last, mask);
307           u16 len = virtio_get_len (vring, packed, hdr_sz, last, mask);
308           u32 bi0 = vring->buffers[slot];
309           vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
310           hdr = vlib_buffer_get_current (b0);
311           if (hdr_sz == sizeof (vnet_virtio_net_hdr_v1_t))
312             num_buffers = hdr->num_buffers;
313
314           b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
315           b0->current_data = 0;
316           b0->current_length = len;
317
318           if (checksum_offload_enabled)
319             virtio_needs_csum (b0, hdr, &l4_proto, &l4_hdr_sz, type);
320
321           if (gso_enabled)
322             fill_gso_buffer_flags (b0, hdr, l4_proto, l4_hdr_sz);
323
324           vnet_buffer (b0)->sw_if_index[VLIB_RX] = vif->sw_if_index;
325           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
326
327           /* if multisegment packet */
328           if (PREDICT_FALSE (num_buffers > 1))
329             {
330               vlib_buffer_t *pb, *cb;
331               pb = b0;
332               b0->total_length_not_including_first_buffer = 0;
333               while (num_buffers > 1)
334                 {
335                   increment_last (last, packed, vring);
336                   u16 cslot = virtio_get_slot_id (vring, packed, last, mask);
337                   /* hdr size is 0 after 1st packet in chain buffers */
338                   u16 clen = virtio_get_len (vring, packed, 0, last, mask);
339                   u32 cbi = vring->buffers[cslot];
340                   cb = vlib_get_buffer (vm, cbi);
341
342                   /* current buffer */
343                   cb->current_length = clen;
344
345                   /* previous buffer */
346                   pb->next_buffer = cbi;
347                   pb->flags |= VLIB_BUFFER_NEXT_PRESENT;
348
349                   /* first buffer */
350                   b0->total_length_not_including_first_buffer += clen;
351
352                   pb = cb;
353                   vring->desc_in_use--;
354                   num_buffers--;
355                   n_left--;
356                 }
357               len += b0->total_length_not_including_first_buffer;
358             }
359
360           if (type == VIRTIO_IF_TYPE_TUN)
361             {
362               switch (b0->data[0] & 0xf0)
363                 {
364                 case 0x40:
365                   next0 = VNET_DEVICE_INPUT_NEXT_IP4_INPUT;
366                   break;
367                 case 0x60:
368                   next0 = VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
369                   break;
370                 default:
371                   next0 = VNET_DEVICE_INPUT_NEXT_DROP;
372                   break;
373                 }
374
375               if (PREDICT_FALSE (vif->per_interface_next_index != ~0))
376                 next0 = vif->per_interface_next_index;
377             }
378           else
379             {
380               /* copy feature arc data from template */
381               b0->current_config_index = bt.current_config_index;
382               vnet_buffer (b0)->feature_arc_index =
383                 vnet_buffer (&bt)->feature_arc_index;
384             }
385
386           /* trace */
387           if (PREDICT_FALSE (n_trace > 0 && vlib_trace_buffer (vm, node, next0, b0,     /* follow_chain */
388                                                                1)))
389             {
390               virtio_input_trace_t *tr;
391               vlib_set_trace_count (vm, node, --n_trace);
392               tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
393               tr->next_index = next0;
394               tr->hw_if_index = vif->hw_if_index;
395               tr->len = len;
396               clib_memcpy_fast (&tr->hdr, hdr, (hdr_sz == 12) ? 12 : 10);
397             }
398
399           /* enqueue buffer */
400           to_next[0] = bi0;
401           vring->desc_in_use--;
402           to_next += 1;
403           n_left_to_next--;
404           n_left--;
405           increment_last (last, packed, vring);
406
407           /* only tun interfaces may have different next index */
408           if (type == VIRTIO_IF_TYPE_TUN)
409             vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
410                                              n_left_to_next, bi0, next0);
411
412           /* next packet */
413           n_rx_packets++;
414           n_rx_bytes += len;
415         }
416       virtio_device_input_ethernet (vm, node, next_index, vif->sw_if_index,
417                                     vif->hw_if_index);
418       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
419     }
420   vring->last_used_idx = last;
421
422   vring->total_packets += n_rx_packets;
423   vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters
424                                    + VNET_INTERFACE_COUNTER_RX, thread_index,
425                                    vif->sw_if_index, n_rx_packets,
426                                    n_rx_bytes);
427
428   return n_rx_packets;
429 }
430
431 static_always_inline uword
432 virtio_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
433                             vlib_frame_t * frame, virtio_if_t * vif, u16 qid,
434                             virtio_if_type_t type)
435 {
436   vnet_virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, qid);
437   const int hdr_sz = vif->virtio_net_hdr_sz;
438   uword rv;
439
440   if (vif->is_packed)
441     {
442       if (vif->gso_enabled)
443         rv =
444           virtio_device_input_gso_inline (vm, node, frame, vif, vring, type,
445                                           1, 1, 1);
446       else if (vif->csum_offload_enabled)
447         rv =
448           virtio_device_input_gso_inline (vm, node, frame, vif, vring, type,
449                                           0, 1, 1);
450       else
451         rv =
452           virtio_device_input_gso_inline (vm, node, frame, vif, vring, type,
453                                           0, 0, 1);
454
455       virtio_refill_vring_packed (vm, vif, type, vring, hdr_sz,
456                                   node->node_index);
457     }
458   else
459     {
460       if (vif->gso_enabled)
461         rv =
462           virtio_device_input_gso_inline (vm, node, frame, vif, vring, type,
463                                           1, 1, 0);
464       else if (vif->csum_offload_enabled)
465         rv =
466           virtio_device_input_gso_inline (vm, node, frame, vif, vring, type,
467                                           0, 1, 0);
468       else
469         rv =
470           virtio_device_input_gso_inline (vm, node, frame, vif, vring, type,
471                                           0, 0, 0);
472
473       virtio_refill_vring_split (vm, vif, type, vring, hdr_sz,
474                                  node->node_index);
475     }
476   return rv;
477 }
478
479 VLIB_NODE_FN (virtio_input_node) (vlib_main_t * vm,
480                                   vlib_node_runtime_t * node,
481                                   vlib_frame_t * frame)
482 {
483   u32 n_rx = 0;
484   virtio_main_t *vim = &virtio_main;
485   vnet_hw_if_rxq_poll_vector_t *p,
486     *pv = vnet_hw_if_get_rxq_poll_vector (vm, node);
487
488   vec_foreach (p, pv)
489     {
490       virtio_if_t *vif;
491       vif = vec_elt_at_index (vim->interfaces, p->dev_instance);
492       if (vif->flags & VIRTIO_IF_FLAG_ADMIN_UP)
493         {
494           if (vif->type == VIRTIO_IF_TYPE_TAP)
495             n_rx += virtio_device_input_inline (
496               vm, node, frame, vif, p->queue_id, VIRTIO_IF_TYPE_TAP);
497           else if (vif->type == VIRTIO_IF_TYPE_PCI)
498             n_rx += virtio_device_input_inline (
499               vm, node, frame, vif, p->queue_id, VIRTIO_IF_TYPE_PCI);
500           else if (vif->type == VIRTIO_IF_TYPE_TUN)
501             n_rx += virtio_device_input_inline (
502               vm, node, frame, vif, p->queue_id, VIRTIO_IF_TYPE_TUN);
503         }
504     }
505
506   return n_rx;
507 }
508
509 /* *INDENT-OFF* */
510 VLIB_REGISTER_NODE (virtio_input_node) = {
511   .name = "virtio-input",
512   .sibling_of = "device-input",
513   .format_trace = format_virtio_input_trace,
514   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
515   .type = VLIB_NODE_TYPE_INPUT,
516   .state = VLIB_NODE_STATE_INTERRUPT,
517   .n_errors = VIRTIO_INPUT_N_ERROR,
518   .error_strings = virtio_input_error_strings,
519 };
520 /* *INDENT-ON* */
521
522 /*
523  * fd.io coding-style-patch-verification: ON
524  *
525  * Local Variables:
526  * eval: (c-set-style "gnu")
527  * End:
528  */