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