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