plugins: dpdk: fix check which makes not sense, likely a typo
[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_pending_free_list;
92
93   /* cached last pool */
94   struct rte_mempool *last_pool;
95   u8 last_buffer_pool_index;
96 } dpdk_buffer_per_thread_data;
97
98 typedef struct
99 {
100   int vfio_container_fd;
101   dpdk_buffer_per_thread_data *ptd;
102 } dpdk_buffer_main_t;
103
104 dpdk_buffer_main_t dpdk_buffer_main;
105
106 static_always_inline void
107 dpdk_rte_pktmbuf_free (vlib_main_t * vm, u32 thread_index, vlib_buffer_t * b)
108 {
109   vlib_buffer_t *hb = b;
110   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
111   dpdk_buffer_per_thread_data *d = vec_elt_at_index (dbm->ptd, thread_index);
112   struct rte_mbuf *mb;
113   u32 next, flags;
114   mb = rte_mbuf_from_vlib_buffer (hb);
115
116 next:
117   flags = b->flags;
118   next = b->next_buffer;
119   mb = rte_mbuf_from_vlib_buffer (b);
120
121   if (PREDICT_FALSE (b->n_add_refs))
122     {
123       rte_mbuf_refcnt_update (mb, b->n_add_refs);
124       b->n_add_refs = 0;
125     }
126
127   mb = rte_pktmbuf_prefree_seg (mb);
128   if (mb)
129     {
130       if (mb->pool != d->last_pool)
131         {
132           d->last_pool = mb->pool;
133           dpdk_mempool_private_t *privp = rte_mempool_get_priv (d->last_pool);
134           d->last_buffer_pool_index = privp->buffer_pool_index;
135           vec_validate_aligned (d->mbuf_pending_free_list,
136                                 d->last_buffer_pool_index,
137                                 CLIB_CACHE_LINE_BYTES);
138         }
139       vec_add1 (d->mbuf_pending_free_list[d->last_buffer_pool_index], mb);
140     }
141
142   if (flags & VLIB_BUFFER_NEXT_PRESENT)
143     {
144       b = vlib_get_buffer (vm, next);
145       goto next;
146     }
147 }
148
149 #ifndef CLIB_MULTIARCH_VARIANT
150 static void
151 del_free_list (vlib_main_t * vm, vlib_buffer_free_list_t * f)
152 {
153   u32 i;
154   vlib_buffer_t *b;
155   u32 thread_index = vlib_get_thread_index ();
156
157   for (i = 0; i < vec_len (f->buffers); i++)
158     {
159       b = vlib_get_buffer (vm, f->buffers[i]);
160       dpdk_rte_pktmbuf_free (vm, thread_index, b);
161     }
162
163   vec_free (f->name);
164   vec_free (f->buffers);
165   /* Poison it. */
166   memset (f, 0xab, sizeof (f[0]));
167 }
168
169 /* Add buffer free list. */
170 static void
171 dpdk_buffer_delete_free_list (vlib_main_t * vm,
172                               vlib_buffer_free_list_index_t free_list_index)
173 {
174   vlib_buffer_free_list_t *f;
175   int i;
176
177   ASSERT (vlib_get_thread_index () == 0);
178
179   f = vlib_buffer_get_free_list (vm, free_list_index);
180
181   del_free_list (vm, f);
182
183   pool_put (vm->buffer_free_list_pool, f);
184
185   for (i = 1; i < vec_len (vlib_mains); i++)
186     {
187       vlib_main_t *wvm = vlib_mains[i];
188       f = vlib_buffer_get_free_list (vlib_mains[i], free_list_index);
189       del_free_list (wvm, f);
190       pool_put (wvm->buffer_free_list_pool, f);
191     }
192 }
193 #endif
194
195 /* Make sure free list has at least given number of free buffers. */
196 uword
197 CLIB_MULTIARCH_FN (dpdk_buffer_fill_free_list) (vlib_main_t * vm,
198                                                 vlib_buffer_free_list_t * fl,
199                                                 uword min_free_buffers)
200 {
201   dpdk_main_t *dm = &dpdk_main;
202   vlib_buffer_t *b0, *b1, *b2, *b3;
203   int n, i;
204   u32 bi0, bi1, bi2, bi3;
205   unsigned socket_id = rte_socket_id ();
206   struct rte_mempool *rmp = dm->pktmbuf_pools[socket_id];
207   dpdk_mempool_private_t *privp = rte_mempool_get_priv (rmp);
208   struct rte_mbuf *mb0, *mb1, *mb2, *mb3;
209   vlib_buffer_t bt;
210
211   /* Too early? */
212   if (PREDICT_FALSE (rmp == 0))
213     return 0;
214
215   /* Already have enough free buffers on free list? */
216   n = min_free_buffers - vec_len (fl->buffers);
217   if (n <= 0)
218     return min_free_buffers;
219
220   /* Always allocate round number of buffers. */
221   n = round_pow2 (n, CLIB_CACHE_LINE_BYTES / sizeof (u32));
222
223   /* Always allocate new buffers in reasonably large sized chunks. */
224   n = clib_max (n, fl->min_n_buffers_each_alloc);
225
226   vec_validate_aligned (vm->mbuf_alloc_list, n - 1, CLIB_CACHE_LINE_BYTES);
227
228   if (rte_mempool_get_bulk (rmp, vm->mbuf_alloc_list, n) < 0)
229     return 0;
230
231   memset (&bt, 0, sizeof (vlib_buffer_t));
232   vlib_buffer_init_for_free_list (&bt, fl);
233   bt.buffer_pool_index = privp->buffer_pool_index;
234
235   _vec_len (vm->mbuf_alloc_list) = n;
236
237   i = 0;
238   int f = vec_len (fl->buffers);
239   vec_resize_aligned (fl->buffers, n, CLIB_CACHE_LINE_BYTES);
240
241   while (i < (n - 7))
242     {
243       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf
244                                    (vm->mbuf_alloc_list[i + 4]), STORE);
245       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf
246                                    (vm->mbuf_alloc_list[i + 5]), STORE);
247       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf
248                                    (vm->mbuf_alloc_list[i + 6]), STORE);
249       vlib_prefetch_buffer_header (vlib_buffer_from_rte_mbuf
250                                    (vm->mbuf_alloc_list[i + 7]), STORE);
251
252       mb0 = vm->mbuf_alloc_list[i];
253       mb1 = vm->mbuf_alloc_list[i + 1];
254       mb2 = vm->mbuf_alloc_list[i + 2];
255       mb3 = vm->mbuf_alloc_list[i + 3];
256
257       b0 = vlib_buffer_from_rte_mbuf (mb0);
258       b1 = vlib_buffer_from_rte_mbuf (mb1);
259       b2 = vlib_buffer_from_rte_mbuf (mb2);
260       b3 = vlib_buffer_from_rte_mbuf (mb3);
261
262       bi0 = vlib_get_buffer_index (vm, b0);
263       bi1 = vlib_get_buffer_index (vm, b1);
264       bi2 = vlib_get_buffer_index (vm, b2);
265       bi3 = vlib_get_buffer_index (vm, b3);
266
267       fl->buffers[f++] = bi0;
268       fl->buffers[f++] = bi1;
269       fl->buffers[f++] = bi2;
270       fl->buffers[f++] = bi3;
271
272       clib_memcpy64_x4 (b0, b1, b2, b3, &bt);
273
274       if (fl->buffer_init_function)
275         {
276           fl->buffer_init_function (vm, fl, &bi0, 1);
277           fl->buffer_init_function (vm, fl, &bi1, 1);
278           fl->buffer_init_function (vm, fl, &bi2, 1);
279           fl->buffer_init_function (vm, fl, &bi3, 1);
280         }
281       i += 4;
282     }
283
284   while (i < n)
285     {
286       mb0 = vm->mbuf_alloc_list[i];
287
288       b0 = vlib_buffer_from_rte_mbuf (mb0);
289       bi0 = vlib_get_buffer_index (vm, b0);
290
291       fl->buffers[f++] = bi0;
292       clib_memcpy (b0, &bt, sizeof (vlib_buffer_t));
293
294       if (fl->buffer_init_function)
295         fl->buffer_init_function (vm, fl, &bi0, 1);
296       i++;
297     }
298
299   fl->n_alloc += n;
300
301   return n;
302 }
303
304 static_always_inline void
305 dpdk_prefetch_buffer_by_index (vlib_main_t * vm, u32 bi)
306 {
307   vlib_buffer_t *b;
308   struct rte_mbuf *mb;
309   b = vlib_get_buffer (vm, bi);
310   mb = rte_mbuf_from_vlib_buffer (b);
311   CLIB_PREFETCH (mb, 2 * CLIB_CACHE_LINE_BYTES, STORE);
312   CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD);
313 }
314
315 static_always_inline void
316 recycle_or_free (vlib_main_t * vm, vlib_buffer_main_t * bm, u32 bi,
317                  vlib_buffer_t * b)
318 {
319   vlib_buffer_free_list_t *fl;
320   u32 thread_index = vlib_get_thread_index ();
321   vlib_buffer_free_list_index_t fi;
322   fl = vlib_buffer_get_buffer_free_list (vm, b, &fi);
323
324   /* The only current use of this callback: multicast recycle */
325   if (PREDICT_FALSE (fl->buffers_added_to_freelist_function != 0))
326     {
327       int j;
328
329       vlib_buffer_add_to_free_list (vm, fl, bi,
330                                     (b->flags & VLIB_BUFFER_RECYCLE) == 0);
331
332       for (j = 0; j < vec_len (vm->buffer_announce_list); j++)
333         {
334           if (fl == vm->buffer_announce_list[j])
335             goto already_announced;
336         }
337       vec_add1 (vm->buffer_announce_list, fl);
338     already_announced:
339       ;
340     }
341   else
342     {
343       if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_RECYCLE) == 0))
344         dpdk_rte_pktmbuf_free (vm, thread_index, b);
345     }
346 }
347
348 static_always_inline void
349 vlib_buffer_free_inline (vlib_main_t * vm,
350                          u32 * buffers, u32 n_buffers, u32 follow_buffer_next)
351 {
352   vlib_buffer_main_t *bm = &buffer_main;
353   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
354   vlib_buffer_t *b0, *b1, *b2, *b3;
355   u32 thread_index = vlib_get_thread_index ();
356   dpdk_buffer_per_thread_data *d = vec_elt_at_index (dbm->ptd, thread_index);
357   int i = 0;
358   u32 (*cb) (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
359              u32 follow_buffer_next);
360
361   cb = bm->buffer_free_callback;
362
363   if (PREDICT_FALSE (cb != 0))
364     n_buffers = (*cb) (vm, buffers, n_buffers, follow_buffer_next);
365
366   if (!n_buffers)
367     return;
368
369   while (i + 7 < n_buffers)
370     {
371       dpdk_prefetch_buffer_by_index (vm, buffers[i + 4]);
372       dpdk_prefetch_buffer_by_index (vm, buffers[i + 5]);
373       dpdk_prefetch_buffer_by_index (vm, buffers[i + 6]);
374       dpdk_prefetch_buffer_by_index (vm, buffers[i + 7]);
375
376       b0 = vlib_get_buffer (vm, buffers[i]);
377       b1 = vlib_get_buffer (vm, buffers[i + 1]);
378       b2 = vlib_get_buffer (vm, buffers[i + 2]);
379       b3 = vlib_get_buffer (vm, buffers[i + 3]);
380
381       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
382       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b1);
383       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b2);
384       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b3);
385
386       recycle_or_free (vm, bm, buffers[i], b0);
387       recycle_or_free (vm, bm, buffers[i + 1], b1);
388       recycle_or_free (vm, bm, buffers[i + 2], b2);
389       recycle_or_free (vm, bm, buffers[i + 3], b3);
390
391       i += 4;
392     }
393   while (i < n_buffers)
394     {
395       b0 = vlib_get_buffer (vm, buffers[i]);
396       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
397       recycle_or_free (vm, bm, buffers[i], b0);
398       i++;
399     }
400   if (vec_len (vm->buffer_announce_list))
401     {
402       vlib_buffer_free_list_t *fl;
403       for (i = 0; i < vec_len (vm->buffer_announce_list); i++)
404         {
405           fl = vm->buffer_announce_list[i];
406           fl->buffers_added_to_freelist_function (vm, fl);
407         }
408       _vec_len (vm->buffer_announce_list) = 0;
409     }
410
411   vec_foreach_index (i, d->mbuf_pending_free_list)
412   {
413     int len = vec_len (d->mbuf_pending_free_list[i]);
414     if (len)
415       {
416         rte_mempool_put_bulk (d->mbuf_pending_free_list[i][len - 1]->pool,
417                               (void *) d->mbuf_pending_free_list[i], len);
418         vec_reset_length (d->mbuf_pending_free_list[i]);
419       }
420   }
421 }
422
423 void
424 CLIB_MULTIARCH_FN (dpdk_buffer_free) (vlib_main_t * vm, u32 * buffers,
425                                       u32 n_buffers)
426 {
427   vlib_buffer_free_inline (vm, buffers, n_buffers,      /* follow_buffer_next */
428                            1);
429 }
430
431 void
432 CLIB_MULTIARCH_FN (dpdk_buffer_free_no_next) (vlib_main_t * vm, u32 * buffers,
433                                               u32 n_buffers)
434 {
435   vlib_buffer_free_inline (vm, buffers, n_buffers,      /* follow_buffer_next */
436                            0);
437 }
438
439 #ifndef CLIB_MULTIARCH_VARIANT
440 static void
441 dpdk_packet_template_init (vlib_main_t * vm,
442                            void *vt,
443                            void *packet_data,
444                            uword n_packet_data_bytes,
445                            uword min_n_buffers_each_alloc, u8 * name)
446 {
447   vlib_packet_template_t *t = (vlib_packet_template_t *) vt;
448
449   vlib_worker_thread_barrier_sync (vm);
450   memset (t, 0, sizeof (t[0]));
451
452   vec_add (t->packet_data, packet_data, n_packet_data_bytes);
453
454   vlib_worker_thread_barrier_release (vm);
455 }
456
457 static clib_error_t *
458 scan_vfio_fd (void *arg, u8 * path_name, u8 * file_name)
459 {
460   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
461   linux_vfio_main_t *lvm = &vfio_main;
462   const char fn[] = "/dev/vfio/vfio";
463   char buff[sizeof (fn)] = { 0 };
464   int fd;
465   u8 *path = format (0, "%v%c", path_name, 0);
466
467   if (readlink ((char *) path, buff, sizeof (fn)) + 1 != sizeof (fn))
468     goto done;
469
470   if (strncmp (fn, buff, sizeof (fn)))
471     goto done;
472
473   fd = atoi ((char *) file_name);
474   if (fd != lvm->container_fd)
475     dbm->vfio_container_fd = fd;
476
477 done:
478   vec_free (path);
479   return 0;
480 }
481
482 clib_error_t *
483 dpdk_pool_create (vlib_main_t * vm, u8 * pool_name, u32 elt_size,
484                   u32 num_elts, u32 pool_priv_size, u16 cache_size, u8 numa,
485                   struct rte_mempool ** _mp,
486                   vlib_physmem_region_index_t * pri)
487 {
488   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
489   struct rte_mempool *mp;
490   vlib_physmem_region_t *pr;
491   clib_error_t *error = 0;
492   u32 size, obj_size;
493   i32 ret;
494
495   obj_size = rte_mempool_calc_obj_size (elt_size, 0, 0);
496   size = rte_mempool_xmem_size (num_elts, obj_size, 21, 0);
497
498   error =
499     vlib_physmem_region_alloc (vm, (i8 *) pool_name, size, numa,
500                                VLIB_PHYSMEM_F_HUGETLB | VLIB_PHYSMEM_F_SHARED,
501                                pri);
502   if (error)
503     return error;
504
505   pr = vlib_physmem_get_region (vm, pri[0]);
506
507   mp =
508     rte_mempool_create_empty ((i8 *) pool_name, num_elts, elt_size,
509                               512, pool_priv_size, numa, 0);
510   if (!mp)
511     return clib_error_return (0, "failed to create %s", pool_name);
512
513   rte_mempool_set_ops_byname (mp, RTE_MBUF_DEFAULT_MEMPOOL_OPS, NULL);
514
515   ret =
516     rte_mempool_populate_iova_tab (mp, pr->mem, pr->page_table, pr->n_pages,
517                                    pr->log2_page_size, NULL, NULL);
518   if (ret != (i32) mp->size)
519     {
520       rte_mempool_free (mp);
521       return clib_error_return (0, "failed to populate %s", pool_name);
522     }
523
524   _mp[0] = mp;
525
526   /* DPDK currently doesn't provide API to map DMA memory for empty mempool
527      so we are using this hack, will be nice to have at least API to get
528      VFIO container FD */
529   if (dbm->vfio_container_fd == -1)
530     foreach_directory_file ("/proc/self/fd", scan_vfio_fd, 0, 0);
531
532   if (dbm->vfio_container_fd != -1)
533     {
534       struct vfio_iommu_type1_dma_map dm = { 0 };
535       int i, rv = 0;
536       dm.argsz = sizeof (struct vfio_iommu_type1_dma_map);
537       dm.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
538
539       /* *INDENT-OFF* */
540       vec_foreach_index (i, pr->page_table)
541         {
542           dm.vaddr = pointer_to_uword (pr->mem) + (i << pr->log2_page_size);
543           dm.size = 1 << pr->log2_page_size;
544           dm.iova = pr->page_table[i];
545           if ((rv = ioctl (dbm->vfio_container_fd, VFIO_IOMMU_MAP_DMA, &dm)))
546             break;
547         }
548       /* *INDENT-ON* */
549       if (rv != 0 && errno != EINVAL)
550         clib_unix_warning ("ioctl(VFIO_IOMMU_MAP_DMA) pool '%s'", pool_name);
551     }
552
553   return 0;
554 }
555
556 clib_error_t *
557 dpdk_buffer_pool_create (vlib_main_t * vm, unsigned num_mbufs,
558                          unsigned socket_id)
559 {
560   dpdk_main_t *dm = &dpdk_main;
561   struct rte_mempool *rmp;
562   dpdk_mempool_private_t priv;
563   vlib_physmem_region_index_t pri;
564   clib_error_t *error = 0;
565   u8 *pool_name;
566   u32 elt_size, i;
567
568   vec_validate_aligned (dm->pktmbuf_pools, socket_id, CLIB_CACHE_LINE_BYTES);
569
570   /* pool already exists, nothing to do */
571   if (dm->pktmbuf_pools[socket_id])
572     return 0;
573
574   pool_name = format (0, "dpdk_mbuf_pool_socket%u%c", socket_id, 0);
575
576   elt_size = sizeof (struct rte_mbuf) +
577     VLIB_BUFFER_HDR_SIZE /* priv size */  +
578     VLIB_BUFFER_PRE_DATA_SIZE + VLIB_BUFFER_DATA_SIZE;  /*data room size */
579
580   error =
581     dpdk_pool_create (vm, pool_name, elt_size, num_mbufs,
582                       sizeof (dpdk_mempool_private_t), 512, socket_id,
583                       &rmp, &pri);
584
585   vec_free (pool_name);
586
587   if (!error)
588     {
589       priv.mbp_priv.mbuf_data_room_size = VLIB_BUFFER_PRE_DATA_SIZE +
590         VLIB_BUFFER_DATA_SIZE;
591       priv.mbp_priv.mbuf_priv_size = VLIB_BUFFER_HDR_SIZE;
592
593       /* call the mempool priv initializer */
594       rte_pktmbuf_pool_init (rmp, &priv);
595
596       /* call the object initializers */
597       rte_mempool_obj_iter (rmp, rte_pktmbuf_init, 0);
598
599       dpdk_mempool_private_t *privp = rte_mempool_get_priv (rmp);
600       privp->buffer_pool_index = vlib_buffer_pool_create (vm, pri, 0);
601
602       dm->pktmbuf_pools[socket_id] = rmp;
603
604       return 0;
605     }
606
607   clib_error_report (error);
608
609   /* no usable pool for this socket, try to use pool from another one */
610   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
611     {
612       if (dm->pktmbuf_pools[i])
613         {
614           clib_warning ("WARNING: Failed to allocate mempool for CPU socket "
615                         "%u. Threads running on socket %u will use socket %u "
616                         "mempool.", socket_id, socket_id, i);
617           dm->pktmbuf_pools[socket_id] = dm->pktmbuf_pools[i];
618           return 0;
619         }
620     }
621
622   return clib_error_return (0, "failed to allocate mempool on socket %u",
623                             socket_id);
624 }
625
626 #if CLIB_DEBUG > 0
627
628 u32 *vlib_buffer_state_validation_lock;
629 uword *vlib_buffer_state_validation_hash;
630 void *vlib_buffer_state_heap;
631
632 static clib_error_t *
633 buffer_state_validation_init (vlib_main_t * vm)
634 {
635   void *oldheap;
636
637   vlib_buffer_state_heap = mheap_alloc (0, 10 << 20);
638
639   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
640
641   vlib_buffer_state_validation_hash = hash_create (0, sizeof (uword));
642   vec_validate_aligned (vlib_buffer_state_validation_lock, 0,
643                         CLIB_CACHE_LINE_BYTES);
644   clib_mem_set_heap (oldheap);
645   return 0;
646 }
647
648 VLIB_INIT_FUNCTION (buffer_state_validation_init);
649 #endif
650
651 #if CLI_DEBUG
652 struct dpdk_validate_buf_result
653 {
654   u32 invalid;
655   u32 uninitialized;
656 };
657
658 #define DPDK_TRAJECTORY_POISON 31
659
660 static void
661 dpdk_buffer_validate_trajectory (struct rte_mempool *mp, void *opaque,
662                                  void *obj, unsigned obj_idx)
663 {
664   vlib_buffer_t *b;
665   struct dpdk_validate_buf_result *counter = opaque;
666   b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
667   if (b->pre_data[0] != 0)
668     {
669       if (b->pre_data[0] == DPDK_TRAJECTORY_POISON)
670         counter->uninitialized++;
671       else
672         counter->invalid++;
673     }
674 }
675
676 int
677 dpdk_buffer_validate_trajectory_all (u32 * uninitialized)
678 {
679   dpdk_main_t *dm = &dpdk_main;
680   struct dpdk_validate_buf_result counter = { 0 };
681   int i;
682
683   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
684     rte_mempool_obj_iter (dm->pktmbuf_pools[i],
685                           dpdk_buffer_validate_trajectory, &counter);
686   if (uninitialized)
687     *uninitialized = counter.uninitialized;
688   return counter.invalid;
689 }
690
691 static void
692 dpdk_buffer_poison_trajectory (struct rte_mempool *mp, void *opaque,
693                                void *obj, unsigned obj_idx)
694 {
695   vlib_buffer_t *b;
696   b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
697   b->pre_data[0] = DPDK_TRAJECTORY_POISON;
698 }
699
700 void
701 dpdk_buffer_poison_trajectory_all (void)
702 {
703   dpdk_main_t *dm = &dpdk_main;
704   int i;
705
706   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
707     rte_mempool_obj_iter (dm->pktmbuf_pools[i], dpdk_buffer_poison_trajectory,
708                           0);
709 }
710 #endif
711
712 static clib_error_t *
713 dpdk_buffer_init (vlib_main_t * vm)
714 {
715   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
716   vlib_thread_main_t *tm = vlib_get_thread_main ();
717
718   vec_validate_aligned (dbm->ptd, tm->n_vlib_mains - 1,
719                         CLIB_CACHE_LINE_BYTES);
720
721   dbm->vfio_container_fd = -1;
722
723   return 0;
724 }
725
726 VLIB_INIT_FUNCTION (dpdk_buffer_init);
727
728 /* *INDENT-OFF* */
729 VLIB_BUFFER_REGISTER_CALLBACKS (dpdk, static) = {
730   .vlib_buffer_fill_free_list_cb = &dpdk_buffer_fill_free_list,
731   .vlib_buffer_free_cb = &dpdk_buffer_free,
732   .vlib_buffer_free_no_next_cb = &dpdk_buffer_free_no_next,
733   .vlib_packet_template_init_cb = &dpdk_packet_template_init,
734   .vlib_buffer_delete_free_list_cb = &dpdk_buffer_delete_free_list,
735 };
736 /* *INDENT-ON* */
737
738 #if __x86_64__
739 vlib_buffer_fill_free_list_cb_t __clib_weak dpdk_buffer_fill_free_list_avx512;
740 vlib_buffer_fill_free_list_cb_t __clib_weak dpdk_buffer_fill_free_list_avx2;
741 vlib_buffer_free_cb_t __clib_weak dpdk_buffer_free_avx512;
742 vlib_buffer_free_cb_t __clib_weak dpdk_buffer_free_avx2;
743 vlib_buffer_free_no_next_cb_t __clib_weak dpdk_buffer_free_no_next_avx512;
744 vlib_buffer_free_no_next_cb_t __clib_weak dpdk_buffer_free_no_next_avx2;
745
746 static void __clib_constructor
747 dpdk_input_multiarch_select (void)
748 {
749   vlib_buffer_callbacks_t *cb = &__dpdk_buffer_callbacks;
750   if (dpdk_buffer_fill_free_list_avx512 && clib_cpu_supports_avx512f ())
751     {
752       cb->vlib_buffer_fill_free_list_cb = dpdk_buffer_fill_free_list_avx512;
753       cb->vlib_buffer_free_cb = dpdk_buffer_free_avx512;
754       cb->vlib_buffer_free_no_next_cb = dpdk_buffer_free_no_next_avx512;
755     }
756   else if (dpdk_buffer_fill_free_list_avx2 && clib_cpu_supports_avx2 ())
757     {
758       cb->vlib_buffer_fill_free_list_cb = dpdk_buffer_fill_free_list_avx2;
759       cb->vlib_buffer_free_cb = dpdk_buffer_free_avx2;
760       cb->vlib_buffer_free_no_next_cb = dpdk_buffer_free_no_next_avx2;
761     }
762 }
763 #endif
764 #endif
765
766 /** @endcond */
767 /*
768  * fd.io coding-style-patch-verification: ON
769  *
770  * Local Variables:
771  * eval: (c-set-style "gnu")
772  * End:
773  */