memif: add private header size field
[vpp.git] / src / plugins / memif / 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 #define _GNU_SOURCE
19 #include <stdint.h>
20 #include <net/if.h>
21 #include <sys/ioctl.h>
22 #include <sys/uio.h>
23
24 #include <vlib/vlib.h>
25 #include <vlib/unix/unix.h>
26 #include <vnet/ethernet/ethernet.h>
27 #include <vnet/devices/devices.h>
28 #include <vnet/feature/feature.h>
29
30 #include <memif/memif.h>
31 #include <memif/private.h>
32
33 #define foreach_memif_input_error \
34   _(BUFFER_ALLOC_FAIL, "buffer allocation failed")              \
35   _(NOT_IP, "not ip packet")
36
37 typedef enum
38 {
39 #define _(f,s) MEMIF_INPUT_ERROR_##f,
40   foreach_memif_input_error
41 #undef _
42     MEMIF_INPUT_N_ERROR,
43 } memif_input_error_t;
44
45 static __clib_unused char *memif_input_error_strings[] = {
46 #define _(n,s) s,
47   foreach_memif_input_error
48 #undef _
49 };
50
51 typedef struct
52 {
53   u32 next_index;
54   u32 hw_if_index;
55   u16 ring;
56 } memif_input_trace_t;
57
58 static __clib_unused u8 *
59 format_memif_input_trace (u8 * s, va_list * args)
60 {
61   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
62   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
63   memif_input_trace_t *t = va_arg (*args, memif_input_trace_t *);
64   u32 indent = format_get_indent (s);
65
66   s = format (s, "memif: hw_if_index %d next-index %d",
67               t->hw_if_index, t->next_index);
68   s = format (s, "\n%Uslot: ring %u", format_white_space, indent + 2,
69               t->ring);
70   return s;
71 }
72
73 static_always_inline u32
74 memif_next_from_ip_hdr (vlib_node_runtime_t * node, vlib_buffer_t * b)
75 {
76   u8 *ptr = vlib_buffer_get_current (b);
77   u8 v = *ptr & 0xf0;
78
79   if (PREDICT_TRUE (v == 0x40))
80     return VNET_DEVICE_INPUT_NEXT_IP4_NCS_INPUT;
81   else if (PREDICT_TRUE (v == 0x60))
82     return VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
83
84   b->error = node->errors[MEMIF_INPUT_ERROR_NOT_IP];
85   return VNET_DEVICE_INPUT_NEXT_DROP;
86 }
87
88 static_always_inline void
89 memif_trace_buffer (vlib_main_t * vm, vlib_node_runtime_t * node,
90                     memif_if_t * mif, vlib_buffer_t * b, u32 next, u16 qid,
91                     uword * n_tracep)
92 {
93   VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b);
94
95   if (PREDICT_TRUE (b != 0))
96     {
97       memif_input_trace_t *tr;
98       vlib_trace_buffer (vm, node, next, b, /* follow_chain */ 0);
99       vlib_set_trace_count (vm, node, --(*n_tracep));
100       tr = vlib_add_trace (vm, node, b, sizeof (*tr));
101       tr->next_index = next;
102       tr->hw_if_index = mif->hw_if_index;
103       tr->ring = qid;
104     }
105 }
106
107 static_always_inline void
108 memif_add_copy_op (memif_per_thread_data_t * ptd, void *data, u32 len,
109                    u16 buffer_offset, u16 buffer_vec_index)
110 {
111   memif_copy_op_t *co;
112   vec_add2_aligned (ptd->copy_ops, co, 1, CLIB_CACHE_LINE_BYTES);
113   co->data = data;
114   co->data_len = len;
115   co->buffer_offset = buffer_offset;
116   co->buffer_vec_index = buffer_vec_index;
117 }
118
119 static_always_inline void
120 memif_add_to_chain (vlib_main_t * vm, vlib_buffer_t * b, u32 * buffers,
121                     u32 buffer_size)
122 {
123   vlib_buffer_t *seg = b;
124   i32 bytes_left = b->current_length - buffer_size + b->current_data;
125
126   if (PREDICT_TRUE (bytes_left <= 0))
127     return;
128
129   b->current_length -= bytes_left;
130   b->total_length_not_including_first_buffer = bytes_left;
131
132   while (bytes_left)
133     {
134       seg->flags |= VLIB_BUFFER_NEXT_PRESENT;
135       seg->next_buffer = buffers[0];
136       seg = vlib_get_buffer (vm, buffers[0]);
137       buffers++;
138       seg->current_data = 0;
139       seg->current_length = clib_min (buffer_size, bytes_left);
140       bytes_left -= seg->current_length;
141     }
142 }
143
144 static_always_inline uword
145 memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
146                            vlib_frame_t * frame, memif_if_t * mif,
147                            memif_ring_type_t type, u16 qid,
148                            memif_interface_mode_t mode)
149 {
150   vnet_main_t *vnm = vnet_get_main ();
151   memif_main_t *mm = &memif_main;
152   memif_ring_t *ring;
153   memif_queue_t *mq;
154   u16 buffer_size = VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES;
155   u32 next_index;
156   uword n_trace = vlib_get_trace_count (vm, node);
157   u32 n_rx_packets = 0, n_rx_bytes = 0;
158   u32 n_left, *to_next = 0;
159   u32 bi0, bi1, bi2, bi3;
160   vlib_buffer_t *b0, *b1, *b2, *b3;
161   u32 thread_index = vlib_get_thread_index ();
162   memif_per_thread_data_t *ptd = vec_elt_at_index (mm->per_thread_data,
163                                                    thread_index);
164   vlib_buffer_t *bt = &ptd->buffer_template;
165   u16 cur_slot, last_slot, ring_size, n_slots, mask;
166   i16 start_offset;
167   u16 n_buffers = 0, n_alloc;
168   memif_copy_op_t *co;
169   memif_packet_op_t *po;
170   memif_region_index_t last_region = ~0;
171   void *last_region_shm = 0;
172
173   mq = vec_elt_at_index (mif->rx_queues, qid);
174   ring = mq->ring;
175   ring_size = 1 << mq->log2_ring_size;
176   mask = ring_size - 1;
177
178   next_index = (mode == MEMIF_INTERFACE_MODE_IP) ?
179     VNET_DEVICE_INPUT_NEXT_IP6_INPUT : VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
180
181   /* asume that somebody will want to add ethernet header on the packet
182      so start with IP header at offset 14 */
183   start_offset = (mode == MEMIF_INTERFACE_MODE_IP) ? 14 : 0;
184
185
186   /* for S2M rings, we are consumers of packet buffers, and for M2S rings we
187      are producers of empty buffers */
188   cur_slot = (type == MEMIF_RING_S2M) ? mq->last_head : mq->last_tail;
189   last_slot = (type == MEMIF_RING_S2M) ? ring->head : ring->tail;
190   if (cur_slot == last_slot)
191     goto refill;
192   n_slots = last_slot - cur_slot;
193
194   /* construct copy and packet vector out of ring slots */
195   while (n_slots && n_rx_packets < MEMIF_RX_VECTOR_SZ)
196     {
197       u32 dst_off, src_off, n_bytes_left;
198       u16 s0;
199       memif_desc_t *d0;
200       void *mb0;
201       po = ptd->packet_ops + n_rx_packets;
202       n_rx_packets++;
203       po->first_buffer_vec_index = n_buffers++;
204       po->packet_len = 0;
205       src_off = 0;
206       dst_off = start_offset;
207
208     next_slot:
209       CLIB_PREFETCH (&ring->desc[(cur_slot + 8) & mask],
210                      CLIB_CACHE_LINE_BYTES, LOAD);
211       s0 = cur_slot & mask;
212       d0 = &ring->desc[s0];
213       n_bytes_left = d0->length;
214
215       /* slave resets buffer length,
216        * so it can produce full size buffer for master
217        */
218       if (type == MEMIF_RING_M2S)
219         d0->length = mif->run.buffer_size;
220
221       po->packet_len += n_bytes_left;
222       if (PREDICT_FALSE (last_region != d0->region))
223         {
224           last_region_shm = mif->regions[d0->region].shm;
225           last_region = d0->region;
226         }
227       mb0 = last_region_shm + d0->offset;
228
229       do
230         {
231           u32 dst_free = buffer_size - dst_off;
232           if (dst_free == 0)
233             {
234               dst_off = 0;
235               dst_free = buffer_size;
236               n_buffers++;
237             }
238           u32 bytes_to_copy = clib_min (dst_free, n_bytes_left);
239           memif_add_copy_op (ptd, mb0 + src_off, bytes_to_copy, dst_off,
240                              n_buffers - 1);
241           n_bytes_left -= bytes_to_copy;
242           src_off += bytes_to_copy;
243           dst_off += bytes_to_copy;
244         }
245       while (PREDICT_FALSE (n_bytes_left));
246
247       cur_slot++;
248       n_slots--;
249       if ((d0->flags & MEMIF_DESC_FLAG_NEXT) && n_slots)
250         {
251           src_off = 0;
252           goto next_slot;
253         }
254     }
255
256   /* allocate free buffers */
257   vec_validate_aligned (ptd->buffers, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
258   n_alloc = vlib_buffer_alloc (vm, ptd->buffers, n_buffers);
259   if (PREDICT_FALSE (n_alloc != n_buffers))
260     {
261       if (n_alloc)
262         vlib_buffer_free (vm, ptd->buffers, n_alloc);
263       vlib_error_count (vm, node->node_index,
264                         MEMIF_INPUT_ERROR_BUFFER_ALLOC_FAIL, 1);
265       goto refill;
266     }
267
268   /* copy data */
269   n_left = vec_len (ptd->copy_ops);
270   co = ptd->copy_ops;
271   while (n_left >= 8)
272     {
273       CLIB_PREFETCH (co[4].data, CLIB_CACHE_LINE_BYTES, LOAD);
274       CLIB_PREFETCH (co[5].data, CLIB_CACHE_LINE_BYTES, LOAD);
275       CLIB_PREFETCH (co[6].data, CLIB_CACHE_LINE_BYTES, LOAD);
276       CLIB_PREFETCH (co[7].data, CLIB_CACHE_LINE_BYTES, LOAD);
277
278       b0 = vlib_get_buffer (vm, ptd->buffers[co[0].buffer_vec_index]);
279       b1 = vlib_get_buffer (vm, ptd->buffers[co[1].buffer_vec_index]);
280       b2 = vlib_get_buffer (vm, ptd->buffers[co[2].buffer_vec_index]);
281       b3 = vlib_get_buffer (vm, ptd->buffers[co[3].buffer_vec_index]);
282
283       clib_memcpy (b0->data + co[0].buffer_offset, co[0].data,
284                    co[0].data_len);
285       clib_memcpy (b1->data + co[1].buffer_offset, co[1].data,
286                    co[1].data_len);
287       clib_memcpy (b2->data + co[2].buffer_offset, co[2].data,
288                    co[2].data_len);
289       clib_memcpy (b3->data + co[3].buffer_offset, co[3].data,
290                    co[3].data_len);
291
292       co += 4;
293       n_left -= 4;
294     }
295   while (n_left)
296     {
297       b0 = vlib_get_buffer (vm, ptd->buffers[co[0].buffer_vec_index]);
298       clib_memcpy (b0->data + co[0].buffer_offset, co[0].data,
299                    co[0].data_len);
300       co += 1;
301       n_left -= 1;
302     }
303
304   /* release slots from the ring */
305   if (type == MEMIF_RING_S2M)
306     {
307       CLIB_MEMORY_STORE_BARRIER ();
308       ring->tail = mq->last_head = cur_slot;
309     }
310   else
311     {
312       mq->last_tail = cur_slot;
313     }
314
315   u32 n_from = n_rx_packets;
316   po = ptd->packet_ops;
317
318   vnet_buffer (bt)->sw_if_index[VLIB_RX] = mif->sw_if_index;
319   bt->current_data = start_offset;
320
321   while (n_from)
322     {
323       u32 n_left_to_next;
324       u32 next0, next1, next2, next3;
325
326       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
327       while (n_from >= 8 && n_left_to_next >= 4)
328         {
329           b0 = vlib_get_buffer (vm, po[4].first_buffer_vec_index);
330           b1 = vlib_get_buffer (vm, po[5].first_buffer_vec_index);
331           b2 = vlib_get_buffer (vm, po[6].first_buffer_vec_index);
332           b3 = vlib_get_buffer (vm, po[7].first_buffer_vec_index);
333           vlib_prefetch_buffer_header (b0, STORE);
334           vlib_prefetch_buffer_header (b1, STORE);
335           vlib_prefetch_buffer_header (b2, STORE);
336           vlib_prefetch_buffer_header (b3, STORE);
337
338           /* enqueue buffer */
339           u32 fbvi0 = po[0].first_buffer_vec_index;
340           u32 fbvi1 = po[1].first_buffer_vec_index;
341           u32 fbvi2 = po[2].first_buffer_vec_index;
342           u32 fbvi3 = po[3].first_buffer_vec_index;
343           to_next[0] = bi0 = ptd->buffers[fbvi0];
344           to_next[1] = bi1 = ptd->buffers[fbvi1];
345           to_next[2] = bi2 = ptd->buffers[fbvi2];
346           to_next[3] = bi3 = ptd->buffers[fbvi3];
347           to_next += 4;
348           n_left_to_next -= 4;
349
350           b0 = vlib_get_buffer (vm, bi0);
351           b1 = vlib_get_buffer (vm, bi1);
352           b2 = vlib_get_buffer (vm, bi2);
353           b3 = vlib_get_buffer (vm, bi3);
354
355           clib_memcpy64_x4 (b0, b1, b2, b3, bt);
356
357           b0->current_length = po[0].packet_len;
358           b1->current_length = po[1].packet_len;
359           b2->current_length = po[2].packet_len;
360           b3->current_length = po[3].packet_len;
361
362           memif_add_to_chain (vm, b0, ptd->buffers + fbvi0 + 1, buffer_size);
363           memif_add_to_chain (vm, b1, ptd->buffers + fbvi1 + 1, buffer_size);
364           memif_add_to_chain (vm, b2, ptd->buffers + fbvi2 + 1, buffer_size);
365           memif_add_to_chain (vm, b3, ptd->buffers + fbvi3 + 1, buffer_size);
366
367           if (mode == MEMIF_INTERFACE_MODE_IP)
368             {
369               next0 = memif_next_from_ip_hdr (node, b0);
370               next1 = memif_next_from_ip_hdr (node, b1);
371               next2 = memif_next_from_ip_hdr (node, b2);
372               next3 = memif_next_from_ip_hdr (node, b3);
373             }
374           else if (mode == MEMIF_INTERFACE_MODE_ETHERNET)
375             {
376               if (PREDICT_FALSE (mif->per_interface_next_index != ~0))
377                 {
378                   next0 = mif->per_interface_next_index;
379                   next1 = mif->per_interface_next_index;
380                   next2 = mif->per_interface_next_index;
381                   next3 = mif->per_interface_next_index;
382                 }
383               else
384                 {
385                   next0 = next1 = next2 = next3 = next_index;
386                   /* redirect if feature path enabled */
387                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
388                                                       &next0, b0);
389                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
390                                                       &next1, b1);
391                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
392                                                       &next2, b2);
393                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
394                                                       &next3, b3);
395                 }
396             }
397
398           /* trace */
399           if (PREDICT_FALSE (n_trace > 0))
400             {
401               memif_trace_buffer (vm, node, mif, b0, next0, qid, &n_trace);
402               if (PREDICT_FALSE (n_trace > 0))
403                 memif_trace_buffer (vm, node, mif, b1, next1, qid, &n_trace);
404               if (PREDICT_FALSE (n_trace > 0))
405                 memif_trace_buffer (vm, node, mif, b2, next2, qid, &n_trace);
406               if (PREDICT_FALSE (n_trace > 0))
407                 memif_trace_buffer (vm, node, mif, b3, next3, qid, &n_trace);
408             }
409
410           /* enqueue */
411           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
412                                            n_left_to_next, bi0, bi1, bi2, bi3,
413                                            next0, next1, next2, next3);
414
415           /* next */
416           n_from -= 4;
417           po += 4;
418         }
419       while (n_from && n_left_to_next)
420         {
421           /* enqueue buffer */
422           u32 fbvi0 = po->first_buffer_vec_index;
423           to_next[0] = bi0 = ptd->buffers[fbvi0];
424           to_next += 1;
425           n_left_to_next--;
426
427           b0 = vlib_get_buffer (vm, bi0);
428           clib_memcpy (b0, bt, 64);
429           b0->current_length = po->packet_len;
430
431           memif_add_to_chain (vm, b0, ptd->buffers + fbvi0 + 1, buffer_size);
432
433           if (mode == MEMIF_INTERFACE_MODE_IP)
434             {
435               next0 = memif_next_from_ip_hdr (node, b0);
436             }
437           else if (mode == MEMIF_INTERFACE_MODE_ETHERNET)
438             {
439               if (PREDICT_FALSE (mif->per_interface_next_index != ~0))
440                 next0 = mif->per_interface_next_index;
441               else
442                 {
443                   next0 = next_index;
444                   /* redirect if feature path enabled */
445                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
446                                                       &next0, b0);
447                 }
448
449             }
450
451           /* trace */
452           if (PREDICT_FALSE (n_trace > 0))
453             memif_trace_buffer (vm, node, mif, b0, next0, qid, &n_trace);
454
455           /* enqueue */
456           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
457                                            n_left_to_next, bi0, next0);
458
459           /* next */
460           n_from--;
461           po++;
462         }
463       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
464     }
465
466   vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters
467                                    + VNET_INTERFACE_COUNTER_RX, thread_index,
468                                    mif->hw_if_index, n_rx_packets,
469                                    n_rx_bytes);
470
471   /* refill ring with empty buffers */
472 refill:
473   vec_reset_length (ptd->buffers);
474   vec_reset_length (ptd->copy_ops);
475
476   if (type == MEMIF_RING_M2S)
477     {
478       u16 head = ring->head;
479       n_slots = ring_size - head + mq->last_tail;
480
481       while (n_slots--)
482         {
483           u16 s = head++ & mask;
484           memif_desc_t *d = &ring->desc[s];
485           d->length = mif->run.buffer_size;
486         }
487
488       CLIB_MEMORY_STORE_BARRIER ();
489       ring->head = head;
490     }
491
492   return n_rx_packets;
493 }
494
495 uword
496 CLIB_MULTIARCH_FN (memif_input_fn) (vlib_main_t * vm,
497                                     vlib_node_runtime_t * node,
498                                     vlib_frame_t * frame)
499 {
500   u32 n_rx = 0;
501   memif_main_t *mm = &memif_main;
502   vnet_device_input_runtime_t *rt = (void *) node->runtime_data;
503   vnet_device_and_queue_t *dq;
504
505   foreach_device_and_queue (dq, rt->devices_and_queues)
506   {
507     memif_if_t *mif;
508     mif = vec_elt_at_index (mm->interfaces, dq->dev_instance);
509     if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) &&
510         (mif->flags & MEMIF_IF_FLAG_CONNECTED))
511       {
512         if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
513           {
514             if (mif->mode == MEMIF_INTERFACE_MODE_IP)
515               n_rx += memif_device_input_inline (vm, node, frame, mif,
516                                                  MEMIF_RING_M2S, dq->queue_id,
517                                                  MEMIF_INTERFACE_MODE_IP);
518             else
519               n_rx += memif_device_input_inline (vm, node, frame, mif,
520                                                  MEMIF_RING_M2S, dq->queue_id,
521                                                  MEMIF_INTERFACE_MODE_ETHERNET);
522           }
523         else
524           {
525             if (mif->mode == MEMIF_INTERFACE_MODE_IP)
526               n_rx += memif_device_input_inline (vm, node, frame, mif,
527                                                  MEMIF_RING_S2M, dq->queue_id,
528                                                  MEMIF_INTERFACE_MODE_IP);
529             else
530               n_rx += memif_device_input_inline (vm, node, frame, mif,
531                                                  MEMIF_RING_S2M, dq->queue_id,
532                                                  MEMIF_INTERFACE_MODE_ETHERNET);
533           }
534       }
535   }
536
537   return n_rx;
538 }
539
540 #ifndef CLIB_MULTIARCH_VARIANT
541 /* *INDENT-OFF* */
542 VLIB_REGISTER_NODE (memif_input_node) = {
543   .function = memif_input_fn,
544   .name = "memif-input",
545   .sibling_of = "device-input",
546   .format_trace = format_memif_input_trace,
547   .type = VLIB_NODE_TYPE_INPUT,
548   .state = VLIB_NODE_STATE_INTERRUPT,
549   .n_errors = MEMIF_INPUT_N_ERROR,
550   .error_strings = memif_input_error_strings,
551 };
552
553 vlib_node_function_t __clib_weak memif_input_fn_avx512;
554 vlib_node_function_t __clib_weak memif_input_fn_avx2;
555
556 #if __x86_64__
557 static void __clib_constructor
558 memif_input_multiarch_select (void)
559 {
560   if (memif_input_fn_avx512 && clib_cpu_supports_avx512f ())
561     memif_input_node.function = memif_input_fn_avx512;
562   else if (memif_input_fn_avx2 && clib_cpu_supports_avx2 ())
563     memif_input_node.function = memif_input_fn_avx2;
564 }
565 #endif
566 #endif
567
568 /* *INDENT-ON* */
569
570
571 /*
572  * fd.io coding-style-patch-verification: ON
573  *
574  * Local Variables:
575  * eval: (c-set-style "gnu")
576  * End:
577  */