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