3d4e8d9efab0d846bde984d91848ee6d41bd00c0
[dpdk.git] / lib / librte_port / rte_port_source_sink.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-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 <stdint.h>
34 #include <string.h>
35
36 #include <rte_mbuf.h>
37 #include <rte_mempool.h>
38 #include <rte_malloc.h>
39
40 #ifdef RTE_NEXT_ABI
41
42 #include <rte_memcpy.h>
43
44 #ifdef RTE_PORT_PCAP
45 #include <pcap.h>
46 #endif
47
48 #endif
49
50 #include "rte_port_source_sink.h"
51
52 /*
53  * Port SOURCE
54  */
55 #ifdef RTE_PORT_STATS_COLLECT
56
57 #define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val) \
58         port->stats.n_pkts_in += val
59 #define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val) \
60         port->stats.n_pkts_drop += val
61
62 #else
63
64 #define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val)
65 #define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val)
66
67 #endif
68
69 struct rte_port_source {
70         struct rte_port_in_stats stats;
71
72         struct rte_mempool *mempool;
73
74 #ifdef RTE_NEXT_ABI
75         /* PCAP buffers and indexes */
76         uint8_t **pkts;
77         uint8_t *pkt_buff;
78         uint32_t *pkt_len;
79         uint32_t n_pkts;
80         uint32_t pkt_index;
81 #endif
82 };
83
84 #ifdef RTE_NEXT_ABI
85
86 #ifdef RTE_PORT_PCAP
87
88 /**
89  * Load PCAP file, allocate and copy packets in the file to memory
90  *
91  * @param p
92  *   Parameters for source port
93  * @param port
94  *   Handle to source port
95  * @param socket_id
96  *   Socket id where the memory is created
97  * @return
98  *   0 on SUCCESS
99  *   error code otherwise
100  */
101 static int
102 pcap_source_load(struct rte_port_source_params *p,
103                 struct rte_port_source *port,
104                 int socket_id)
105 {
106         uint32_t status = 0;
107         uint32_t n_pkts = 0;
108         uint32_t i;
109         uint32_t *pkt_len_aligns = NULL;
110         size_t total_buff_len = 0;
111         pcap_t *pcap_handle;
112         char pcap_errbuf[PCAP_ERRBUF_SIZE];
113         uint32_t max_len;
114         struct pcap_pkthdr pcap_hdr;
115         const uint8_t *pkt;
116         uint8_t *buff = NULL;
117         uint32_t pktmbuf_maxlen = (uint32_t)
118                         (rte_pktmbuf_data_room_size(port->mempool) -
119                         RTE_PKTMBUF_HEADROOM);
120
121         if (p->file_name == NULL)
122                 return 0;
123
124         if (p->n_bytes_per_pkt == 0)
125                 max_len = pktmbuf_maxlen;
126         else
127                 max_len = RTE_MIN(p->n_bytes_per_pkt, pktmbuf_maxlen);
128
129         /* first time open, get packet number */
130         pcap_handle = pcap_open_offline(p->file_name, pcap_errbuf);
131         if (pcap_handle == NULL) {
132                 status = -ENOENT;
133                 goto error_exit;
134         }
135
136         while ((pkt = pcap_next(pcap_handle, &pcap_hdr)) != NULL)
137                 n_pkts++;
138
139         pcap_close(pcap_handle);
140
141         port->pkt_len = rte_zmalloc_socket("PCAP",
142                 (sizeof(*port->pkt_len) * n_pkts), 0, socket_id);
143         if (port->pkt_len == NULL) {
144                 status = -ENOMEM;
145                 goto error_exit;
146         }
147
148         pkt_len_aligns = rte_malloc("PCAP",
149                 (sizeof(*pkt_len_aligns) * n_pkts), 0);
150         if (pkt_len_aligns == NULL) {
151                 status = -ENOMEM;
152                 goto error_exit;
153         }
154
155         port->pkts = rte_zmalloc_socket("PCAP",
156                 (sizeof(*port->pkts) * n_pkts), 0, socket_id);
157         if (port->pkts == NULL) {
158                 status = -ENOMEM;
159                 goto error_exit;
160         }
161
162         /* open 2nd time, get pkt_len */
163         pcap_handle = pcap_open_offline(p->file_name, pcap_errbuf);
164         if (pcap_handle == NULL) {
165                 status = -ENOENT;
166                 goto error_exit;
167         }
168
169         for (i = 0; i < n_pkts; i++) {
170                 pkt = pcap_next(pcap_handle, &pcap_hdr);
171                 port->pkt_len[i] = RTE_MIN(max_len, pcap_hdr.len);
172                 pkt_len_aligns[i] = RTE_CACHE_LINE_ROUNDUP(
173                         port->pkt_len[i]);
174                 total_buff_len += pkt_len_aligns[i];
175         }
176
177         pcap_close(pcap_handle);
178
179         /* allocate a big trunk of data for pcap file load */
180         buff = rte_zmalloc_socket("PCAP",
181                 total_buff_len, 0, socket_id);
182         if (buff == NULL) {
183                 status = -ENOMEM;
184                 goto error_exit;
185         }
186
187         port->pkt_buff = buff;
188
189         /* open file one last time to copy the pkt content */
190         pcap_handle = pcap_open_offline(p->file_name, pcap_errbuf);
191         if (pcap_handle == NULL) {
192                 status = -ENOENT;
193                 goto error_exit;
194         }
195
196         for (i = 0; i < n_pkts; i++) {
197                 pkt = pcap_next(pcap_handle, &pcap_hdr);
198                 rte_memcpy(buff, pkt, port->pkt_len[i]);
199                 port->pkts[i] = buff;
200                 buff += pkt_len_aligns[i];
201         }
202
203         pcap_close(pcap_handle);
204
205         port->n_pkts = n_pkts;
206
207         rte_free(pkt_len_aligns);
208
209         return 0;
210
211 error_exit:
212         if (pkt_len_aligns)
213                 rte_free(pkt_len_aligns);
214         if (port->pkt_len)
215                 rte_free(port->pkt_len);
216         if (port->pkts)
217                 rte_free(port->pkts);
218         if (port->pkt_buff)
219                 rte_free(port->pkt_buff);
220
221         return status;
222 }
223
224 #else
225 static int
226 pcap_source_load(__rte_unused struct rte_port_source_params *p,
227                 struct rte_port_source *port,
228                 __rte_unused int socket_id)
229 {
230         port->pkt_buff = NULL;
231         port->pkt_len = NULL;
232         port->pkts = NULL;
233         port->pkt_index = 0;
234
235         return -ENOTSUP;
236 }
237 #endif /* RTE_PORT_PCAP */
238
239 #endif
240
241 static void *
242 rte_port_source_create(void *params, int socket_id)
243 {
244         struct rte_port_source_params *p =
245                         (struct rte_port_source_params *) params;
246         struct rte_port_source *port;
247
248         /* Check input arguments*/
249         if ((p == NULL) || (p->mempool == NULL)) {
250                 RTE_LOG(ERR, PORT, "%s: Invalid params\n", __func__);
251                 return NULL;
252         }
253
254         /* Memory allocation */
255         port = rte_zmalloc_socket("PORT", sizeof(*port),
256                         RTE_CACHE_LINE_SIZE, socket_id);
257         if (port == NULL) {
258                 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
259                 return NULL;
260         }
261
262         /* Initialization */
263         port->mempool = (struct rte_mempool *) p->mempool;
264
265 #ifdef RTE_NEXT_ABI
266
267         /* pcap file load and initialization */
268         int status = pcap_source_load(p, port, socket_id);
269
270         if (status == 0) {
271                 if (port->pkt_buff != NULL) {
272                         RTE_LOG(INFO, PORT, "Successfully load pcap file "
273                                 "'%s' with %u pkts\n",
274                                 p->file_name, port->n_pkts);
275                 }
276         } else if (status != -ENOTSUP) {
277                 /* ENOTSUP is not treated as error */
278                 switch (status) {
279                 case -ENOENT:
280                         RTE_LOG(ERR, PORT, "%s: Failed to open pcap file "
281                                 "'%s' for reading\n",
282                                 __func__, p->file_name);
283                         break;
284                 case -ENOMEM:
285                         RTE_LOG(ERR, PORT, "%s: Not enough memory\n",
286                                 __func__);
287                         break;
288                 default:
289                         RTE_LOG(ERR, PORT, "%s: Failed to enable PCAP "
290                                 "support for unknown reason\n",
291                                 __func__);
292                         break;
293                 }
294
295                 rte_free(port);
296                 port = NULL;
297         }
298
299 #endif
300
301         return port;
302 }
303
304 static int
305 rte_port_source_free(void *port)
306 {
307         struct rte_port_source *p =
308                         (struct rte_port_source *)port;
309
310         /* Check input parameters */
311         if (p == NULL)
312                 return 0;
313
314 #ifdef RTE_NEXT_ABI
315
316         if (p->pkt_len)
317                 rte_free(p->pkt_len);
318         if (p->pkts)
319                 rte_free(p->pkts);
320         if (p->pkt_buff)
321                 rte_free(p->pkt_buff);
322 #endif
323
324         rte_free(p);
325
326         return 0;
327 }
328
329 static int
330 rte_port_source_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
331 {
332         struct rte_port_source *p = (struct rte_port_source *) port;
333         uint32_t i;
334
335         if (rte_mempool_get_bulk(p->mempool, (void **) pkts, n_pkts) != 0)
336                 return 0;
337
338         for (i = 0; i < n_pkts; i++) {
339                 rte_mbuf_refcnt_set(pkts[i], 1);
340                 rte_pktmbuf_reset(pkts[i]);
341         }
342
343 #ifdef RTE_NEXT_ABI
344
345         if (p->pkt_buff != NULL) {
346                 for (i = 0; i < n_pkts; i++) {
347                         uint8_t *pkt_data = rte_pktmbuf_mtod(pkts[i],
348                                 uint8_t *);
349
350                         rte_memcpy(pkt_data, p->pkts[p->pkt_index],
351                                         p->pkt_len[p->pkt_index]);
352                         pkts[i]->data_len = p->pkt_len[p->pkt_index];
353                         pkts[i]->pkt_len = pkts[i]->data_len;
354
355                         p->pkt_index++;
356                         if (p->pkt_index >= p->n_pkts)
357                                 p->pkt_index = 0;
358                 }
359         }
360
361 #endif
362
363         RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(p, n_pkts);
364
365         return n_pkts;
366 }
367
368 static int
369 rte_port_source_stats_read(void *port,
370                 struct rte_port_in_stats *stats, int clear)
371 {
372         struct rte_port_source *p =
373                 (struct rte_port_source *) port;
374
375         if (stats != NULL)
376                 memcpy(stats, &p->stats, sizeof(p->stats));
377
378         if (clear)
379                 memset(&p->stats, 0, sizeof(p->stats));
380
381         return 0;
382 }
383
384 /*
385  * Port SINK
386  */
387 #ifdef RTE_PORT_STATS_COLLECT
388
389 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) \
390         (port->stats.n_pkts_in += val)
391 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) \
392         (port->stats.n_pkts_drop += val)
393
394 #else
395
396 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val)
397 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val)
398
399 #endif
400
401 struct rte_port_sink {
402         struct rte_port_out_stats stats;
403 };
404
405 static void *
406 rte_port_sink_create(__rte_unused void *params, int socket_id)
407 {
408         struct rte_port_sink *port;
409
410         /* Memory allocation */
411         port = rte_zmalloc_socket("PORT", sizeof(*port),
412                         RTE_CACHE_LINE_SIZE, socket_id);
413         if (port == NULL) {
414                 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
415                 return NULL;
416         }
417
418         return port;
419 }
420
421 static int
422 rte_port_sink_tx(void *port, struct rte_mbuf *pkt)
423 {
424         __rte_unused struct rte_port_sink *p = (struct rte_port_sink *) port;
425
426         RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
427         rte_pktmbuf_free(pkt);
428         RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
429
430         return 0;
431 }
432
433 static int
434 rte_port_sink_tx_bulk(void *port, struct rte_mbuf **pkts,
435         uint64_t pkts_mask)
436 {
437         __rte_unused struct rte_port_sink *p = (struct rte_port_sink *) port;
438
439         if ((pkts_mask & (pkts_mask + 1)) == 0) {
440                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
441                 uint32_t i;
442
443                 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, n_pkts);
444                 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, n_pkts);
445                 for (i = 0; i < n_pkts; i++) {
446                         struct rte_mbuf *pkt = pkts[i];
447
448                         rte_pktmbuf_free(pkt);
449                 }
450         } else {
451                 for ( ; pkts_mask; ) {
452                         uint32_t pkt_index = __builtin_ctzll(pkts_mask);
453                         uint64_t pkt_mask = 1LLU << pkt_index;
454                         struct rte_mbuf *pkt = pkts[pkt_index];
455
456                         RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
457                         RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
458                         rte_pktmbuf_free(pkt);
459                         pkts_mask &= ~pkt_mask;
460                 }
461         }
462
463         return 0;
464 }
465
466 static int
467 rte_port_sink_stats_read(void *port, struct rte_port_out_stats *stats,
468                 int clear)
469 {
470         struct rte_port_sink *p =
471                 (struct rte_port_sink *) port;
472
473         if (stats != NULL)
474                 memcpy(stats, &p->stats, sizeof(p->stats));
475
476         if (clear)
477                 memset(&p->stats, 0, sizeof(p->stats));
478
479         return 0;
480 }
481
482 /*
483  * Summary of port operations
484  */
485 struct rte_port_in_ops rte_port_source_ops = {
486         .f_create = rte_port_source_create,
487         .f_free = rte_port_source_free,
488         .f_rx = rte_port_source_rx,
489         .f_stats = rte_port_source_stats_read,
490 };
491
492 struct rte_port_out_ops rte_port_sink_ops = {
493         .f_create = rte_port_sink_create,
494         .f_free = NULL,
495         .f_tx = rte_port_sink_tx,
496         .f_tx_bulk = rte_port_sink_tx_bulk,
497         .f_flush = NULL,
498         .f_stats = rte_port_sink_stats_read,
499 };