xref: /dpdk/lib/port/rte_port_source_sink.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
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 	if (pkt_len_aligns)
167 		rte_free(pkt_len_aligns);
168 	if (port->pkt_len)
169 		rte_free(port->pkt_len);
170 	if (port->pkts)
171 		rte_free(port->pkts);
172 	if (port->pkt_buff)
173 		rte_free(port->pkt_buff);
174 
175 	return -1;
176 }
177 
178 #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id)	\
179 	pcap_source_load(port, file_name, n_bytes, socket_id)
180 
181 #else /* RTE_PORT_PCAP */
182 
183 #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id)	\
184 ({								\
185 	int _ret = 0;						\
186 								\
187 	if (file_name) {					\
188 		RTE_LOG(ERR, PORT, "Source port field "		\
189 			"\"file_name\" is not NULL.\n");	\
190 		_ret = -1;					\
191 	}							\
192 								\
193 	_ret;							\
194 })
195 
196 #endif /* RTE_PORT_PCAP */
197 
198 static void *
199 rte_port_source_create(void *params, int socket_id)
200 {
201 	struct rte_port_source_params *p =
202 			params;
203 	struct rte_port_source *port;
204 
205 	/* Check input arguments*/
206 	if ((p == NULL) || (p->mempool == NULL)) {
207 		RTE_LOG(ERR, PORT, "%s: Invalid params\n", __func__);
208 		return NULL;
209 	}
210 
211 	/* Memory allocation */
212 	port = rte_zmalloc_socket("PORT", sizeof(*port),
213 			RTE_CACHE_LINE_SIZE, socket_id);
214 	if (port == NULL) {
215 		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
216 		return NULL;
217 	}
218 
219 	/* Initialization */
220 	port->mempool = (struct rte_mempool *) p->mempool;
221 
222 	if (p->file_name) {
223 		int status = PCAP_SOURCE_LOAD(port, p->file_name,
224 			p->n_bytes_per_pkt, socket_id);
225 
226 		if (status < 0) {
227 			rte_free(port);
228 			port = NULL;
229 		}
230 	}
231 
232 	return port;
233 }
234 
235 static int
236 rte_port_source_free(void *port)
237 {
238 	struct rte_port_source *p =
239 			port;
240 
241 	/* Check input parameters */
242 	if (p == NULL)
243 		return 0;
244 
245 	if (p->pkt_len)
246 		rte_free(p->pkt_len);
247 	if (p->pkts)
248 		rte_free(p->pkts);
249 	if (p->pkt_buff)
250 		rte_free(p->pkt_buff);
251 
252 	rte_free(p);
253 
254 	return 0;
255 }
256 
257 static int
258 rte_port_source_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
259 {
260 	struct rte_port_source *p = port;
261 	uint32_t i;
262 
263 	if (rte_pktmbuf_alloc_bulk(p->mempool, pkts, n_pkts) != 0)
264 		return 0;
265 
266 	if (p->pkt_buff != NULL) {
267 		for (i = 0; i < n_pkts; i++) {
268 			uint8_t *pkt_data = rte_pktmbuf_mtod(pkts[i],
269 				uint8_t *);
270 
271 			rte_memcpy(pkt_data, p->pkts[p->pkt_index],
272 					p->pkt_len[p->pkt_index]);
273 			pkts[i]->data_len = p->pkt_len[p->pkt_index];
274 			pkts[i]->pkt_len = pkts[i]->data_len;
275 
276 			p->pkt_index++;
277 			if (p->pkt_index >= p->n_pkts)
278 				p->pkt_index = 0;
279 		}
280 	}
281 
282 	RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(p, n_pkts);
283 
284 	return n_pkts;
285 }
286 
287 static int
288 rte_port_source_stats_read(void *port,
289 		struct rte_port_in_stats *stats, int clear)
290 {
291 	struct rte_port_source *p =
292 		port;
293 
294 	if (stats != NULL)
295 		memcpy(stats, &p->stats, sizeof(p->stats));
296 
297 	if (clear)
298 		memset(&p->stats, 0, sizeof(p->stats));
299 
300 	return 0;
301 }
302 
303 /*
304  * Port SINK
305  */
306 #ifdef RTE_PORT_STATS_COLLECT
307 
308 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) \
309 	(port->stats.n_pkts_in += val)
310 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) \
311 	(port->stats.n_pkts_drop += val)
312 
313 #else
314 
315 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val)
316 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val)
317 
318 #endif
319 
320 struct rte_port_sink {
321 	struct rte_port_out_stats stats;
322 
323 	/* PCAP dumper handle and pkts number */
324 	void *dumper;
325 	uint32_t max_pkts;
326 	uint32_t pkt_index;
327 	uint32_t dump_finish;
328 };
329 
330 #ifdef RTE_PORT_PCAP
331 
332 static int
333 pcap_sink_open(struct rte_port_sink *port,
334 	const char *file_name,
335 	uint32_t max_n_pkts)
336 {
337 	pcap_t *tx_pcap;
338 	pcap_dumper_t *pcap_dumper;
339 
340 	/** Open a dead pcap handler for opening dumper file */
341 	tx_pcap = pcap_open_dead(DLT_EN10MB, 65535);
342 	if (tx_pcap == NULL) {
343 		RTE_LOG(ERR, PORT, "Cannot open pcap dead handler\n");
344 		return -1;
345 	}
346 
347 	/* The dumper is created using the previous pcap_t reference */
348 	pcap_dumper = pcap_dump_open(tx_pcap, file_name);
349 	if (pcap_dumper == NULL) {
350 		RTE_LOG(ERR, PORT, "Failed to open pcap file "
351 			"\"%s\" for writing\n", file_name);
352 		return -1;
353 	}
354 
355 	port->dumper = pcap_dumper;
356 	port->max_pkts = max_n_pkts;
357 	port->pkt_index = 0;
358 	port->dump_finish = 0;
359 
360 	RTE_LOG(INFO, PORT, "Ready to dump packets to file \"%s\"\n",
361 		file_name);
362 
363 	return 0;
364 }
365 
366 static void
367 pcap_sink_write_pkt(struct rte_port_sink *port, struct rte_mbuf *mbuf)
368 {
369 	uint8_t *pcap_dumper = (port->dumper);
370 	struct pcap_pkthdr pcap_hdr;
371 	uint8_t jumbo_pkt_buf[RTE_ETHER_MAX_JUMBO_FRAME_LEN];
372 	uint8_t *pkt;
373 
374 	/* Maximum num packets already reached */
375 	if (port->dump_finish)
376 		return;
377 
378 	pkt = rte_pktmbuf_mtod(mbuf, uint8_t *);
379 
380 	pcap_hdr.len = mbuf->pkt_len;
381 	pcap_hdr.caplen = pcap_hdr.len;
382 	gettimeofday(&(pcap_hdr.ts), NULL);
383 
384 	if (mbuf->nb_segs > 1) {
385 		struct rte_mbuf *jumbo_mbuf;
386 		uint32_t pkt_index = 0;
387 
388 		/* if packet size longer than RTE_ETHER_MAX_JUMBO_FRAME_LEN,
389 		 * ignore it.
390 		 */
391 		if (mbuf->pkt_len > RTE_ETHER_MAX_JUMBO_FRAME_LEN)
392 			return;
393 
394 		for (jumbo_mbuf = mbuf; jumbo_mbuf != NULL;
395 				jumbo_mbuf = jumbo_mbuf->next) {
396 			rte_memcpy(&jumbo_pkt_buf[pkt_index],
397 				rte_pktmbuf_mtod(jumbo_mbuf, uint8_t *),
398 				jumbo_mbuf->data_len);
399 			pkt_index += jumbo_mbuf->data_len;
400 		}
401 
402 		jumbo_pkt_buf[pkt_index] = '\0';
403 
404 		pkt = jumbo_pkt_buf;
405 	}
406 
407 	pcap_dump(pcap_dumper, &pcap_hdr, pkt);
408 
409 	port->pkt_index++;
410 
411 	if ((port->max_pkts != 0) && (port->pkt_index >= port->max_pkts)) {
412 		port->dump_finish = 1;
413 		RTE_LOG(INFO, PORT, "Dumped %u packets to file\n",
414 				port->pkt_index);
415 	}
416 
417 }
418 
419 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts)		\
420 	pcap_sink_open(port, file_name, max_n_pkts)
421 
422 #define PCAP_SINK_WRITE_PKT(port, mbuf)				\
423 	pcap_sink_write_pkt(port, mbuf)
424 
425 #define PCAP_SINK_FLUSH_PKT(dumper)				\
426 do {								\
427 	if (dumper)						\
428 		pcap_dump_flush((pcap_dumper_t *)dumper);	\
429 } while (0)
430 
431 #define PCAP_SINK_CLOSE(dumper)					\
432 do {								\
433 	if (dumper)						\
434 		pcap_dump_close((pcap_dumper_t *)dumper);	\
435 } while (0)
436 
437 #else
438 
439 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts)		\
440 ({								\
441 	int _ret = 0;						\
442 								\
443 	if (file_name) {					\
444 		RTE_LOG(ERR, PORT, "Sink port field "		\
445 			"\"file_name\" is not NULL.\n");	\
446 		_ret = -1;					\
447 	}							\
448 								\
449 	_ret;							\
450 })
451 
452 #define PCAP_SINK_WRITE_PKT(port, mbuf) {}
453 
454 #define PCAP_SINK_FLUSH_PKT(dumper)
455 
456 #define PCAP_SINK_CLOSE(dumper)
457 
458 #endif
459 
460 static void *
461 rte_port_sink_create(void *params, int socket_id)
462 {
463 	struct rte_port_sink *port;
464 	struct rte_port_sink_params *p = params;
465 
466 	/* Memory allocation */
467 	port = rte_zmalloc_socket("PORT", sizeof(*port),
468 			RTE_CACHE_LINE_SIZE, socket_id);
469 	if (port == NULL) {
470 		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
471 		return NULL;
472 	}
473 
474 	if (!p)
475 		return port;
476 
477 	if (p->file_name) {
478 		int status = PCAP_SINK_OPEN(port, p->file_name,
479 			p->max_n_pkts);
480 
481 		if (status < 0) {
482 			rte_free(port);
483 			port = NULL;
484 		}
485 	}
486 
487 	return port;
488 }
489 
490 static int
491 rte_port_sink_tx(void *port, struct rte_mbuf *pkt)
492 {
493 	struct rte_port_sink *p = port;
494 
495 	RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
496 	if (p->dumper != NULL)
497 		PCAP_SINK_WRITE_PKT(p, pkt);
498 	rte_pktmbuf_free(pkt);
499 	RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
500 
501 	return 0;
502 }
503 
504 static int
505 rte_port_sink_tx_bulk(void *port, struct rte_mbuf **pkts,
506 	uint64_t pkts_mask)
507 {
508 	struct rte_port_sink *p = port;
509 
510 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
511 		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
512 		uint32_t i;
513 
514 		RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, n_pkts);
515 		RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, n_pkts);
516 
517 		if (p->dumper) {
518 			for (i = 0; i < n_pkts; i++)
519 				PCAP_SINK_WRITE_PKT(p, pkts[i]);
520 		}
521 
522 		for (i = 0; i < n_pkts; i++) {
523 			struct rte_mbuf *pkt = pkts[i];
524 
525 			rte_pktmbuf_free(pkt);
526 		}
527 
528 	} else {
529 		if (p->dumper) {
530 			uint64_t dump_pkts_mask = pkts_mask;
531 			uint32_t pkt_index;
532 
533 			for ( ; dump_pkts_mask; ) {
534 				pkt_index = __builtin_ctzll(
535 					dump_pkts_mask);
536 				PCAP_SINK_WRITE_PKT(p, pkts[pkt_index]);
537 				dump_pkts_mask &= ~(1LLU << pkt_index);
538 			}
539 		}
540 
541 		for ( ; pkts_mask; ) {
542 			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
543 			uint64_t pkt_mask = 1LLU << pkt_index;
544 			struct rte_mbuf *pkt = pkts[pkt_index];
545 
546 			RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
547 			RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
548 			rte_pktmbuf_free(pkt);
549 			pkts_mask &= ~pkt_mask;
550 		}
551 	}
552 
553 	return 0;
554 }
555 
556 static int
557 rte_port_sink_flush(void *port)
558 {
559 	struct rte_port_sink *p =
560 			port;
561 
562 	if (p == NULL)
563 		return 0;
564 
565 	PCAP_SINK_FLUSH_PKT(p->dumper);
566 
567 	return 0;
568 }
569 
570 static int
571 rte_port_sink_free(void *port)
572 {
573 	struct rte_port_sink *p =
574 			port;
575 
576 	if (p == NULL)
577 		return 0;
578 
579 	PCAP_SINK_CLOSE(p->dumper);
580 
581 	rte_free(p);
582 
583 	return 0;
584 }
585 
586 static int
587 rte_port_sink_stats_read(void *port, struct rte_port_out_stats *stats,
588 		int clear)
589 {
590 	struct rte_port_sink *p =
591 		port;
592 
593 	if (stats != NULL)
594 		memcpy(stats, &p->stats, sizeof(p->stats));
595 
596 	if (clear)
597 		memset(&p->stats, 0, sizeof(p->stats));
598 
599 	return 0;
600 }
601 
602 /*
603  * Summary of port operations
604  */
605 struct rte_port_in_ops rte_port_source_ops = {
606 	.f_create = rte_port_source_create,
607 	.f_free = rte_port_source_free,
608 	.f_rx = rte_port_source_rx,
609 	.f_stats = rte_port_source_stats_read,
610 };
611 
612 struct rte_port_out_ops rte_port_sink_ops = {
613 	.f_create = rte_port_sink_create,
614 	.f_free = rte_port_sink_free,
615 	.f_tx = rte_port_sink_tx,
616 	.f_tx_bulk = rte_port_sink_tx_bulk,
617 	.f_flush = rte_port_sink_flush,
618 	.f_stats = rte_port_sink_stats_read,
619 };
620