Imported Upstream version 16.07-rc1
[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                         (struct rte_port_source_params *) 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                         (struct rte_port_source *)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 = (struct rte_port_source *) port;
290         uint32_t i;
291
292         if (rte_mempool_get_bulk(p->mempool, (void **) pkts, n_pkts) != 0)
293                 return 0;
294
295         for (i = 0; i < n_pkts; i++) {
296                 rte_mbuf_refcnt_set(pkts[i], 1);
297                 rte_pktmbuf_reset(pkts[i]);
298         }
299
300         if (p->pkt_buff != NULL) {
301                 for (i = 0; i < n_pkts; i++) {
302                         uint8_t *pkt_data = rte_pktmbuf_mtod(pkts[i],
303                                 uint8_t *);
304
305                         rte_memcpy(pkt_data, p->pkts[p->pkt_index],
306                                         p->pkt_len[p->pkt_index]);
307                         pkts[i]->data_len = p->pkt_len[p->pkt_index];
308                         pkts[i]->pkt_len = pkts[i]->data_len;
309
310                         p->pkt_index++;
311                         if (p->pkt_index >= p->n_pkts)
312                                 p->pkt_index = 0;
313                 }
314         }
315
316         RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(p, n_pkts);
317
318         return n_pkts;
319 }
320
321 static int
322 rte_port_source_stats_read(void *port,
323                 struct rte_port_in_stats *stats, int clear)
324 {
325         struct rte_port_source *p =
326                 (struct rte_port_source *) port;
327
328         if (stats != NULL)
329                 memcpy(stats, &p->stats, sizeof(p->stats));
330
331         if (clear)
332                 memset(&p->stats, 0, sizeof(p->stats));
333
334         return 0;
335 }
336
337 /*
338  * Port SINK
339  */
340 #ifdef RTE_PORT_STATS_COLLECT
341
342 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) \
343         (port->stats.n_pkts_in += val)
344 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) \
345         (port->stats.n_pkts_drop += val)
346
347 #else
348
349 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val)
350 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val)
351
352 #endif
353
354 struct rte_port_sink {
355         struct rte_port_out_stats stats;
356
357         /* PCAP dumper handle and pkts number */
358         void *dumper;
359         uint32_t max_pkts;
360         uint32_t pkt_index;
361         uint32_t dump_finish;
362 };
363
364 #ifdef RTE_PORT_PCAP
365
366 static int
367 pcap_sink_open(struct rte_port_sink *port,
368         const char *file_name,
369         uint32_t max_n_pkts)
370 {
371         pcap_t *tx_pcap;
372         pcap_dumper_t *pcap_dumper;
373
374         /** Open a dead pcap handler for opening dumper file */
375         tx_pcap = pcap_open_dead(DLT_EN10MB, 65535);
376         if (tx_pcap == NULL) {
377                 RTE_LOG(ERR, PORT, "Cannot open pcap dead handler\n");
378                 return -1;
379         }
380
381         /* The dumper is created using the previous pcap_t reference */
382         pcap_dumper = pcap_dump_open(tx_pcap, file_name);
383         if (pcap_dumper == NULL) {
384                 RTE_LOG(ERR, PORT, "Failed to open pcap file "
385                         "\"%s\" for writing\n", file_name);
386                 return -1;
387         }
388
389         port->dumper = pcap_dumper;
390         port->max_pkts = max_n_pkts;
391         port->pkt_index = 0;
392         port->dump_finish = 0;
393
394         RTE_LOG(INFO, PORT, "Ready to dump packets to file \"%s\"\n",
395                 file_name);
396
397         return 0;
398 }
399
400 static void
401 pcap_sink_write_pkt(struct rte_port_sink *port, struct rte_mbuf *mbuf)
402 {
403         uint8_t *pcap_dumper = (uint8_t *)(port->dumper);
404         struct pcap_pkthdr pcap_hdr;
405         uint8_t jumbo_pkt_buf[ETHER_MAX_JUMBO_FRAME_LEN];
406         uint8_t *pkt;
407
408         /* Maximum num packets already reached */
409         if (port->dump_finish)
410                 return;
411
412         pkt = rte_pktmbuf_mtod(mbuf, uint8_t *);
413
414         pcap_hdr.len = mbuf->pkt_len;
415         pcap_hdr.caplen = pcap_hdr.len;
416         gettimeofday(&(pcap_hdr.ts), NULL);
417
418         if (mbuf->nb_segs > 1) {
419                 struct rte_mbuf *jumbo_mbuf;
420                 uint32_t pkt_index = 0;
421
422                 /* if packet size longer than ETHER_MAX_JUMBO_FRAME_LEN,
423                  * ignore it.
424                  */
425                 if (mbuf->pkt_len > ETHER_MAX_JUMBO_FRAME_LEN)
426                         return;
427
428                 for (jumbo_mbuf = mbuf; jumbo_mbuf != NULL;
429                                 jumbo_mbuf = jumbo_mbuf->next) {
430                         rte_memcpy(&jumbo_pkt_buf[pkt_index],
431                                 rte_pktmbuf_mtod(jumbo_mbuf, uint8_t *),
432                                 jumbo_mbuf->data_len);
433                         pkt_index += jumbo_mbuf->data_len;
434                 }
435
436                 jumbo_pkt_buf[pkt_index] = '\0';
437
438                 pkt = jumbo_pkt_buf;
439         }
440
441         pcap_dump(pcap_dumper, &pcap_hdr, pkt);
442
443         port->pkt_index++;
444
445         if ((port->max_pkts != 0) && (port->pkt_index >= port->max_pkts)) {
446                 port->dump_finish = 1;
447                 RTE_LOG(INFO, PORT, "Dumped %u packets to file\n",
448                                 port->pkt_index);
449         }
450
451 }
452
453 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts)             \
454         pcap_sink_open(port, file_name, max_n_pkts)
455
456 #define PCAP_SINK_WRITE_PKT(port, mbuf)                         \
457         pcap_sink_write_pkt(port, mbuf)
458
459 #define PCAP_SINK_FLUSH_PKT(dumper)                             \
460 do {                                                            \
461         if (dumper)                                             \
462                 pcap_dump_flush((pcap_dumper_t *)dumper);       \
463 } while (0)
464
465 #define PCAP_SINK_CLOSE(dumper)                                 \
466 do {                                                            \
467         if (dumper)                                             \
468                 pcap_dump_close((pcap_dumper_t *)dumper);       \
469 } while (0)
470
471 #else
472
473 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts)             \
474 ({                                                              \
475         int _ret = 0;                                           \
476                                                                 \
477         if (file_name) {                                        \
478                 RTE_LOG(ERR, PORT, "Sink port field "           \
479                         "\"file_name\" is not NULL.\n");        \
480                 _ret = -1;                                      \
481         }                                                       \
482                                                                 \
483         _ret;                                                   \
484 })
485
486 #define PCAP_SINK_WRITE_PKT(port, mbuf) {}
487
488 #define PCAP_SINK_FLUSH_PKT(dumper)
489
490 #define PCAP_SINK_CLOSE(dumper)
491
492 #endif
493
494 static void *
495 rte_port_sink_create(void *params, int socket_id)
496 {
497         struct rte_port_sink *port;
498         struct rte_port_sink_params *p = params;
499
500         /* Memory allocation */
501         port = rte_zmalloc_socket("PORT", sizeof(*port),
502                         RTE_CACHE_LINE_SIZE, socket_id);
503         if (port == NULL) {
504                 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
505                 return NULL;
506         }
507
508         if (!p)
509                 return port;
510
511         if (p->file_name) {
512                 int status = PCAP_SINK_OPEN(port, p->file_name,
513                         p->max_n_pkts);
514
515                 if (status < 0) {
516                         rte_free(port);
517                         port = NULL;
518                 }
519         }
520
521         return port;
522 }
523
524 static int
525 rte_port_sink_tx(void *port, struct rte_mbuf *pkt)
526 {
527         struct rte_port_sink *p = (struct rte_port_sink *) port;
528
529         RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
530         if (p->dumper != NULL)
531                 PCAP_SINK_WRITE_PKT(p, pkt);
532         rte_pktmbuf_free(pkt);
533         RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
534
535         return 0;
536 }
537
538 static int
539 rte_port_sink_tx_bulk(void *port, struct rte_mbuf **pkts,
540         uint64_t pkts_mask)
541 {
542         struct rte_port_sink *p = (struct rte_port_sink *) port;
543
544         if ((pkts_mask & (pkts_mask + 1)) == 0) {
545                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
546                 uint32_t i;
547
548                 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, n_pkts);
549                 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, n_pkts);
550
551                 if (p->dumper) {
552                         for (i = 0; i < n_pkts; i++)
553                                 PCAP_SINK_WRITE_PKT(p, pkts[i]);
554                 }
555
556                 for (i = 0; i < n_pkts; i++) {
557                         struct rte_mbuf *pkt = pkts[i];
558
559                         rte_pktmbuf_free(pkt);
560                 }
561
562         } else {
563                 if (p->dumper) {
564                         uint64_t dump_pkts_mask = pkts_mask;
565                         uint32_t pkt_index;
566
567                         for ( ; dump_pkts_mask; ) {
568                                 pkt_index = __builtin_ctzll(
569                                         dump_pkts_mask);
570                                 PCAP_SINK_WRITE_PKT(p, pkts[pkt_index]);
571                                 dump_pkts_mask &= ~(1LLU << pkt_index);
572                         }
573                 }
574
575                 for ( ; pkts_mask; ) {
576                         uint32_t pkt_index = __builtin_ctzll(pkts_mask);
577                         uint64_t pkt_mask = 1LLU << pkt_index;
578                         struct rte_mbuf *pkt = pkts[pkt_index];
579
580                         RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
581                         RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
582                         rte_pktmbuf_free(pkt);
583                         pkts_mask &= ~pkt_mask;
584                 }
585         }
586
587         return 0;
588 }
589
590 static int
591 rte_port_sink_flush(void *port)
592 {
593         struct rte_port_sink *p =
594                         (struct rte_port_sink *)port;
595
596         if (p == NULL)
597                 return 0;
598
599         PCAP_SINK_FLUSH_PKT(p->dumper);
600
601         return 0;
602 }
603
604 static int
605 rte_port_sink_free(void *port)
606 {
607         struct rte_port_sink *p =
608                         (struct rte_port_sink *)port;
609
610         if (p == NULL)
611                 return 0;
612
613         PCAP_SINK_CLOSE(p->dumper);
614
615         rte_free(p);
616
617         return 0;
618 }
619
620 static int
621 rte_port_sink_stats_read(void *port, struct rte_port_out_stats *stats,
622                 int clear)
623 {
624         struct rte_port_sink *p =
625                 (struct rte_port_sink *) port;
626
627         if (stats != NULL)
628                 memcpy(stats, &p->stats, sizeof(p->stats));
629
630         if (clear)
631                 memset(&p->stats, 0, sizeof(p->stats));
632
633         return 0;
634 }
635
636 /*
637  * Summary of port operations
638  */
639 struct rte_port_in_ops rte_port_source_ops = {
640         .f_create = rte_port_source_create,
641         .f_free = rte_port_source_free,
642         .f_rx = rte_port_source_rx,
643         .f_stats = rte_port_source_stats_read,
644 };
645
646 struct rte_port_out_ops rte_port_sink_ops = {
647         .f_create = rte_port_sink_create,
648         .f_free = rte_port_sink_free,
649         .f_tx = rte_port_sink_tx,
650         .f_tx_bulk = rte_port_sink_tx_bulk,
651         .f_flush = rte_port_sink_flush,
652         .f_stats = rte_port_sink_stats_read,
653 };