dpdk: check result of rte_mempool_create_empty
[vpp.git] / src / plugins / dpdk / buffer.c
1 /*
2  * Copyright (c) 2017-2019 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 #include <unistd.h>
17 #include <errno.h>
18
19 #include <rte_config.h>
20 #include <rte_mbuf.h>
21 #include <rte_ethdev.h>
22 #include <rte_vfio.h>
23
24 #include <vlib/vlib.h>
25 #include <dpdk/buffer.h>
26
27 STATIC_ASSERT (VLIB_BUFFER_PRE_DATA_SIZE == RTE_PKTMBUF_HEADROOM,
28                "VLIB_BUFFER_PRE_DATA_SIZE must be equal to RTE_PKTMBUF_HEADROOM");
29
30 #ifndef CLIB_MARCH_VARIANT
31 struct rte_mempool **dpdk_mempool_by_buffer_pool_index = 0;
32 struct rte_mempool **dpdk_no_cache_mempool_by_buffer_pool_index = 0;
33
34 clib_error_t *
35 dpdk_buffer_pool_init (vlib_main_t * vm, vlib_buffer_pool_t * bp)
36 {
37   uword buffer_mem_start = vm->buffer_main->buffer_mem_start;
38   struct rte_mempool *mp, *nmp;
39   struct rte_pktmbuf_pool_private priv;
40   enum rte_iova_mode iova_mode;
41   u32 *bi;
42   u8 *name = 0;
43
44   u32 elt_size =
45     sizeof (struct rte_mbuf) + sizeof (vlib_buffer_t) + bp->data_size;
46
47   /* create empty mempools */
48   vec_validate_aligned (dpdk_mempool_by_buffer_pool_index, bp->index,
49                         CLIB_CACHE_LINE_BYTES);
50   vec_validate_aligned (dpdk_no_cache_mempool_by_buffer_pool_index, bp->index,
51                         CLIB_CACHE_LINE_BYTES);
52
53   /* normal mempool */
54   name = format (name, "vpp pool %u%c", bp->index, 0);
55   mp = rte_mempool_create_empty ((char *) name, vec_len (bp->buffers),
56                                  elt_size, 512, sizeof (priv),
57                                  bp->numa_node, 0);
58   if (!mp)
59     {
60       vec_free (name);
61       return clib_error_return (0,
62                                 "failed to create normal mempool for numa node %u",
63                                 bp->index);
64     }
65   vec_reset_length (name);
66
67   /* non-cached mempool */
68   name = format (name, "vpp pool %u (no cache)%c", bp->index, 0);
69   nmp = rte_mempool_create_empty ((char *) name, vec_len (bp->buffers),
70                                   elt_size, 0, sizeof (priv),
71                                   bp->numa_node, 0);
72   if (!nmp)
73     {
74       rte_mempool_free (mp);
75       vec_free (name);
76       return clib_error_return (0,
77                                 "failed to create non-cache mempool for numa nude %u",
78                                 bp->index);
79     }
80   vec_free (name);
81
82   dpdk_mempool_by_buffer_pool_index[bp->index] = mp;
83   dpdk_no_cache_mempool_by_buffer_pool_index[bp->index] = nmp;
84
85   mp->pool_id = nmp->pool_id = bp->index;
86
87   rte_mempool_set_ops_byname (mp, "vpp", NULL);
88   rte_mempool_set_ops_byname (nmp, "vpp-no-cache", NULL);
89
90   /* Call the mempool priv initializer */
91   priv.mbuf_data_room_size = VLIB_BUFFER_PRE_DATA_SIZE +
92     vlib_buffer_get_default_data_size (vm);
93   priv.mbuf_priv_size = VLIB_BUFFER_HDR_SIZE;
94   rte_pktmbuf_pool_init (mp, &priv);
95   rte_pktmbuf_pool_init (nmp, &priv);
96
97   iova_mode = rte_eal_iova_mode ();
98
99   /* populate mempool object buffer header */
100   /* *INDENT-OFF* */
101   vec_foreach (bi, bp->buffers)
102     {
103       struct rte_mempool_objhdr *hdr;
104       vlib_buffer_t *b = vlib_get_buffer (vm, *bi);
105       struct rte_mbuf *mb = rte_mbuf_from_vlib_buffer (b);
106       hdr = (struct rte_mempool_objhdr *) RTE_PTR_SUB (mb, sizeof (*hdr));
107       hdr->mp = mp;
108       hdr->iova = (iova_mode == RTE_IOVA_VA) ?
109         pointer_to_uword (mb) : vlib_physmem_get_pa (vm, mb);
110       STAILQ_INSERT_TAIL (&mp->elt_list, hdr, next);
111       STAILQ_INSERT_TAIL (&nmp->elt_list, hdr, next);
112       mp->populated_size++;
113       nmp->populated_size++;
114     }
115   /* *INDENT-ON* */
116
117   /* call the object initializers */
118   rte_mempool_obj_iter (mp, rte_pktmbuf_init, 0);
119
120   /* *INDENT-OFF* */
121   vec_foreach (bi, bp->buffers)
122     {
123       vlib_buffer_t *b;
124       b = vlib_buffer_ptr_from_index (buffer_mem_start, *bi, 0);
125       vlib_buffer_copy_template (b, &bp->buffer_template);
126     }
127   /* *INDENT-ON* */
128
129   /* map DMA pages if at least one physical device exists */
130   if (rte_eth_dev_count_avail ())
131     {
132       uword i;
133       size_t page_sz;
134       vlib_physmem_map_t *pm;
135       int do_vfio_map = 1;
136
137       pm = vlib_physmem_get_map (vm, bp->physmem_map_index);
138       page_sz = 1ULL << pm->log2_page_size;
139
140       for (i = 0; i < pm->n_pages; i++)
141         {
142           char *va = ((char *) pm->base) + i * page_sz;
143           uword pa = (iova_mode == RTE_IOVA_VA) ?
144             pointer_to_uword (va) : pm->page_table[i];
145
146           if (do_vfio_map &&
147               rte_vfio_dma_map (pointer_to_uword (va), pa, page_sz))
148             do_vfio_map = 0;
149
150           struct rte_mempool_memhdr *memhdr;
151           memhdr = clib_mem_alloc (sizeof (*memhdr));
152           memhdr->mp = mp;
153           memhdr->addr = va;
154           memhdr->iova = pa;
155           memhdr->len = page_sz;
156           memhdr->free_cb = 0;
157           memhdr->opaque = 0;
158
159           STAILQ_INSERT_TAIL (&mp->mem_list, memhdr, next);
160           mp->nb_mem_chunks++;
161         }
162     }
163
164   return 0;
165 }
166
167 static int
168 dpdk_ops_vpp_alloc (struct rte_mempool *mp)
169 {
170   clib_warning ("");
171   return 0;
172 }
173
174 static void
175 dpdk_ops_vpp_free (struct rte_mempool *mp)
176 {
177   clib_warning ("");
178 }
179
180 #endif
181
182 static_always_inline void
183 dpdk_ops_vpp_enqueue_one (vlib_buffer_t * bt, void *obj)
184 {
185   /* Only non-replicated packets (b->ref_count == 1) expected */
186
187   struct rte_mbuf *mb = obj;
188   vlib_buffer_t *b = vlib_buffer_from_rte_mbuf (mb);
189   ASSERT (b->ref_count == 1);
190   ASSERT (b->buffer_pool_index == bt->buffer_pool_index);
191   vlib_buffer_copy_template (b, bt);
192 }
193
194 int
195 CLIB_MULTIARCH_FN (dpdk_ops_vpp_enqueue) (struct rte_mempool * mp,
196                                           void *const *obj_table, unsigned n)
197 {
198   const int batch_size = 32;
199   vlib_main_t *vm = vlib_get_main ();
200   vlib_buffer_t bt;
201   u8 buffer_pool_index = mp->pool_id;
202   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
203   u32 bufs[batch_size];
204   u32 n_left = n;
205   void *const *obj = obj_table;
206
207   vlib_buffer_copy_template (&bt, &bp->buffer_template);
208
209   while (n_left >= 4)
210     {
211       dpdk_ops_vpp_enqueue_one (&bt, obj[0]);
212       dpdk_ops_vpp_enqueue_one (&bt, obj[1]);
213       dpdk_ops_vpp_enqueue_one (&bt, obj[2]);
214       dpdk_ops_vpp_enqueue_one (&bt, obj[3]);
215       obj += 4;
216       n_left -= 4;
217     }
218
219   while (n_left)
220     {
221       dpdk_ops_vpp_enqueue_one (&bt, obj[0]);
222       obj += 1;
223       n_left -= 1;
224     }
225
226   while (n >= batch_size)
227     {
228       vlib_get_buffer_indices_with_offset (vm, (void **) obj_table, bufs,
229                                            batch_size,
230                                            sizeof (struct rte_mbuf));
231       vlib_buffer_pool_put (vm, buffer_pool_index, bufs, batch_size);
232       n -= batch_size;
233       obj_table += batch_size;
234     }
235
236   if (n)
237     {
238       vlib_get_buffer_indices_with_offset (vm, (void **) obj_table, bufs,
239                                            n, sizeof (struct rte_mbuf));
240       vlib_buffer_pool_put (vm, buffer_pool_index, bufs, n);
241     }
242
243   return 0;
244 }
245
246 CLIB_MARCH_FN_REGISTRATION (dpdk_ops_vpp_enqueue);
247
248 static_always_inline void
249 dpdk_ops_vpp_enqueue_no_cache_one (vlib_main_t * vm, struct rte_mempool *old,
250                                    struct rte_mempool *new, void *obj,
251                                    vlib_buffer_t * bt)
252 {
253   struct rte_mbuf *mb = obj;
254   vlib_buffer_t *b = vlib_buffer_from_rte_mbuf (mb);
255
256   if (clib_atomic_sub_fetch (&b->ref_count, 1) == 0)
257     {
258       u32 bi = vlib_get_buffer_index (vm, b);
259       mb->pool = new;
260       vlib_buffer_copy_template (b, bt);
261       vlib_buffer_pool_put (vm, bt->buffer_pool_index, &bi, 1);
262       return;
263     }
264 }
265
266 int
267 CLIB_MULTIARCH_FN (dpdk_ops_vpp_enqueue_no_cache) (struct rte_mempool * cmp,
268                                                    void *const *obj_table,
269                                                    unsigned n)
270 {
271   vlib_main_t *vm = vlib_get_main ();
272   vlib_buffer_t bt;
273   struct rte_mempool *mp;
274   mp = dpdk_mempool_by_buffer_pool_index[cmp->pool_id];
275   u8 buffer_pool_index = cmp->pool_id;
276   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
277   vlib_buffer_copy_template (&bt, &bp->buffer_template);
278
279   while (n >= 4)
280     {
281       dpdk_ops_vpp_enqueue_no_cache_one (vm, cmp, mp, obj_table[0], &bt);
282       dpdk_ops_vpp_enqueue_no_cache_one (vm, cmp, mp, obj_table[1], &bt);
283       dpdk_ops_vpp_enqueue_no_cache_one (vm, cmp, mp, obj_table[2], &bt);
284       dpdk_ops_vpp_enqueue_no_cache_one (vm, cmp, mp, obj_table[3], &bt);
285       obj_table += 4;
286       n -= 4;
287     }
288
289   while (n)
290     {
291       dpdk_ops_vpp_enqueue_no_cache_one (vm, cmp, mp, obj_table[0], &bt);
292       obj_table += 1;
293       n -= 1;
294     }
295
296   return 0;
297 }
298
299 CLIB_MARCH_FN_REGISTRATION (dpdk_ops_vpp_enqueue_no_cache);
300
301 int
302 CLIB_MULTIARCH_FN (dpdk_ops_vpp_dequeue) (struct rte_mempool * mp,
303                                           void **obj_table, unsigned n)
304 {
305   const int batch_size = 32;
306   vlib_main_t *vm = vlib_get_main ();
307   u32 bufs[batch_size], total = 0, n_alloc = 0;
308   u8 buffer_pool_index = mp->pool_id;
309   void **obj = obj_table;
310
311   while (n >= batch_size)
312     {
313       n_alloc = vlib_buffer_alloc_from_pool (vm, bufs, batch_size,
314                                              buffer_pool_index);
315       if (n_alloc != batch_size)
316         goto alloc_fail;
317
318       vlib_get_buffers_with_offset (vm, bufs, obj, batch_size,
319                                     -(i32) sizeof (struct rte_mbuf));
320       total += batch_size;
321       obj += batch_size;
322       n -= batch_size;
323     }
324
325   if (n)
326     {
327       n_alloc = vlib_buffer_alloc_from_pool (vm, bufs, n, buffer_pool_index);
328
329       if (n_alloc != n)
330         goto alloc_fail;
331
332       vlib_get_buffers_with_offset (vm, bufs, obj, n,
333                                     -(i32) sizeof (struct rte_mbuf));
334     }
335
336   return 0;
337
338 alloc_fail:
339   /* dpdk doesn't support partial alloc, so we need to return what we
340      already got */
341   if (n_alloc)
342     vlib_buffer_pool_put (vm, buffer_pool_index, bufs, n_alloc);
343   obj = obj_table;
344   while (total)
345     {
346       vlib_get_buffer_indices_with_offset (vm, obj, bufs, batch_size,
347                                            sizeof (struct rte_mbuf));
348       vlib_buffer_pool_put (vm, buffer_pool_index, bufs, batch_size);
349
350       obj += batch_size;
351       total -= batch_size;
352     }
353   return -ENOENT;
354 }
355
356 CLIB_MARCH_FN_REGISTRATION (dpdk_ops_vpp_dequeue);
357
358 #ifndef CLIB_MARCH_VARIANT
359
360 static int
361 dpdk_ops_vpp_dequeue_no_cache (struct rte_mempool *mp, void **obj_table,
362                                unsigned n)
363 {
364   clib_error ("bug");
365   return 0;
366 }
367
368 static unsigned
369 dpdk_ops_vpp_get_count (const struct rte_mempool *mp)
370 {
371   clib_warning ("");
372   return 0;
373 }
374
375 static unsigned
376 dpdk_ops_vpp_get_count_no_cache (const struct rte_mempool *mp)
377 {
378   struct rte_mempool *cmp;
379   cmp = dpdk_no_cache_mempool_by_buffer_pool_index[mp->pool_id];
380   return dpdk_ops_vpp_get_count (cmp);
381 }
382
383 clib_error_t *
384 dpdk_buffer_pools_create (vlib_main_t * vm)
385 {
386   clib_error_t *err;
387   vlib_buffer_pool_t *bp;
388
389   struct rte_mempool_ops ops = { };
390
391   strncpy (ops.name, "vpp", 4);
392   ops.alloc = dpdk_ops_vpp_alloc;
393   ops.free = dpdk_ops_vpp_free;
394   ops.get_count = dpdk_ops_vpp_get_count;
395   ops.enqueue = CLIB_MARCH_FN_POINTER (dpdk_ops_vpp_enqueue);
396   ops.dequeue = CLIB_MARCH_FN_POINTER (dpdk_ops_vpp_dequeue);
397   rte_mempool_register_ops (&ops);
398
399   strncpy (ops.name, "vpp-no-cache", 13);
400   ops.get_count = dpdk_ops_vpp_get_count_no_cache;
401   ops.enqueue = CLIB_MARCH_FN_POINTER (dpdk_ops_vpp_enqueue_no_cache);
402   ops.dequeue = dpdk_ops_vpp_dequeue_no_cache;
403   rte_mempool_register_ops (&ops);
404
405   /* *INDENT-OFF* */
406   vec_foreach (bp, vm->buffer_main->buffer_pools)
407     if (bp->start && (err = dpdk_buffer_pool_init (vm, bp)))
408       return err;
409   /* *INDENT-ON* */
410   return 0;
411 }
412
413 VLIB_BUFFER_SET_EXT_HDR_SIZE (sizeof (struct rte_mempool_objhdr) +
414                               sizeof (struct rte_mbuf));
415
416 #endif
417
418 /** @endcond */
419 /*
420  * fd.io coding-style-patch-verification: ON
421  *
422  * Local Variables:
423  * eval: (c-set-style "gnu")
424  * End:
425  */