dpdk: set dmamap iova address value according to eal_iova_mode
[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           if (rte_eal_iova_mode() == RTE_IOVA_PA)
545                   dm.iova = pr->page_table[i];
546           else
547                   dm.iova = dm.vaddr;
548           if ((rv = ioctl (dbm->vfio_container_fd, VFIO_IOMMU_MAP_DMA, &dm)))
549             break;
550         }
551       /* *INDENT-ON* */
552       if (rv != 0 && errno != EINVAL)
553         clib_unix_warning ("ioctl(VFIO_IOMMU_MAP_DMA) pool '%s'", pool_name);
554     }
555
556   return 0;
557 }
558
559 clib_error_t *
560 dpdk_buffer_pool_create (vlib_main_t * vm, unsigned num_mbufs,
561                          unsigned socket_id)
562 {
563   dpdk_main_t *dm = &dpdk_main;
564   struct rte_mempool *rmp;
565   dpdk_mempool_private_t priv;
566   vlib_physmem_region_index_t pri;
567   clib_error_t *error = 0;
568   u8 *pool_name;
569   u32 elt_size, i;
570
571   vec_validate_aligned (dm->pktmbuf_pools, socket_id, CLIB_CACHE_LINE_BYTES);
572
573   /* pool already exists, nothing to do */
574   if (dm->pktmbuf_pools[socket_id])
575     return 0;
576
577   pool_name = format (0, "dpdk_mbuf_pool_socket%u%c", socket_id, 0);
578
579   elt_size = sizeof (struct rte_mbuf) +
580     VLIB_BUFFER_HDR_SIZE /* priv size */  +
581     VLIB_BUFFER_PRE_DATA_SIZE + VLIB_BUFFER_DATA_SIZE;  /*data room size */
582
583   error =
584     dpdk_pool_create (vm, pool_name, elt_size, num_mbufs,
585                       sizeof (dpdk_mempool_private_t), 512, socket_id,
586                       &rmp, &pri);
587
588   vec_free (pool_name);
589
590   if (!error)
591     {
592       priv.mbp_priv.mbuf_data_room_size = VLIB_BUFFER_PRE_DATA_SIZE +
593         VLIB_BUFFER_DATA_SIZE;
594       priv.mbp_priv.mbuf_priv_size = VLIB_BUFFER_HDR_SIZE;
595
596       /* call the mempool priv initializer */
597       rte_pktmbuf_pool_init (rmp, &priv);
598
599       /* call the object initializers */
600       rte_mempool_obj_iter (rmp, rte_pktmbuf_init, 0);
601
602       dpdk_mempool_private_t *privp = rte_mempool_get_priv (rmp);
603       privp->buffer_pool_index = vlib_buffer_pool_create (vm, pri, 0);
604
605       dm->pktmbuf_pools[socket_id] = rmp;
606
607       return 0;
608     }
609
610   clib_error_report (error);
611
612   /* no usable pool for this socket, try to use pool from another one */
613   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
614     {
615       if (dm->pktmbuf_pools[i])
616         {
617           clib_warning ("WARNING: Failed to allocate mempool for CPU socket "
618                         "%u. Threads running on socket %u will use socket %u "
619                         "mempool.", socket_id, socket_id, i);
620           dm->pktmbuf_pools[socket_id] = dm->pktmbuf_pools[i];
621           return 0;
622         }
623     }
624
625   return clib_error_return (0, "failed to allocate mempool on socket %u",
626                             socket_id);
627 }
628
629 #if CLIB_DEBUG > 0
630
631 u32 *vlib_buffer_state_validation_lock;
632 uword *vlib_buffer_state_validation_hash;
633 void *vlib_buffer_state_heap;
634
635 static clib_error_t *
636 buffer_state_validation_init (vlib_main_t * vm)
637 {
638   void *oldheap;
639
640   vlib_buffer_state_heap = mheap_alloc (0, 10 << 20);
641
642   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
643
644   vlib_buffer_state_validation_hash = hash_create (0, sizeof (uword));
645   vec_validate_aligned (vlib_buffer_state_validation_lock, 0,
646                         CLIB_CACHE_LINE_BYTES);
647   clib_mem_set_heap (oldheap);
648   return 0;
649 }
650
651 VLIB_INIT_FUNCTION (buffer_state_validation_init);
652 #endif
653
654 #if CLI_DEBUG
655 struct dpdk_validate_buf_result
656 {
657   u32 invalid;
658   u32 uninitialized;
659 };
660
661 #define DPDK_TRAJECTORY_POISON 31
662
663 static void
664 dpdk_buffer_validate_trajectory (struct rte_mempool *mp, void *opaque,
665                                  void *obj, unsigned obj_idx)
666 {
667   vlib_buffer_t *b;
668   struct dpdk_validate_buf_result *counter = opaque;
669   b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
670   if (b->pre_data[0] != 0)
671     {
672       if (b->pre_data[0] == DPDK_TRAJECTORY_POISON)
673         counter->uninitialized++;
674       else
675         counter->invalid++;
676     }
677 }
678
679 int
680 dpdk_buffer_validate_trajectory_all (u32 * uninitialized)
681 {
682   dpdk_main_t *dm = &dpdk_main;
683   struct dpdk_validate_buf_result counter = { 0 };
684   int i;
685
686   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
687     rte_mempool_obj_iter (dm->pktmbuf_pools[i],
688                           dpdk_buffer_validate_trajectory, &counter);
689   if (uninitialized)
690     *uninitialized = counter.uninitialized;
691   return counter.invalid;
692 }
693
694 static void
695 dpdk_buffer_poison_trajectory (struct rte_mempool *mp, void *opaque,
696                                void *obj, unsigned obj_idx)
697 {
698   vlib_buffer_t *b;
699   b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
700   b->pre_data[0] = DPDK_TRAJECTORY_POISON;
701 }
702
703 void
704 dpdk_buffer_poison_trajectory_all (void)
705 {
706   dpdk_main_t *dm = &dpdk_main;
707   int i;
708
709   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
710     rte_mempool_obj_iter (dm->pktmbuf_pools[i], dpdk_buffer_poison_trajectory,
711                           0);
712 }
713 #endif
714
715 static clib_error_t *
716 dpdk_buffer_init (vlib_main_t * vm)
717 {
718   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
719   vlib_thread_main_t *tm = vlib_get_thread_main ();
720
721   vec_validate_aligned (dbm->ptd, tm->n_vlib_mains - 1,
722                         CLIB_CACHE_LINE_BYTES);
723
724   dbm->vfio_container_fd = -1;
725
726   return 0;
727 }
728
729 VLIB_INIT_FUNCTION (dpdk_buffer_init);
730
731 /* *INDENT-OFF* */
732 VLIB_BUFFER_REGISTER_CALLBACKS (dpdk, static) = {
733   .vlib_buffer_fill_free_list_cb = &dpdk_buffer_fill_free_list,
734   .vlib_buffer_free_cb = &dpdk_buffer_free,
735   .vlib_buffer_free_no_next_cb = &dpdk_buffer_free_no_next,
736   .vlib_packet_template_init_cb = &dpdk_packet_template_init,
737   .vlib_buffer_delete_free_list_cb = &dpdk_buffer_delete_free_list,
738 };
739 /* *INDENT-ON* */
740
741 #if __x86_64__
742 vlib_buffer_fill_free_list_cb_t __clib_weak dpdk_buffer_fill_free_list_avx512;
743 vlib_buffer_fill_free_list_cb_t __clib_weak dpdk_buffer_fill_free_list_avx2;
744 vlib_buffer_free_cb_t __clib_weak dpdk_buffer_free_avx512;
745 vlib_buffer_free_cb_t __clib_weak dpdk_buffer_free_avx2;
746 vlib_buffer_free_no_next_cb_t __clib_weak dpdk_buffer_free_no_next_avx512;
747 vlib_buffer_free_no_next_cb_t __clib_weak dpdk_buffer_free_no_next_avx2;
748
749 static void __clib_constructor
750 dpdk_input_multiarch_select (void)
751 {
752   vlib_buffer_callbacks_t *cb = &__dpdk_buffer_callbacks;
753   if (dpdk_buffer_fill_free_list_avx512 && clib_cpu_supports_avx512f ())
754     {
755       cb->vlib_buffer_fill_free_list_cb = dpdk_buffer_fill_free_list_avx512;
756       cb->vlib_buffer_free_cb = dpdk_buffer_free_avx512;
757       cb->vlib_buffer_free_no_next_cb = dpdk_buffer_free_no_next_avx512;
758     }
759   else if (dpdk_buffer_fill_free_list_avx2 && clib_cpu_supports_avx2 ())
760     {
761       cb->vlib_buffer_fill_free_list_cb = dpdk_buffer_fill_free_list_avx2;
762       cb->vlib_buffer_free_cb = dpdk_buffer_free_avx2;
763       cb->vlib_buffer_free_no_next_cb = dpdk_buffer_free_no_next_avx2;
764     }
765 }
766 #endif
767 #endif
768
769 /** @endcond */
770 /*
771  * fd.io coding-style-patch-verification: ON
772  *
773  * Local Variables:
774  * eval: (c-set-style "gnu")
775  * End:
776  */