vppinfra: explicitely state for signed types that they are signed
[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_MARCH_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_MARCH_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   dpdk_mempool_private_t priv;
492   clib_error_t *error = 0;
493   u32 size, obj_size;
494   i32 ret;
495
496   obj_size = rte_mempool_calc_obj_size (elt_size, 0, 0);
497   size = rte_mempool_xmem_size (num_elts, obj_size, 21, 0);
498
499   error =
500     vlib_physmem_region_alloc (vm, (char *) pool_name, size, numa,
501                                VLIB_PHYSMEM_F_HUGETLB | VLIB_PHYSMEM_F_SHARED,
502                                pri);
503   if (error)
504     return error;
505
506   pr = vlib_physmem_get_region (vm, pri[0]);
507
508   mp =
509     rte_mempool_create_empty ((char *) pool_name, num_elts, elt_size,
510                               512, pool_priv_size, numa, 0);
511   if (!mp)
512     return clib_error_return (0, "failed to create %s", pool_name);
513
514   rte_mempool_set_ops_byname (mp, RTE_MBUF_DEFAULT_MEMPOOL_OPS, NULL);
515
516   /* Call the mempool priv initializer */
517   priv.mbp_priv.mbuf_data_room_size = VLIB_BUFFER_PRE_DATA_SIZE +
518     VLIB_BUFFER_DATA_SIZE;
519   priv.mbp_priv.mbuf_priv_size = VLIB_BUFFER_HDR_SIZE;
520   rte_pktmbuf_pool_init (mp, &priv);
521
522   ret =
523     rte_mempool_populate_iova_tab (mp, pr->mem, pr->page_table, pr->n_pages,
524                                    pr->log2_page_size, NULL, NULL);
525   if (ret != (i32) mp->size)
526     {
527       rte_mempool_free (mp);
528       return clib_error_return (0, "failed to populate %s", pool_name);
529     }
530
531   _mp[0] = mp;
532
533   /* DPDK currently doesn't provide API to map DMA memory for empty mempool
534      so we are using this hack, will be nice to have at least API to get
535      VFIO container FD */
536   if (dbm->vfio_container_fd == -1)
537     foreach_directory_file ("/proc/self/fd", scan_vfio_fd, 0, 0);
538
539   if (dbm->vfio_container_fd != -1)
540     {
541       struct vfio_iommu_type1_dma_map dm = { 0 };
542       int i, rv = 0;
543       dm.argsz = sizeof (struct vfio_iommu_type1_dma_map);
544       dm.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
545
546       /* *INDENT-OFF* */
547       vec_foreach_index (i, pr->page_table)
548         {
549           dm.vaddr = pointer_to_uword (pr->mem) + (i << pr->log2_page_size);
550           dm.size = 1 << pr->log2_page_size;
551           dm.iova = pr->page_table[i];
552           if ((rv = ioctl (dbm->vfio_container_fd, VFIO_IOMMU_MAP_DMA, &dm)))
553             break;
554         }
555       /* *INDENT-ON* */
556       if (rv != 0 && errno != EINVAL)
557         clib_unix_warning ("ioctl(VFIO_IOMMU_MAP_DMA) pool '%s'", pool_name);
558     }
559
560   return 0;
561 }
562
563 clib_error_t *
564 dpdk_buffer_pool_create (vlib_main_t * vm, unsigned num_mbufs,
565                          unsigned socket_id)
566 {
567   dpdk_main_t *dm = &dpdk_main;
568   struct rte_mempool *rmp;
569   vlib_physmem_region_index_t pri;
570   clib_error_t *error = 0;
571   u8 *pool_name;
572   u32 elt_size, i;
573
574   vec_validate_aligned (dm->pktmbuf_pools, socket_id, CLIB_CACHE_LINE_BYTES);
575
576   /* pool already exists, nothing to do */
577   if (dm->pktmbuf_pools[socket_id])
578     return 0;
579
580   pool_name = format (0, "dpdk_mbuf_pool_socket%u%c", socket_id, 0);
581
582   elt_size = sizeof (struct rte_mbuf) +
583     VLIB_BUFFER_HDR_SIZE /* priv size */  +
584     VLIB_BUFFER_PRE_DATA_SIZE + VLIB_BUFFER_DATA_SIZE;  /*data room size */
585
586   error =
587     dpdk_pool_create (vm, pool_name, elt_size, num_mbufs,
588                       sizeof (dpdk_mempool_private_t), 512, socket_id,
589                       &rmp, &pri);
590
591   vec_free (pool_name);
592
593   if (!error)
594     {
595       /* call the object initializers */
596       rte_mempool_obj_iter (rmp, rte_pktmbuf_init, 0);
597
598       dpdk_mempool_private_t *privp = rte_mempool_get_priv (rmp);
599       privp->buffer_pool_index = vlib_buffer_pool_create (vm, pri, 0);
600
601       dm->pktmbuf_pools[socket_id] = rmp;
602
603       return 0;
604     }
605
606   clib_error_report (error);
607
608   /* no usable pool for this socket, try to use pool from another one */
609   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
610     {
611       if (dm->pktmbuf_pools[i])
612         {
613           clib_warning ("WARNING: Failed to allocate mempool for CPU socket "
614                         "%u. Threads running on socket %u will use socket %u "
615                         "mempool.", socket_id, socket_id, i);
616           dm->pktmbuf_pools[socket_id] = dm->pktmbuf_pools[i];
617           return 0;
618         }
619     }
620
621   return clib_error_return (0, "failed to allocate mempool on socket %u",
622                             socket_id);
623 }
624
625 #if CLIB_DEBUG > 0
626
627 u32 *vlib_buffer_state_validation_lock;
628 uword *vlib_buffer_state_validation_hash;
629 void *vlib_buffer_state_heap;
630
631 static clib_error_t *
632 buffer_state_validation_init (vlib_main_t * vm)
633 {
634   void *oldheap;
635
636   vlib_buffer_state_heap = mheap_alloc (0, 10 << 20);
637
638   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
639
640   vlib_buffer_state_validation_hash = hash_create (0, sizeof (uword));
641   vec_validate_aligned (vlib_buffer_state_validation_lock, 0,
642                         CLIB_CACHE_LINE_BYTES);
643   clib_mem_set_heap (oldheap);
644   return 0;
645 }
646
647 VLIB_INIT_FUNCTION (buffer_state_validation_init);
648 #endif
649
650 #if CLI_DEBUG
651 struct dpdk_validate_buf_result
652 {
653   u32 invalid;
654   u32 uninitialized;
655 };
656
657 #define DPDK_TRAJECTORY_POISON 31
658
659 static void
660 dpdk_buffer_validate_trajectory (struct rte_mempool *mp, void *opaque,
661                                  void *obj, unsigned obj_idx)
662 {
663   vlib_buffer_t *b;
664   struct dpdk_validate_buf_result *counter = opaque;
665   b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
666   if (b->pre_data[0] != 0)
667     {
668       if (b->pre_data[0] == DPDK_TRAJECTORY_POISON)
669         counter->uninitialized++;
670       else
671         counter->invalid++;
672     }
673 }
674
675 int
676 dpdk_buffer_validate_trajectory_all (u32 * uninitialized)
677 {
678   dpdk_main_t *dm = &dpdk_main;
679   struct dpdk_validate_buf_result counter = { 0 };
680   int i;
681
682   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
683     rte_mempool_obj_iter (dm->pktmbuf_pools[i],
684                           dpdk_buffer_validate_trajectory, &counter);
685   if (uninitialized)
686     *uninitialized = counter.uninitialized;
687   return counter.invalid;
688 }
689
690 static void
691 dpdk_buffer_poison_trajectory (struct rte_mempool *mp, void *opaque,
692                                void *obj, unsigned obj_idx)
693 {
694   vlib_buffer_t *b;
695   b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
696   b->pre_data[0] = DPDK_TRAJECTORY_POISON;
697 }
698
699 void
700 dpdk_buffer_poison_trajectory_all (void)
701 {
702   dpdk_main_t *dm = &dpdk_main;
703   int i;
704
705   for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
706     rte_mempool_obj_iter (dm->pktmbuf_pools[i], dpdk_buffer_poison_trajectory,
707                           0);
708 }
709 #endif
710
711 static clib_error_t *
712 dpdk_buffer_init (vlib_main_t * vm)
713 {
714   dpdk_buffer_main_t *dbm = &dpdk_buffer_main;
715   vlib_thread_main_t *tm = vlib_get_thread_main ();
716
717   vec_validate_aligned (dbm->ptd, tm->n_vlib_mains - 1,
718                         CLIB_CACHE_LINE_BYTES);
719
720   dbm->vfio_container_fd = -1;
721
722   return 0;
723 }
724
725 VLIB_INIT_FUNCTION (dpdk_buffer_init);
726
727 /* *INDENT-OFF* */
728 VLIB_BUFFER_REGISTER_CALLBACKS (dpdk, static) = {
729   .vlib_buffer_fill_free_list_cb = &dpdk_buffer_fill_free_list,
730   .vlib_buffer_free_cb = &dpdk_buffer_free,
731   .vlib_buffer_free_no_next_cb = &dpdk_buffer_free_no_next,
732   .vlib_packet_template_init_cb = &dpdk_packet_template_init,
733   .vlib_buffer_delete_free_list_cb = &dpdk_buffer_delete_free_list,
734 };
735 /* *INDENT-ON* */
736
737 #if __x86_64__
738 vlib_buffer_fill_free_list_cb_t __clib_weak dpdk_buffer_fill_free_list_avx512;
739 vlib_buffer_fill_free_list_cb_t __clib_weak dpdk_buffer_fill_free_list_avx2;
740 vlib_buffer_free_cb_t __clib_weak dpdk_buffer_free_avx512;
741 vlib_buffer_free_cb_t __clib_weak dpdk_buffer_free_avx2;
742 vlib_buffer_free_no_next_cb_t __clib_weak dpdk_buffer_free_no_next_avx512;
743 vlib_buffer_free_no_next_cb_t __clib_weak dpdk_buffer_free_no_next_avx2;
744
745 static void __clib_constructor
746 dpdk_input_multiarch_select (void)
747 {
748   vlib_buffer_callbacks_t *cb = &__dpdk_buffer_callbacks;
749   if (dpdk_buffer_fill_free_list_avx512 && clib_cpu_supports_avx512f ())
750     {
751       cb->vlib_buffer_fill_free_list_cb = dpdk_buffer_fill_free_list_avx512;
752       cb->vlib_buffer_free_cb = dpdk_buffer_free_avx512;
753       cb->vlib_buffer_free_no_next_cb = dpdk_buffer_free_no_next_avx512;
754     }
755   else if (dpdk_buffer_fill_free_list_avx2 && clib_cpu_supports_avx2 ())
756     {
757       cb->vlib_buffer_fill_free_list_cb = dpdk_buffer_fill_free_list_avx2;
758       cb->vlib_buffer_free_cb = dpdk_buffer_free_avx2;
759       cb->vlib_buffer_free_no_next_cb = dpdk_buffer_free_no_next_avx2;
760     }
761 }
762 #endif
763 #endif
764
765 /** @endcond */
766 /*
767  * fd.io coding-style-patch-verification: ON
768  *
769  * Local Variables:
770  * eval: (c-set-style "gnu")
771  * End:
772  */