a79f2f64a64202fad8e756e1046f577a59225ef6
[deb_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 #include <rte_memcpy.h>
40
41 #ifdef RTE_PORT_PCAP
42 #include <rte_ether.h>
43 #include <pcap.h>
44 #endif
45
46 #include "rte_port_source_sink.h"
47
48 /*
49  * Port SOURCE
50  */
51 #ifdef RTE_PORT_STATS_COLLECT
52
53 #define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val) \
54         port->stats.n_pkts_in += val
55 #define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val) \
56         port->stats.n_pkts_drop += val
57
58 #else
59
60 #define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val)
61 #define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val)
62
63 #endif
64
65 struct rte_port_source {
66         struct rte_port_in_stats stats;
67
68         struct rte_mempool *mempool;
69
70         /* PCAP buffers and indices */
71         uint8_t **pkts;
72         uint8_t *pkt_buff;
73         uint32_t *pkt_len;
74         uint32_t n_pkts;
75         uint32_t pkt_index;
76 };
77
78 #ifdef RTE_PORT_PCAP
79
80 static int
81 pcap_source_load(struct rte_port_source *port,
82                 const char *file_name,
83                 uint32_t n_bytes_per_pkt,
84                 int socket_id)
85 {
86         uint32_t n_pkts = 0;
87         uint32_t i;
88         uint32_t *pkt_len_aligns = NULL;
89         size_t total_buff_len = 0;
90         pcap_t *pcap_handle;
91         char pcap_errbuf[PCAP_ERRBUF_SIZE];
92         uint32_t max_len;
93         struct pcap_pkthdr pcap_hdr;
94         const uint8_t *pkt;
95         uint8_t *buff = NULL;
96         uint32_t pktmbuf_maxlen = (uint32_t)
97                         (rte_pktmbuf_data_room_size(port->mempool) -
98                         RTE_PKTMBUF_HEADROOM);
99
100         if (n_bytes_per_pkt == 0)
101                 max_len = pktmbuf_maxlen;
102         else
103                 max_len = RTE_MIN(n_bytes_per_pkt, pktmbuf_maxlen);
104
105         /* first time open, get packet number */
106         pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
107         if (pcap_handle == NULL) {
108                 RTE_LOG(ERR, PORT, "Failed to open pcap file "
109                         "'%s' for reading\n", file_name);
110                 goto error_exit;
111         }
112
113         while ((pkt = pcap_next(pcap_handle, &pcap_hdr)) != NULL)
114                 n_pkts++;
115
116         pcap_close(pcap_handle);
117
118         port->pkt_len = rte_zmalloc_socket("PCAP",
119                 (sizeof(*port->pkt_len) * n_pkts), 0, socket_id);
120         if (port->pkt_len == NULL) {
121                 RTE_LOG(ERR, PORT, "No enough memory\n");
122                 goto error_exit;
123         }
124
125         pkt_len_aligns = rte_malloc("PCAP",
126                 (sizeof(*pkt_len_aligns) * n_pkts), 0);
127         if (pkt_len_aligns == NULL) {
128                 RTE_LOG(ERR, PORT, "No enough memory\n");
129                 goto error_exit;
130         }
131
132         port->pkts = rte_zmalloc_socket("PCAP",
133                 (sizeof(*port->pkts) * n_pkts), 0, socket_id);
134         if (port->pkts == NULL) {
135                 RTE_LOG(ERR, PORT, "No enough memory\n");
136                 goto error_exit;
137         }
138
139         /* open 2nd time, get pkt_len */
140         pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
141         if (pcap_handle == NULL) {
142                 RTE_LOG(ERR, PORT, "Failed to open pcap file "
143                         "'%s' for reading\n", file_name);
144                 goto error_exit;
145         }
146
147         for (i = 0; i < n_pkts; i++) {
148                 pkt = pcap_next(pcap_handle, &pcap_hdr);
149                 port->pkt_len[i] = RTE_MIN(max_len, pcap_hdr.len);
150                 pkt_len_aligns[i] = RTE_CACHE_LINE_ROUNDUP(
151                         port->pkt_len[i]);
152                 total_buff_len += pkt_len_aligns[i];
153         }
154
155         pcap_close(pcap_handle);
156
157         /* allocate a big trunk of data for pcap file load */
158         buff = rte_zmalloc_socket("PCAP",
159                 total_buff_len, 0, socket_id);
160         if (buff == NULL) {
161                 RTE_LOG(ERR, PORT, "No enough memory\n");
162                 goto error_exit;
163         }
164
165         port->pkt_buff = buff;
166
167         /* open file one last time to copy the pkt content */
168         pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
169         if (pcap_handle == NULL) {
170                 RTE_LOG(ERR, PORT, "Failed to open pcap file "
171                         "'%s' for reading\n", file_name);
172                 goto error_exit;
173         }
174
175         for (i = 0; i < n_pkts; i++) {
176                 pkt = pcap_next(pcap_handle, &pcap_hdr);
177                 rte_memcpy(buff, pkt, port->pkt_len[i]);
178                 port->pkts[i] = buff;
179                 buff += pkt_len_aligns[i];
180         }
181
182         pcap_close(pcap_handle);
183
184         port->n_pkts = n_pkts;
185
186         rte_free(pkt_len_aligns);
187
188         RTE_LOG(INFO, PORT, "Successfully load pcap file "
189                 "'%s' with %u pkts\n",
190                 file_name, port->n_pkts);
191
192         return 0;
193
194 error_exit:
195         if (pkt_len_aligns)
196                 rte_free(pkt_len_aligns);
197         if (port->pkt_len)
198                 rte_free(port->pkt_len);
199         if (port->pkts)
200                 rte_free(port->pkts);
201         if (port->pkt_buff)
202                 rte_free(port->pkt_buff);
203
204         return -1;
205 }
206
207 #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id)   \
208         pcap_source_load(port, file_name, n_bytes, socket_id)
209
210 #else /* RTE_PORT_PCAP */
211
212 #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id)   \
213 ({                                                              \
214         int _ret = 0;                                           \
215                                                                 \
216         if (file_name) {                                        \
217                 RTE_LOG(ERR, PORT, "Source port field "         \
218                         "\"file_name\" is not NULL.\n");        \
219                 _ret = -1;                                      \
220         }                                                       \
221                                                                 \
222         _ret;                                                   \
223 })
224
225 #endif /* RTE_PORT_PCAP */
226
227 static void *
228 rte_port_source_create(void *params, int socket_id)
229 {
230         struct rte_port_source_params *p =
231                         params;
232         struct rte_port_source *port;
233
234         /* Check input arguments*/
235         if ((p == NULL) || (p->mempool == NULL)) {
236                 RTE_LOG(ERR, PORT, "%s: Invalid params\n", __func__);
237                 return NULL;
238         }
239
240         /* Memory allocation */
241         port = rte_zmalloc_socket("PORT", sizeof(*port),
242                         RTE_CACHE_LINE_SIZE, socket_id);
243         if (port == NULL) {
244                 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
245                 return NULL;
246         }
247
248         /* Initialization */
249         port->mempool = (struct rte_mempool *) p->mempool;
250
251         if (p->file_name) {
252                 int status = PCAP_SOURCE_LOAD(port, p->file_name,
253                         p->n_bytes_per_pkt, socket_id);
254
255                 if (status < 0) {
256                         rte_free(port);
257                         port = NULL;
258                 }
259         }
260
261         return port;
262 }
263
264 static int
265 rte_port_source_free(void *port)
266 {
267         struct rte_port_source *p =
268                         port;
269
270         /* Check input parameters */
271         if (p == NULL)
272                 return 0;
273
274         if (p->pkt_len)
275                 rte_free(p->pkt_len);
276         if (p->pkts)
277                 rte_free(p->pkts);
278         if (p->pkt_buff)
279                 rte_free(p->pkt_buff);
280
281         rte_free(p);
282
283         return 0;
284 }
285
286 static int
287 rte_port_source_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
288 {
289         struct rte_port_source *p = port;
290         uint32_t i;
291
292         if (rte_pktmbuf_alloc_bulk(p->mempool, pkts, n_pkts) != 0)
293                 return 0;
294
295         if (p->pkt_buff != NULL) {
296                 for (i = 0; i < n_pkts; i++) {
297                         uint8_t *pkt_data = rte_pktmbuf_mtod(pkts[i],
298                                 uint8_t *);
299
300                         rte_memcpy(pkt_data, p->pkts[p->pkt_index],
301                                         p->pkt_len[p->pkt_index]);
302                         pkts[i]->data_len = p->pkt_len[p->pkt_index];
303                         pkts[i]->pkt_len = pkts[i]->data_len;
304
305                         p->pkt_index++;
306                         if (p->pkt_index >= p->n_pkts)
307                                 p->pkt_index = 0;
308                 }
309         }
310
311         RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(p, n_pkts);
312
313         return n_pkts;
314 }
315
316 static int
317 rte_port_source_stats_read(void *port,
318                 struct rte_port_in_stats *stats, int clear)
319 {
320         struct rte_port_source *p =
321                 port;
322
323         if (stats != NULL)
324                 memcpy(stats, &p->stats, sizeof(p->stats));
325
326         if (clear)
327                 memset(&p->stats, 0, sizeof(p->stats));
328
329         return 0;
330 }
331
332 /*
333  * Port SINK
334  */
335 #ifdef RTE_PORT_STATS_COLLECT
336
337 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) \
338         (port->stats.n_pkts_in += val)
339 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) \
340         (port->stats.n_pkts_drop += val)
341
342 #else
343
344 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val)
345 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val)
346
347 #endif
348
349 struct rte_port_sink {
350         struct rte_port_out_stats stats;
351
352         /* PCAP dumper handle and pkts number */
353         void *dumper;
354         uint32_t max_pkts;
355         uint32_t pkt_index;
356         uint32_t dump_finish;
357 };
358
359 #ifdef RTE_PORT_PCAP
360
361 static int
362 pcap_sink_open(struct rte_port_sink *port,
363         const char *file_name,
364         uint32_t max_n_pkts)
365 {
366         pcap_t *tx_pcap;
367         pcap_dumper_t *pcap_dumper;
368
369         /** Open a dead pcap handler for opening dumper file */
370         tx_pcap = pcap_open_dead(DLT_EN10MB, 65535);
371         if (tx_pcap == NULL) {
372                 RTE_LOG(ERR, PORT, "Cannot open pcap dead handler\n");
373                 return -1;
374         }
375
376         /* The dumper is created using the previous pcap_t reference */
377         pcap_dumper = pcap_dump_open(tx_pcap, file_name);
378         if (pcap_dumper == NULL) {
379                 RTE_LOG(ERR, PORT, "Failed to open pcap file "
380                         "\"%s\" for writing\n", file_name);
381                 return -1;
382         }
383
384         port->dumper = pcap_dumper;
385         port->max_pkts = max_n_pkts;
386         port->pkt_index = 0;
387         port->dump_finish = 0;
388
389         RTE_LOG(INFO, PORT, "Ready to dump packets to file \"%s\"\n",
390                 file_name);
391
392         return 0;
393 }
394
395 static void
396 pcap_sink_write_pkt(struct rte_port_sink *port, struct rte_mbuf *mbuf)
397 {
398         uint8_t *pcap_dumper = (port->dumper);
399         struct pcap_pkthdr pcap_hdr;
400         uint8_t jumbo_pkt_buf[ETHER_MAX_JUMBO_FRAME_LEN];
401         uint8_t *pkt;
402
403         /* Maximum num packets already reached */
404         if (port->dump_finish)
405                 return;
406
407         pkt = rte_pktmbuf_mtod(mbuf, uint8_t *);
408
409         pcap_hdr.len = mbuf->pkt_len;
410         pcap_hdr.caplen = pcap_hdr.len;
411         gettimeofday(&(pcap_hdr.ts), NULL);
412
413         if (mbuf->nb_segs > 1) {
414                 struct rte_mbuf *jumbo_mbuf;
415                 uint32_t pkt_index = 0;
416
417                 /* if packet size longer than ETHER_MAX_JUMBO_FRAME_LEN,
418                  * ignore it.
419                  */
420                 if (mbuf->pkt_len > ETHER_MAX_JUMBO_FRAME_LEN)
421                         return;
422
423                 for (jumbo_mbuf = mbuf; jumbo_mbuf != NULL;
424                                 jumbo_mbuf = jumbo_mbuf->next) {
425                         rte_memcpy(&jumbo_pkt_buf[pkt_index],
426                                 rte_pktmbuf_mtod(jumbo_mbuf, uint8_t *),
427                                 jumbo_mbuf->data_len);
428                         pkt_index += jumbo_mbuf->data_len;
429                 }
430
431                 jumbo_pkt_buf[pkt_index] = '\0';
432
433                 pkt = jumbo_pkt_buf;
434         }
435
436         pcap_dump(pcap_dumper, &pcap_hdr, pkt);
437
438         port->pkt_index++;
439
440         if ((port->max_pkts != 0) && (port->pkt_index >= port->max_pkts)) {
441                 port->dump_finish = 1;
442                 RTE_LOG(INFO, PORT, "Dumped %u packets to file\n",
443                                 port->pkt_index);
444         }
445
446 }
447
448 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts)             \
449         pcap_sink_open(port, file_name, max_n_pkts)
450
451 #define PCAP_SINK_WRITE_PKT(port, mbuf)                         \
452         pcap_sink_write_pkt(port, mbuf)
453
454 #define PCAP_SINK_FLUSH_PKT(dumper)                             \
455 do {                                                            \
456         if (dumper)                                             \
457                 pcap_dump_flush((pcap_dumper_t *)dumper);       \
458 } while (0)
459
460 #define PCAP_SINK_CLOSE(dumper)                                 \
461 do {                                                            \
462         if (dumper)                                             \
463                 pcap_dump_close((pcap_dumper_t *)dumper);       \
464 } while (0)
465
466 #else
467
468 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts)             \
469 ({                                                              \
470         int _ret = 0;                                           \
471                                                                 \
472         if (file_name) {                                        \
473                 RTE_LOG(ERR, PORT, "Sink port field "           \
474                         "\"file_name\" is not NULL.\n");        \
475                 _ret = -1;                                      \
476         }                                                       \
477                                                                 \
478         _ret;                                                   \
479 })
480
481 #define PCAP_SINK_WRITE_PKT(port, mbuf) {}
482
483 #define PCAP_SINK_FLUSH_PKT(dumper)
484
485 #define PCAP_SINK_CLOSE(dumper)
486
487 #endif
488
489 static void *
490 rte_port_sink_create(void *params, int socket_id)
491 {
492         struct rte_port_sink *port;
493         struct rte_port_sink_params *p = params;
494
495         /* Memory allocation */
496         port = rte_zmalloc_socket("PORT", sizeof(*port),
497                         RTE_CACHE_LINE_SIZE, socket_id);
498         if (port == NULL) {
499                 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
500                 return NULL;
501         }
502
503         if (!p)
504                 return port;
505
506         if (p->file_name) {
507                 int status = PCAP_SINK_OPEN(port, p->file_name,
508                         p->max_n_pkts);
509
510                 if (status < 0) {
511                         rte_free(port);
512                         port = NULL;
513                 }
514         }
515
516         return port;
517 }
518
519 static int
520 rte_port_sink_tx(void *port, struct rte_mbuf *pkt)
521 {
522         struct rte_port_sink *p = port;
523
524         RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
525         if (p->dumper != NULL)
526                 PCAP_SINK_WRITE_PKT(p, pkt);
527         rte_pktmbuf_free(pkt);
528         RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
529
530         return 0;
531 }
532
533 static int
534 rte_port_sink_tx_bulk(void *port, struct rte_mbuf **pkts,
535         uint64_t pkts_mask)
536 {
537         struct rte_port_sink *p = port;
538
539         if ((pkts_mask & (pkts_mask + 1)) == 0) {
540                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
541                 uint32_t i;
542
543                 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, n_pkts);
544                 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, n_pkts);
545
546                 if (p->dumper) {
547                         for (i = 0; i < n_pkts; i++)
548                                 PCAP_SINK_WRITE_PKT(p, pkts[i]);
549                 }
550
551                 for (i = 0; i < n_pkts; i++) {
552                         struct rte_mbuf *pkt = pkts[i];
553
554                         rte_pktmbuf_free(pkt);
555                 }
556
557         } else {
558                 if (p->dumper) {
559                         uint64_t dump_pkts_mask = pkts_mask;
560                         uint32_t pkt_index;
561
562                         for ( ; dump_pkts_mask; ) {
563                                 pkt_index = __builtin_ctzll(
564                                         dump_pkts_mask);
565                                 PCAP_SINK_WRITE_PKT(p, pkts[pkt_index]);
566                                 dump_pkts_mask &= ~(1LLU << pkt_index);
567                         }
568                 }
569
570                 for ( ; pkts_mask; ) {
571                         uint32_t pkt_index = __builtin_ctzll(pkts_mask);
572                         uint64_t pkt_mask = 1LLU << pkt_index;
573                         struct rte_mbuf *pkt = pkts[pkt_index];
574
575                         RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
576                         RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
577                         rte_pktmbuf_free(pkt);
578                         pkts_mask &= ~pkt_mask;
579                 }
580         }
581
582         return 0;
583 }
584
585 static int
586 rte_port_sink_flush(void *port)
587 {
588         struct rte_port_sink *p =
589                         port;
590
591         if (p == NULL)
592                 return 0;
593
594         PCAP_SINK_FLUSH_PKT(p->dumper);
595
596         return 0;
597 }
598
599 static int
600 rte_port_sink_free(void *port)
601 {
602         struct rte_port_sink *p =
603                         port;
604
605         if (p == NULL)
606                 return 0;
607
608         PCAP_SINK_CLOSE(p->dumper);
609
610         rte_free(p);
611
612         return 0;
613 }
614
615 static int
616 rte_port_sink_stats_read(void *port, struct rte_port_out_stats *stats,
617                 int clear)
618 {
619         struct rte_port_sink *p =
620                 port;
621
622         if (stats != NULL)
623                 memcpy(stats, &p->stats, sizeof(p->stats));
624
625         if (clear)
626                 memset(&p->stats, 0, sizeof(p->stats));
627
628         return 0;
629 }
630
631 /*
632  * Summary of port operations
633  */
634 struct rte_port_in_ops rte_port_source_ops = {
635         .f_create = rte_port_source_create,
636         .f_free = rte_port_source_free,
637         .f_rx = rte_port_source_rx,
638         .f_stats = rte_port_source_stats_read,
639 };
640
641 struct rte_port_out_ops rte_port_sink_ops = {
642         .f_create = rte_port_sink_create,
643         .f_free = rte_port_sink_free,
644         .f_tx = rte_port_sink_tx,
645         .f_tx_bulk = rte_port_sink_tx_bulk,
646         .f_flush = rte_port_sink_flush,
647         .f_stats = rte_port_sink_stats_read,
648 };