xref: /dpdk/lib/port/rte_port_source_sink.c (revision 9ad3a41ab2a10db0059e1decdbf3ec038f348e08)
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 };
612