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