Imported Upstream version 16.07-rc1
[deb_dpdk.git] / lib / librte_port / rte_port_kni.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016 Ethan Zhuang <zhuangwj@gmail.com>.
5  *   Copyright(c) 2016 Intel Corporation.
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 #include <string.h>
35
36 #include <rte_common.h>
37 #include <rte_malloc.h>
38 #include <rte_kni.h>
39
40 #include "rte_port_kni.h"
41
42 /*
43  * Port KNI Reader
44  */
45 #ifdef RTE_PORT_STATS_COLLECT
46
47 #define RTE_PORT_KNI_READER_STATS_PKTS_IN_ADD(port, val) \
48         port->stats.n_pkts_in += val
49 #define RTE_PORT_KNI_READER_STATS_PKTS_DROP_ADD(port, val) \
50         port->stats.n_pkts_drop += val
51
52 #else
53
54 #define RTE_PORT_KNI_READER_STATS_PKTS_IN_ADD(port, val)
55 #define RTE_PORT_KNI_READER_STATS_PKTS_DROP_ADD(port, val)
56
57 #endif
58
59 struct rte_port_kni_reader {
60         struct rte_port_in_stats stats;
61
62         struct rte_kni *kni;
63 };
64
65 static void *
66 rte_port_kni_reader_create(void *params, int socket_id)
67 {
68         struct rte_port_kni_reader_params *conf =
69                         (struct rte_port_kni_reader_params *) params;
70         struct rte_port_kni_reader *port;
71
72         /* Check input parameters */
73         if (conf == NULL) {
74                 RTE_LOG(ERR, PORT, "%s: params is NULL\n", __func__);
75                 return NULL;
76         }
77
78         /* Memory allocation */
79         port = rte_zmalloc_socket("PORT", sizeof(*port),
80                 RTE_CACHE_LINE_SIZE, socket_id);
81         if (port == NULL) {
82                 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
83                 return NULL;
84         }
85
86         /* Initialization */
87         port->kni = conf->kni;
88
89         return port;
90 }
91
92 static int
93 rte_port_kni_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
94 {
95         struct rte_port_kni_reader *p =
96                         (struct rte_port_kni_reader *) port;
97         uint16_t rx_pkt_cnt;
98
99         rx_pkt_cnt = rte_kni_rx_burst(p->kni, pkts, n_pkts);
100         RTE_PORT_KNI_READER_STATS_PKTS_IN_ADD(p, rx_pkt_cnt);
101         return rx_pkt_cnt;
102 }
103
104 static int
105 rte_port_kni_reader_free(void *port)
106 {
107         if (port == NULL) {
108                 RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__);
109                 return -EINVAL;
110         }
111
112         rte_free(port);
113
114         return 0;
115 }
116
117 static int rte_port_kni_reader_stats_read(void *port,
118         struct rte_port_in_stats *stats, int clear)
119 {
120         struct rte_port_kni_reader *p =
121                         (struct rte_port_kni_reader *) port;
122
123         if (stats != NULL)
124                 memcpy(stats, &p->stats, sizeof(p->stats));
125
126         if (clear)
127                 memset(&p->stats, 0, sizeof(p->stats));
128
129         return 0;
130 }
131
132 /*
133  * Port KNI Writer
134  */
135 #ifdef RTE_PORT_STATS_COLLECT
136
137 #define RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(port, val) \
138         port->stats.n_pkts_in += val
139 #define RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(port, val) \
140         port->stats.n_pkts_drop += val
141
142 #else
143
144 #define RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(port, val)
145 #define RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(port, val)
146
147 #endif
148
149 struct rte_port_kni_writer {
150         struct rte_port_out_stats stats;
151
152         struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
153         uint32_t tx_burst_sz;
154         uint32_t tx_buf_count;
155         uint64_t bsz_mask;
156         struct rte_kni *kni;
157 };
158
159 static void *
160 rte_port_kni_writer_create(void *params, int socket_id)
161 {
162         struct rte_port_kni_writer_params *conf =
163                         (struct rte_port_kni_writer_params *) params;
164         struct rte_port_kni_writer *port;
165
166         /* Check input parameters */
167         if ((conf == NULL) ||
168                 (conf->tx_burst_sz == 0) ||
169                 (conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
170                 (!rte_is_power_of_2(conf->tx_burst_sz))) {
171                 RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
172                 return NULL;
173         }
174
175         /* Memory allocation */
176         port = rte_zmalloc_socket("PORT", sizeof(*port),
177                 RTE_CACHE_LINE_SIZE, socket_id);
178         if (port == NULL) {
179                 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
180                 return NULL;
181         }
182
183         /* Initialization */
184         port->kni = conf->kni;
185         port->tx_burst_sz = conf->tx_burst_sz;
186         port->tx_buf_count = 0;
187         port->bsz_mask = 1LLU << (conf->tx_burst_sz - 1);
188
189         return port;
190 }
191
192 static inline void
193 send_burst(struct rte_port_kni_writer *p)
194 {
195         uint32_t nb_tx;
196
197         nb_tx = rte_kni_tx_burst(p->kni, p->tx_buf, p->tx_buf_count);
198
199         RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);
200         for (; nb_tx < p->tx_buf_count; nb_tx++)
201                 rte_pktmbuf_free(p->tx_buf[nb_tx]);
202
203         p->tx_buf_count = 0;
204 }
205
206 static int
207 rte_port_kni_writer_tx(void *port, struct rte_mbuf *pkt)
208 {
209         struct rte_port_kni_writer *p =
210                         (struct rte_port_kni_writer *) port;
211
212         p->tx_buf[p->tx_buf_count++] = pkt;
213         RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, 1);
214         if (p->tx_buf_count >= p->tx_burst_sz)
215                 send_burst(p);
216
217         return 0;
218 }
219
220 static int
221 rte_port_kni_writer_tx_bulk(void *port,
222         struct rte_mbuf **pkts,
223         uint64_t pkts_mask)
224 {
225         struct rte_port_kni_writer *p =
226                         (struct rte_port_kni_writer *) port;
227         uint64_t bsz_mask = p->bsz_mask;
228         uint32_t tx_buf_count = p->tx_buf_count;
229         uint64_t expr = (pkts_mask & (pkts_mask + 1)) |
230                                         ((pkts_mask & bsz_mask) ^ bsz_mask);
231
232         if (expr == 0) {
233                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
234                 uint32_t n_pkts_ok;
235
236                 if (tx_buf_count)
237                         send_burst(p);
238
239                 RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, n_pkts);
240                 n_pkts_ok = rte_kni_tx_burst(p->kni, pkts, n_pkts);
241
242                 RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(p, n_pkts - n_pkts_ok);
243                 for (; n_pkts_ok < n_pkts; n_pkts_ok++) {
244                         struct rte_mbuf *pkt = pkts[n_pkts_ok];
245
246                         rte_pktmbuf_free(pkt);
247                 }
248         } else {
249                 for (; pkts_mask;) {
250                         uint32_t pkt_index = __builtin_ctzll(pkts_mask);
251                         uint64_t pkt_mask = 1LLU << pkt_index;
252                         struct rte_mbuf *pkt = pkts[pkt_index];
253
254                         p->tx_buf[tx_buf_count++] = pkt;
255                         RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, 1);
256                         pkts_mask &= ~pkt_mask;
257                 }
258
259                 p->tx_buf_count = tx_buf_count;
260                 if (tx_buf_count >= p->tx_burst_sz)
261                         send_burst(p);
262         }
263
264         return 0;
265 }
266
267 static int
268 rte_port_kni_writer_flush(void *port)
269 {
270         struct rte_port_kni_writer *p =
271                         (struct rte_port_kni_writer *) port;
272
273         if (p->tx_buf_count > 0)
274                 send_burst(p);
275
276         return 0;
277 }
278
279 static int
280 rte_port_kni_writer_free(void *port)
281 {
282         if (port == NULL) {
283                 RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
284                 return -EINVAL;
285         }
286
287         rte_port_kni_writer_flush(port);
288         rte_free(port);
289
290         return 0;
291 }
292
293 static int rte_port_kni_writer_stats_read(void *port,
294         struct rte_port_out_stats *stats, int clear)
295 {
296         struct rte_port_kni_writer *p =
297                         (struct rte_port_kni_writer *) port;
298
299         if (stats != NULL)
300                 memcpy(stats, &p->stats, sizeof(p->stats));
301
302         if (clear)
303                 memset(&p->stats, 0, sizeof(p->stats));
304
305         return 0;
306 }
307
308 /*
309  * Port KNI Writer Nodrop
310  */
311 #ifdef RTE_PORT_STATS_COLLECT
312
313 #define RTE_PORT_KNI_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val) \
314         port->stats.n_pkts_in += val
315 #define RTE_PORT_KNI_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val) \
316         port->stats.n_pkts_drop += val
317
318 #else
319
320 #define RTE_PORT_KNI_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val)
321 #define RTE_PORT_KNI_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val)
322
323 #endif
324
325 struct rte_port_kni_writer_nodrop {
326         struct rte_port_out_stats stats;
327
328         struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
329         uint32_t tx_burst_sz;
330         uint32_t tx_buf_count;
331         uint64_t bsz_mask;
332         uint64_t n_retries;
333         struct rte_kni *kni;
334 };
335
336 static void *
337 rte_port_kni_writer_nodrop_create(void *params, int socket_id)
338 {
339         struct rte_port_kni_writer_nodrop_params *conf =
340                 (struct rte_port_kni_writer_nodrop_params *) params;
341         struct rte_port_kni_writer_nodrop *port;
342
343         /* Check input parameters */
344         if ((conf == NULL) ||
345                 (conf->tx_burst_sz == 0) ||
346                 (conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
347                 (!rte_is_power_of_2(conf->tx_burst_sz))) {
348                 RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
349                 return NULL;
350         }
351
352         /* Memory allocation */
353         port = rte_zmalloc_socket("PORT", sizeof(*port),
354                 RTE_CACHE_LINE_SIZE, socket_id);
355         if (port == NULL) {
356                 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
357                 return NULL;
358         }
359
360         /* Initialization */
361         port->kni = conf->kni;
362         port->tx_burst_sz = conf->tx_burst_sz;
363         port->tx_buf_count = 0;
364         port->bsz_mask = 1LLU << (conf->tx_burst_sz - 1);
365
366         /*
367          * When n_retries is 0 it means that we should wait for every packet to
368          * send no matter how many retries should it take. To limit number of
369          * branches in fast path, we use UINT64_MAX instead of branching.
370          */
371         port->n_retries = (conf->n_retries == 0) ? UINT64_MAX : conf->n_retries;
372
373         return port;
374 }
375
376 static inline void
377 send_burst_nodrop(struct rte_port_kni_writer_nodrop *p)
378 {
379         uint32_t nb_tx = 0, i;
380
381         nb_tx = rte_kni_tx_burst(p->kni, p->tx_buf, p->tx_buf_count);
382
383         /* We sent all the packets in a first try */
384         if (nb_tx >= p->tx_buf_count) {
385                 p->tx_buf_count = 0;
386                 return;
387         }
388
389         for (i = 0; i < p->n_retries; i++) {
390                 nb_tx += rte_kni_tx_burst(p->kni,
391                         p->tx_buf + nb_tx,
392                         p->tx_buf_count - nb_tx);
393
394                 /* We sent all the packets in more than one try */
395                 if (nb_tx >= p->tx_buf_count) {
396                         p->tx_buf_count = 0;
397                         return;
398                 }
399         }
400
401         /* We didn't send the packets in maximum allowed attempts */
402         RTE_PORT_KNI_WRITER_NODROP_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);
403         for ( ; nb_tx < p->tx_buf_count; nb_tx++)
404                 rte_pktmbuf_free(p->tx_buf[nb_tx]);
405
406         p->tx_buf_count = 0;
407 }
408
409 static int
410 rte_port_kni_writer_nodrop_tx(void *port, struct rte_mbuf *pkt)
411 {
412         struct rte_port_kni_writer_nodrop *p =
413                         (struct rte_port_kni_writer_nodrop *) port;
414
415         p->tx_buf[p->tx_buf_count++] = pkt;
416         RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, 1);
417         if (p->tx_buf_count >= p->tx_burst_sz)
418                 send_burst_nodrop(p);
419
420         return 0;
421 }
422
423 static int
424 rte_port_kni_writer_nodrop_tx_bulk(void *port,
425         struct rte_mbuf **pkts,
426         uint64_t pkts_mask)
427 {
428         struct rte_port_kni_writer_nodrop *p =
429                         (struct rte_port_kni_writer_nodrop *) port;
430
431         uint64_t bsz_mask = p->bsz_mask;
432         uint32_t tx_buf_count = p->tx_buf_count;
433         uint64_t expr = (pkts_mask & (pkts_mask + 1)) |
434                                         ((pkts_mask & bsz_mask) ^ bsz_mask);
435
436         if (expr == 0) {
437                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
438                 uint32_t n_pkts_ok;
439
440                 if (tx_buf_count)
441                         send_burst_nodrop(p);
442
443                 RTE_PORT_KNI_WRITER_NODROP_STATS_PKTS_IN_ADD(p, n_pkts);
444                 n_pkts_ok = rte_kni_tx_burst(p->kni, pkts, n_pkts);
445
446                 if (n_pkts_ok >= n_pkts)
447                         return 0;
448
449                 /*
450                  * If we didn't manage to send all packets in single burst, move
451                  * remaining packets to the buffer and call send burst.
452                  */
453                 for (; n_pkts_ok < n_pkts; n_pkts_ok++) {
454                         struct rte_mbuf *pkt = pkts[n_pkts_ok];
455                         p->tx_buf[p->tx_buf_count++] = pkt;
456                 }
457                 send_burst_nodrop(p);
458         } else {
459                 for ( ; pkts_mask; ) {
460                         uint32_t pkt_index = __builtin_ctzll(pkts_mask);
461                         uint64_t pkt_mask = 1LLU << pkt_index;
462                         struct rte_mbuf *pkt = pkts[pkt_index];
463
464                         p->tx_buf[tx_buf_count++] = pkt;
465                         RTE_PORT_KNI_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
466                         pkts_mask &= ~pkt_mask;
467                 }
468
469                 p->tx_buf_count = tx_buf_count;
470                 if (tx_buf_count >= p->tx_burst_sz)
471                         send_burst_nodrop(p);
472         }
473
474         return 0;
475 }
476
477 static int
478 rte_port_kni_writer_nodrop_flush(void *port)
479 {
480         struct rte_port_kni_writer_nodrop *p =
481                 (struct rte_port_kni_writer_nodrop *) port;
482
483         if (p->tx_buf_count > 0)
484                 send_burst_nodrop(p);
485
486         return 0;
487 }
488
489 static int
490 rte_port_kni_writer_nodrop_free(void *port)
491 {
492         if (port == NULL) {
493                 RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
494                 return -EINVAL;
495         }
496
497         rte_port_kni_writer_nodrop_flush(port);
498         rte_free(port);
499
500         return 0;
501 }
502
503 static int rte_port_kni_writer_nodrop_stats_read(void *port,
504         struct rte_port_out_stats *stats, int clear)
505 {
506         struct rte_port_kni_writer_nodrop *p =
507                         (struct rte_port_kni_writer_nodrop *) port;
508
509         if (stats != NULL)
510                 memcpy(stats, &p->stats, sizeof(p->stats));
511
512         if (clear)
513                 memset(&p->stats, 0, sizeof(p->stats));
514
515         return 0;
516 }
517
518
519 /*
520  * Summary of port operations
521  */
522 struct rte_port_in_ops rte_port_kni_reader_ops = {
523         .f_create = rte_port_kni_reader_create,
524         .f_free = rte_port_kni_reader_free,
525         .f_rx = rte_port_kni_reader_rx,
526         .f_stats = rte_port_kni_reader_stats_read,
527 };
528
529 struct rte_port_out_ops rte_port_kni_writer_ops = {
530         .f_create = rte_port_kni_writer_create,
531         .f_free = rte_port_kni_writer_free,
532         .f_tx = rte_port_kni_writer_tx,
533         .f_tx_bulk = rte_port_kni_writer_tx_bulk,
534         .f_flush = rte_port_kni_writer_flush,
535         .f_stats = rte_port_kni_writer_stats_read,
536 };
537
538 struct rte_port_out_ops rte_port_kni_writer_nodrop_ops = {
539         .f_create = rte_port_kni_writer_nodrop_create,
540         .f_free = rte_port_kni_writer_nodrop_free,
541         .f_tx = rte_port_kni_writer_nodrop_tx,
542         .f_tx_bulk = rte_port_kni_writer_nodrop_tx_bulk,
543         .f_flush = rte_port_kni_writer_nodrop_flush,
544         .f_stats = rte_port_kni_writer_nodrop_stats_read,
545 };