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