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