6afd20e06fefce390b40414eed76066244923371
[vpp.git] / src / plugins / dpdk / buffer.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * buffer.c: allocate/free network buffers.
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 /**
41  * @file
42  *
43  * Allocate/free network buffers.
44  */
45
46 #include <unistd.h>
47 #include <linux/vfio.h>
48 #include <sys/ioctl.h>
49
50 #include <rte_config.h>
51
52 #include <rte_common.h>
53 #include <rte_log.h>
54 #include <rte_memory.h>
55 #include <rte_memzone.h>
56 #include <rte_tailq.h>
57 #include <rte_eal.h>
58 #include <rte_per_lcore.h>
59 #include <rte_launch.h>
60 #include <rte_atomic.h>
61 #include <rte_cycles.h>
62 #include <rte_prefetch.h>
63 #include <rte_lcore.h>
64 #include <rte_per_lcore.h>
65 #include <rte_branch_prediction.h>
66 #include <rte_interrupts.h>
67 #include <rte_pci.h>
68 #include <rte_random.h>
69 #include <rte_debug.h>
70 #include <rte_ether.h>
71 #include <rte_ethdev.h>
72 #include <rte_ring.h>
73 #include <rte_mempool.h>
74 #include <rte_mbuf.h>
75 #include <rte_version.h>
76
77 #include <vlib/vlib.h>
78 #include <vlib/unix/unix.h>
79 #include <vlib/pci/pci.h>
80 #include <vlib/linux/vfio.h>
81 #include <vnet/vnet.h>
82 #include <dpdk/device/dpdk.h>
83 #include <dpdk/device/dpdk_priv.h>
84
85 STATIC_ASSERT (VLIB_BUFFER_PRE_DATA_SIZE == RTE_PKTMBUF_HEADROOM,
86                "VLIB_BUFFER_PRE_DATA_SIZE must be equal to RTE_PKTMBUF_HEADROOM");
87
88 typedef struct
89 {
90   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
91   struct rte_mbuf **mbuf_alloc_list;
92 } dpdk_buffer_per_thread_data;
93
94 typedef struct
95 {
96   int vfio_container_fd;
97   dpdk_buffer_per_thread_data *ptd;
98 } dpdk_buffer_main_t;
99
100 dpdk_buffer_main_t dpdk_buffer_main;
101
102 static_always_inline void
103 dpdk_rte_pktmbuf_free (vlib_main_t * vm, u32 thread_index, vlib_buffer_t * b,
104                        int maybe_next)
105 {
106   struct rte_mbuf *mb;
107   u32 next, flags;
108
109 next:
110   flags = b->flags;
111   next = b->next_buffer;
112   mb = rte_mbuf_from_vlib_buffer (b);
113
114   if (PREDICT_FALSE (b->n_add_refs))
115     {
116       rte_mbuf_refcnt_update (mb, b->n_add_refs);
117       b->n_add_refs = 0;
118     }
119
120   if ((mb = rte_pktmbuf_prefree_seg (mb)))
121     rte_mempool_put (mb->pool, mb);
122
123   if (maybe_next && (flags & VLIB_BUFFER_NEXT_PRESENT))
124     {
125       b = vlib_get_buffer (vm, next);
126       goto next;
127     }
128 }
129
130 #ifndef CLIB_MARCH_VARIANT
131 static void
132 del_free_list (vlib_main_t * vm, vlib_buffer_free_list_t * f)
133 {
134   u32 i;
135   vlib_buffer_t *b;
136   u32 thread_index = vlib_get_thread_index ();
137
138   for (i = 0; i < vec_len (f->buffers); i++)
139     {
140       b = vlib_get_buffer (vm, f->buffers[i]);
141       dpdk_rte_pktmbuf_free (vm, thread_index, b, 1);
142     }
143
144   vec_free (f->name);
145   vec_free (f->buffers);
146   /* Poison it. */
147   memset (f, 0xab, sizeof (f[0]));
148 }
149
150 /* Add buffer free list. */
151 static void
152 dpdk_buffer_delete_free_list (vlib_main_t * vm,
153                               vlib_buffer_free_list_index_t free_list_index)
154 {
155   vlib_buffer_free_list_t *f;
156   int i;
157
158   ASSERT (vlib_get_thread_index () == 0);
159
160   f = vlib_buffer_get_free_list (vm, free_list_index);
161
162   del_free_list (vm, f);
163
164   pool_put (vm->buffer_free_list_pool, f);
165
166   for (i = 1; i < vec_len (vlib_mains); i++)
167     {
168       vlib_main_t *wvm = vlib_mains[i];
169       f = vlib_buffer_get_free_list (vlib_mains[i], free_list_index);
170       del_free_list (wvm, f);
171       pool_put (wvm->buffer_free_list_pool, f);
172     }
173 }
174 #endif
175
176 /* Make sure free list has at least given number of free buffers. */
177 uword
178 CLIB_MULTIARCH_FN (dpdk_buffer_fill_free_list) (vlib_main_t * vm,
179                                                 vlib_buffer_free_list_t * fl,
180                                                 uword min_free_buffers)
181 {
182   dpdk_main_t *dm = &dpdk_main;
183   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
184   struct rte_mbuf **mb;
185   uword n_left, first;
186   word n_alloc;
187   unsigned socket_id = rte_socket_id ();
188   u32 thread_index = vlib_get_thread_index ();
189   dpdk_buffer_per_thread_data *d = vec_elt_at_index (dbm->ptd, thread_index);
190   struct rte_mempool *rmp = dm->pktmbuf_pools[socket_id];
191   dpdk_mempool_private_t *privp = rte_mempool_get_priv (rmp);
192   vlib_buffer_t bt;
193   u32 *bi;
194
195   /* Too early? */
196   if (PREDICT_FALSE (rmp == 0))
197     return 0;
198
199   /* Already have enough free buffers on free list? */
200   n_alloc = min_free_buffers - vec_len (fl->buffers);
201   if (n_alloc <= 0)
202     return min_free_buffers;
203
204   /* Always allocate round number of buffers. */
205   n_alloc = round_pow2 (n_alloc, CLIB_CACHE_LINE_BYTES / sizeof (u32));
206
207   /* Always allocate new buffers in reasonably large sized chunks. */
208   n_alloc = clib_max (n_alloc, fl->min_n_buffers_each_alloc);
209
210   vec_validate_aligned (d->mbuf_alloc_list, n_alloc - 1,
211                         CLIB_CACHE_LINE_BYTES);
212
213   if (rte_mempool_get_bulk (rmp, (void *) d->mbuf_alloc_list, n_alloc) < 0)
214     return 0;
215
216   memset (&bt, 0, sizeof (vlib_buffer_t));
217   vlib_buffer_init_for_free_list (&bt, fl);
218   bt.buffer_pool_index = privp->buffer_pool_index;
219
220   _vec_len (d->mbuf_alloc_list) = n_alloc;
221
222   first = vec_len (fl->buffers);
223   vec_resize_aligned (fl->buffers, n_alloc, CLIB_CACHE_LINE_BYTES);
224
225   n_left = n_alloc;
226   mb = d->mbuf_alloc_list;
227   bi = fl->buffers + first;
228
229   ASSERT (n_left % 8 == 0);
230
231   while (n_left >= 8)
232     {
233       if (PREDICT_FALSE (n_left < 24))
234         goto no_prefetch;
235
236       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf (mb[16]), STORE);
237       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf (mb[17]), STORE);
238       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf (mb[18]), STORE);
239       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf (mb[19]), STORE);
240       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf (mb[20]), STORE);
241       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf (mb[21]), STORE);
242       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf (mb[22]), STORE);
243       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf (mb[23]), STORE);
244
245     no_prefetch:
246       vlib_get_buffer_indices_with_offset (vm, (void **) mb, bi, 8,
247                                            sizeof (struct rte_mbuf));
248       clib_memcpy64_x4 (vlib_buffer_from_rte_mbuf (mb[0]),
249                         vlib_buffer_from_rte_mbuf (mb[1]),
250                         vlib_buffer_from_rte_mbuf (mb[2]),
251                         vlib_buffer_from_rte_mbuf (mb[3]), &bt);
252       clib_memcpy64_x4 (vlib_buffer_from_rte_mbuf (mb[4]),
253                         vlib_buffer_from_rte_mbuf (mb[5]),
254                         vlib_buffer_from_rte_mbuf (mb[6]),
255                         vlib_buffer_from_rte_mbuf (mb[7]), &bt);
256
257       n_left -= 8;
258       mb += 8;
259       bi += 8;
260     }
261
262   if (fl->buffer_init_function)
263     fl->buffer_init_function (vm, fl, fl->buffers + first, n_alloc);
264
265   fl->n_alloc += n_alloc;
266
267   return n_alloc;
268 }
269
270 static_always_inline void
271 dpdk_prefetch_buffer (vlib_buffer_t * b)
272 {
273   struct rte_mbuf *mb;
274   mb = rte_mbuf_from_vlib_buffer (b);
275   CLIB_PREFETCH (mb, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
276   CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD);
277 }
278
279 static_always_inline void
280 recycle_or_free (vlib_main_t * vm, vlib_buffer_main_t * bm, u32 bi,
281                  vlib_buffer_t * b)
282 {
283   vlib_buffer_free_list_t *fl;
284   u32 thread_index = vlib_get_thread_index ();
285   vlib_buffer_free_list_index_t fi;
286   fl = vlib_buffer_get_buffer_free_list (vm, b, &fi);
287
288   /* The only current use of this callback: multicast recycle */
289   if (PREDICT_FALSE (fl->buffers_added_to_freelist_function != 0))
290     {
291       int j;
292
293       vlib_buffer_add_to_free_list (vm, fl, bi,
294                                     (b->flags & VLIB_BUFFER_RECYCLE) == 0);
295
296       for (j = 0; j < vec_len (vm->buffer_announce_list); j++)
297         {
298           if (fl == vm->buffer_announce_list[j])
299             goto already_announced;
300         }
301       vec_add1 (vm->buffer_announce_list, fl);
302     already_announced:
303       ;
304     }
305   else if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_RECYCLE) == 0))
306     dpdk_rte_pktmbuf_free (vm, thread_index, b, 1);
307 }
308
309 static_always_inline void
310 vlib_buffer_free_inline (vlib_main_t * vm,
311                          u32 * buffers, u32 n_buffers, u32 follow_buffer_next)
312 {
313   vlib_buffer_main_t *bm = &buffer_main;
314   vlib_buffer_t *bufp[n_buffers], **b = bufp;
315   u32 thread_index = vlib_get_thread_index ();
316   int i = 0;
317   u32 simple_mask = (VLIB_BUFFER_NON_DEFAULT_FREELIST | VLIB_BUFFER_RECYCLE |
318                      VLIB_BUFFER_NEXT_PRESENT);
319   u32 n_left, *bi;
320   u32 (*cb) (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
321              u32 follow_buffer_next);
322
323   cb = bm->buffer_free_callback;
324
325   if (PREDICT_FALSE (cb != 0))
326     n_buffers = (*cb) (vm, buffers, n_buffers, follow_buffer_next);
327
328   if (!n_buffers)
329     return;
330
331   n_left = n_buffers;
332   bi = buffers;
333   b = bufp;
334   vlib_get_buffers (vm, bi, b, n_buffers);
335
336   while (n_left >= 4)
337     {
338       u32 or_flags;
339       vlib_buffer_t **p;
340
341       if (n_left < 16)
342         goto no_prefetch;
343
344       p = b + 12;
345       dpdk_prefetch_buffer (p[0]);
346       dpdk_prefetch_buffer (p[1]);
347       dpdk_prefetch_buffer (p[2]);
348       dpdk_prefetch_buffer (p[3]);
349     no_prefetch:
350
351       for (i = 0; i < 4; i++)
352         VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[i]);
353
354       or_flags = b[0]->flags | b[1]->flags | b[2]->flags | b[3]->flags;
355
356       if (or_flags & simple_mask)
357         {
358           recycle_or_free (vm, bm, bi[0], b[0]);
359           recycle_or_free (vm, bm, bi[1], b[1]);
360           recycle_or_free (vm, bm, bi[2], b[2]);
361           recycle_or_free (vm, bm, bi[3], b[3]);
362         }
363       else
364         {
365           dpdk_rte_pktmbuf_free (vm, thread_index, b[0], 0);
366           dpdk_rte_pktmbuf_free (vm, thread_index, b[1], 0);
367           dpdk_rte_pktmbuf_free (vm, thread_index, b[2], 0);
368           dpdk_rte_pktmbuf_free (vm, thread_index, b[3], 0);
369         }
370       bi += 4;
371       b += 4;
372       n_left -= 4;
373     }
374   while (n_left)
375     {
376       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
377       recycle_or_free (vm, bm, bi[0], b[0]);
378       bi += 1;
379       b += 1;
380       n_left -= 1;
381     }
382   if (vec_len (vm->buffer_announce_list))
383     {
384       vlib_buffer_free_list_t *fl;
385       for (i = 0; i < vec_len (vm->buffer_announce_list); i++)
386         {
387           fl = vm->buffer_announce_list[i];
388           fl->buffers_added_to_freelist_function (vm, fl);
389         }
390       _vec_len (vm->buffer_announce_list) = 0;
391     }
392 }
393
394 void
395 CLIB_MULTIARCH_FN (dpdk_buffer_free) (vlib_main_t * vm, u32 * buffers,
396                                       u32 n_buffers)
397 {
398   vlib_buffer_free_inline (vm, buffers, n_buffers,      /* follow_buffer_next */
399                            1);
400 }
401
402 void
403 CLIB_MULTIARCH_FN (dpdk_buffer_free_no_next) (vlib_main_t * vm, u32 * buffers,
404                                               u32 n_buffers)
405 {
406   vlib_buffer_free_inline (vm, buffers, n_buffers,      /* follow_buffer_next */
407                            0);
408 }
409
410 #ifndef CLIB_MARCH_VARIANT
411 static void
412 dpdk_packet_template_init (vlib_main_t * vm,
413                            void *vt,
414                            void *packet_data,
415                            uword n_packet_data_bytes,
416                            uword min_n_buffers_each_alloc, u8 * name)
417 {
418   vlib_packet_template_t *t = (vlib_packet_template_t *) vt;
419
420   vlib_worker_thread_barrier_sync (vm);
421   memset (t, 0, sizeof (t[0]));
422
423   vec_add (t->packet_data, packet_data, n_packet_data_bytes);
424
425   vlib_worker_thread_barrier_release (vm);
426 }
427
428 static clib_error_t *
429 scan_vfio_fd (void *arg, u8 * path_name, u8 * file_name)
430 {
431   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
432   linux_vfio_main_t *lvm = &vfio_main;
433   const char fn[] = "/dev/vfio/vfio";
434   char buff[sizeof (fn)] = { 0 };
435   int fd;
436   u8 *path = format (0, "%v%c", path_name, 0);
437
438   if (readlink ((char *) path, buff, sizeof (fn)) + 1 != sizeof (fn))
439     goto done;
440
441   if (strncmp (fn, buff, sizeof (fn)))
442     goto done;
443
444   fd = atoi ((char *) file_name);
445   if (fd != lvm->container_fd)
446     dbm->vfio_container_fd = fd;
447
448 done:
449   vec_free (path);
450   return 0;
451 }
452
453 clib_error_t *
454 dpdk_pool_create (vlib_main_t * vm, u8 * pool_name, u32 elt_size,
455                   u32 num_elts, u32 pool_priv_size, u16 cache_size, u8 numa,
456                   struct rte_mempool ** _mp,
457                   vlib_physmem_region_index_t * pri)
458 {
459   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
460   struct rte_mempool *mp;
461   vlib_physmem_region_t *pr;
462   dpdk_mempool_private_t priv;
463   clib_error_t *error = 0;
464   u32 size, obj_size;
465   i32 ret;
466   uword i;
467
468   obj_size = rte_mempool_calc_obj_size (elt_size, 0, 0);
469
470 #if RTE_VERSION < RTE_VERSION_NUM(18, 5, 0, 0)
471   size = rte_mempool_xmem_size (num_elts, obj_size, 21, 0);
472 #else
473   size = rte_mempool_calc_mem_size_helper (num_elts, obj_size, 21);
474 #endif
475
476   error = vlib_physmem_region_alloc (vm, (char *) pool_name, size, numa,
477                                      VLIB_PHYSMEM_F_HUGETLB |
478                                      VLIB_PHYSMEM_F_SHARED, pri);
479   if (error)
480     return error;
481
482   pr = vlib_physmem_get_region (vm, pri[0]);
483
484   mp = rte_mempool_create_empty ((char *) pool_name, num_elts, elt_size,
485                                  512, pool_priv_size, numa, 0);
486   if (!mp)
487     return clib_error_return (0, "failed to create %s", pool_name);
488
489   rte_mempool_set_ops_byname (mp, RTE_MBUF_DEFAULT_MEMPOOL_OPS, NULL);
490
491   /* Call the mempool priv initializer */
492   priv.mbp_priv.mbuf_data_room_size = VLIB_BUFFER_PRE_DATA_SIZE +
493     VLIB_BUFFER_DATA_SIZE;
494   priv.mbp_priv.mbuf_priv_size = VLIB_BUFFER_HDR_SIZE;
495   rte_pktmbuf_pool_init (mp, &priv);
496
497   for (i = 0; i < pr->n_pages; i++)
498     {
499       size_t page_size = 1 << pr->log2_page_size;
500       ret = rte_mempool_populate_iova (mp, ((char *) pr->mem) + i * page_size,
501                                        pr->page_table[i], page_size, 0, 0);
502       if (ret < 0)
503         {
504           rte_mempool_free (mp);
505           return clib_error_return (0, "failed to populate %s", pool_name);
506         }
507     }
508
509   _mp[0] = mp;
510
511   /* DPDK currently doesn't provide API to map DMA memory for empty mempool
512      so we are using this hack, will be nice to have at least API to get
513      VFIO container FD */
514   if (dbm->vfio_container_fd == -1)
515     foreach_directory_file ("/proc/self/fd", scan_vfio_fd, 0, 0);
516
517   if (dbm->vfio_container_fd != -1)
518     {
519       struct vfio_iommu_type1_dma_map dm = { 0 };
520       int i, rv = 0;
521       dm.argsz = sizeof (struct vfio_iommu_type1_dma_map);
522       dm.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
523
524       /* *INDENT-OFF* */
525       vec_foreach_index (i, pr->page_table)
526         {
527           dm.vaddr = pointer_to_uword (pr->mem) + (i << pr->log2_page_size);
528           dm.size = 1 << pr->log2_page_size;
529           dm.iova = pr->page_table[i];
530           if ((rv = ioctl (dbm->vfio_container_fd, VFIO_IOMMU_MAP_DMA, &dm)))
531             break;
532         }
533       /* *INDENT-ON* */
534       if (rv != 0 && errno != EINVAL)
535         clib_unix_warning ("ioctl(VFIO_IOMMU_MAP_DMA) pool '%s'", pool_name);
536     }
537
538   return 0;
539 }
540
541 clib_error_t *
542 dpdk_buffer_pool_create (vlib_main_t * vm, unsigned num_mbufs,
543                          unsigned socket_id)
544 {
545   dpdk_main_t *dm = &dpdk_main;
546   struct rte_mempool *rmp;
547   vlib_physmem_region_index_t pri;
548   clib_error_t *error = 0;
549   u8 *pool_name;
550   u32 elt_size, i;
551
552   vec_validate_aligned (dm->pktmbuf_pools, socket_id, CLIB_CACHE_LINE_BYTES);
553
554   /* pool already exists, nothing to do */
555   if (dm->pktmbuf_pools[socket_id])
556     return 0;
557
558   pool_name = format (0, "dpdk_mbuf_pool_socket%u%c", socket_id, 0);
559
560   elt_size = sizeof (struct rte_mbuf) +
561     VLIB_BUFFER_HDR_SIZE /* priv size */  +
562     VLIB_BUFFER_PRE_DATA_SIZE + VLIB_BUFFER_DATA_SIZE;  /*data room size */
563
564   error =
565     dpdk_pool_create (vm, pool_name, elt_size, num_mbufs,
566                       sizeof (dpdk_mempool_private_t), 512, socket_id,
567                       &rmp, &pri);
568
569   vec_free (pool_name);
570
571   if (!error)
572     {
573       /* call the object initializers */
574       rte_mempool_obj_iter (rmp, rte_pktmbuf_init, 0);
575
576       dpdk_mempool_private_t *privp = rte_mempool_get_priv (rmp);
577       privp->buffer_pool_index = vlib_buffer_pool_create (vm, pri, 0);
578
579       dm->pktmbuf_pools[socket_id] = rmp;
580
581       return 0;
582     }
583
584   clib_error_report (error);
585
586   /* no usable pool for this socket, try to use pool from another one */
587   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
588     {
589       if (dm->pktmbuf_pools[i])
590         {
591           clib_warning ("WARNING: Failed to allocate mempool for CPU socket "
592                         "%u. Threads running on socket %u will use socket %u "
593                         "mempool.", socket_id, socket_id, i);
594           dm->pktmbuf_pools[socket_id] = dm->pktmbuf_pools[i];
595           return 0;
596         }
597     }
598
599   return clib_error_return (0, "failed to allocate mempool on socket %u",
600                             socket_id);
601 }
602
603 #if CLIB_DEBUG > 0
604
605 u32 *vlib_buffer_state_validation_lock;
606 uword *vlib_buffer_state_validation_hash;
607 void *vlib_buffer_state_heap;
608
609 static clib_error_t *
610 buffer_state_validation_init (vlib_main_t * vm)
611 {
612   void *oldheap;
613
614   vlib_buffer_state_heap = mheap_alloc (0, 10 << 20);
615
616   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
617
618   vlib_buffer_state_validation_hash = hash_create (0, sizeof (uword));
619   vec_validate_aligned (vlib_buffer_state_validation_lock, 0,
620                         CLIB_CACHE_LINE_BYTES);
621   clib_mem_set_heap (oldheap);
622   return 0;
623 }
624
625 VLIB_INIT_FUNCTION (buffer_state_validation_init);
626 #endif
627
628 #if CLI_DEBUG
629 struct dpdk_validate_buf_result
630 {
631   u32 invalid;
632   u32 uninitialized;
633 };
634
635 #define DPDK_TRAJECTORY_POISON 31
636
637 static void
638 dpdk_buffer_validate_trajectory (struct rte_mempool *mp, void *opaque,
639                                  void *obj, unsigned obj_idx)
640 {
641   vlib_buffer_t *b;
642   struct dpdk_validate_buf_result *counter = opaque;
643   b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
644   if (b->pre_data[0] != 0)
645     {
646       if (b->pre_data[0] == DPDK_TRAJECTORY_POISON)
647         counter->uninitialized++;
648       else
649         counter->invalid++;
650     }
651 }
652
653 int
654 dpdk_buffer_validate_trajectory_all (u32 * uninitialized)
655 {
656   dpdk_main_t *dm = &dpdk_main;
657   struct dpdk_validate_buf_result counter = { 0 };
658   int i;
659
660   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
661     rte_mempool_obj_iter (dm->pktmbuf_pools[i],
662                           dpdk_buffer_validate_trajectory, &counter);
663   if (uninitialized)
664     *uninitialized = counter.uninitialized;
665   return counter.invalid;
666 }
667
668 static void
669 dpdk_buffer_poison_trajectory (struct rte_mempool *mp, void *opaque,
670                                void *obj, unsigned obj_idx)
671 {
672   vlib_buffer_t *b;
673   b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
674   b->pre_data[0] = DPDK_TRAJECTORY_POISON;
675 }
676
677 void
678 dpdk_buffer_poison_trajectory_all (void)
679 {
680   dpdk_main_t *dm = &dpdk_main;
681   int i;
682
683   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
684     rte_mempool_obj_iter (dm->pktmbuf_pools[i], dpdk_buffer_poison_trajectory,
685                           0);
686 }
687 #endif
688
689 static clib_error_t *
690 dpdk_buffer_init (vlib_main_t * vm)
691 {
692   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
693   vlib_thread_main_t *tm = vlib_get_thread_main ();
694
695   vec_validate_aligned (dbm->ptd, tm->n_vlib_mains - 1,
696                         CLIB_CACHE_LINE_BYTES);
697
698   dbm->vfio_container_fd = -1;
699
700   return 0;
701 }
702
703 VLIB_INIT_FUNCTION (dpdk_buffer_init);
704
705 /* *INDENT-OFF* */
706 VLIB_BUFFER_REGISTER_CALLBACKS (dpdk, static) = {
707   .vlib_buffer_fill_free_list_cb = &dpdk_buffer_fill_free_list,
708   .vlib_buffer_free_cb = &dpdk_buffer_free,
709   .vlib_buffer_free_no_next_cb = &dpdk_buffer_free_no_next,
710   .vlib_packet_template_init_cb = &dpdk_packet_template_init,
711   .vlib_buffer_delete_free_list_cb = &dpdk_buffer_delete_free_list,
712 };
713 /* *INDENT-ON* */
714
715 #if __x86_64__
716 vlib_buffer_fill_free_list_cb_t __clib_weak dpdk_buffer_fill_free_list_avx512;
717 vlib_buffer_fill_free_list_cb_t __clib_weak dpdk_buffer_fill_free_list_avx2;
718 vlib_buffer_free_cb_t __clib_weak dpdk_buffer_free_avx512;
719 vlib_buffer_free_cb_t __clib_weak dpdk_buffer_free_avx2;
720 vlib_buffer_free_no_next_cb_t __clib_weak dpdk_buffer_free_no_next_avx512;
721 vlib_buffer_free_no_next_cb_t __clib_weak dpdk_buffer_free_no_next_avx2;
722
723 static void __clib_constructor
724 dpdk_input_multiarch_select (void)
725 {
726   vlib_buffer_callbacks_t *cb = &__dpdk_buffer_callbacks;
727   if (dpdk_buffer_fill_free_list_avx512 && clib_cpu_supports_avx512f ())
728     {
729       cb->vlib_buffer_fill_free_list_cb = dpdk_buffer_fill_free_list_avx512;
730       cb->vlib_buffer_free_cb = dpdk_buffer_free_avx512;
731       cb->vlib_buffer_free_no_next_cb = dpdk_buffer_free_no_next_avx512;
732     }
733   else if (dpdk_buffer_fill_free_list_avx2 && clib_cpu_supports_avx2 ())
734     {
735       cb->vlib_buffer_fill_free_list_cb = dpdk_buffer_fill_free_list_avx2;
736       cb->vlib_buffer_free_cb = dpdk_buffer_free_avx2;
737       cb->vlib_buffer_free_no_next_cb = dpdk_buffer_free_no_next_avx2;
738     }
739 }
740 #endif
741 #endif
742
743 /** @endcond */
744 /*
745  * fd.io coding-style-patch-verification: ON
746  *
747  * Local Variables:
748  * eval: (c-set-style "gnu")
749  * End:
750  */