xref: /dpdk/lib/graph/graph_pcap.c (revision 166591931b72700d8e499fbc008cf14d8e6ce0e8)
19b72ea1fSAmit Prakash Shukla /* SPDX-License-Identifier: BSD-3-Clause
29b72ea1fSAmit Prakash Shukla  * Copyright(C) 2023 Marvell International Ltd.
39b72ea1fSAmit Prakash Shukla  */
49b72ea1fSAmit Prakash Shukla 
59b72ea1fSAmit Prakash Shukla #include <errno.h>
69b72ea1fSAmit Prakash Shukla #include <pwd.h>
79b72ea1fSAmit Prakash Shukla #include <stdlib.h>
89b72ea1fSAmit Prakash Shukla #include <unistd.h>
99b72ea1fSAmit Prakash Shukla 
10df5908c9SStephen Hemminger #include <rte_ethdev.h>
119b72ea1fSAmit Prakash Shukla #include <rte_mbuf.h>
129b72ea1fSAmit Prakash Shukla #include <rte_pcapng.h>
139b72ea1fSAmit Prakash Shukla 
14a2bc0584SZhirun Yan #include "rte_graph_worker.h"
159b72ea1fSAmit Prakash Shukla 
169b72ea1fSAmit Prakash Shukla #include "graph_pcap_private.h"
179b72ea1fSAmit Prakash Shukla 
189b72ea1fSAmit Prakash Shukla #define GRAPH_PCAP_BUF_SZ	128
199b72ea1fSAmit Prakash Shukla #define GRAPH_PCAP_NUM_PACKETS	1024
209b72ea1fSAmit Prakash Shukla #define GRAPH_PCAP_PKT_POOL	"graph_pcap_pkt_pool"
219b72ea1fSAmit Prakash Shukla #define GRAPH_PCAP_FILE_NAME	"dpdk_graph_pcap_capture_XXXXXX.pcapng"
229b72ea1fSAmit Prakash Shukla 
239b72ea1fSAmit Prakash Shukla /* For multi-process, packets are captured in separate files. */
249b72ea1fSAmit Prakash Shukla static rte_pcapng_t *pcapng_fd;
259b72ea1fSAmit Prakash Shukla static bool pcap_enable;
269b72ea1fSAmit Prakash Shukla struct rte_mempool *pkt_mp;
279b72ea1fSAmit Prakash Shukla 
289b72ea1fSAmit Prakash Shukla void
graph_pcap_enable(bool val)299b72ea1fSAmit Prakash Shukla graph_pcap_enable(bool val)
309b72ea1fSAmit Prakash Shukla {
319b72ea1fSAmit Prakash Shukla 	pcap_enable = val;
329b72ea1fSAmit Prakash Shukla }
339b72ea1fSAmit Prakash Shukla 
349b72ea1fSAmit Prakash Shukla int
graph_pcap_is_enable(void)359b72ea1fSAmit Prakash Shukla graph_pcap_is_enable(void)
369b72ea1fSAmit Prakash Shukla {
379b72ea1fSAmit Prakash Shukla 	return pcap_enable;
389b72ea1fSAmit Prakash Shukla }
399b72ea1fSAmit Prakash Shukla 
409b72ea1fSAmit Prakash Shukla void
graph_pcap_exit(struct rte_graph * graph)419b72ea1fSAmit Prakash Shukla graph_pcap_exit(struct rte_graph *graph)
429b72ea1fSAmit Prakash Shukla {
439b72ea1fSAmit Prakash Shukla 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
449b72ea1fSAmit Prakash Shukla 		rte_mempool_free(pkt_mp);
459b72ea1fSAmit Prakash Shukla 
469b72ea1fSAmit Prakash Shukla 	if (pcapng_fd) {
479b72ea1fSAmit Prakash Shukla 		rte_pcapng_close(pcapng_fd);
489b72ea1fSAmit Prakash Shukla 		pcapng_fd = NULL;
499b72ea1fSAmit Prakash Shukla 	}
509b72ea1fSAmit Prakash Shukla 
519b72ea1fSAmit Prakash Shukla 	/* Disable pcap. */
529b72ea1fSAmit Prakash Shukla 	graph->pcap_enable = 0;
539b72ea1fSAmit Prakash Shukla 	graph_pcap_enable(0);
549b72ea1fSAmit Prakash Shukla }
559b72ea1fSAmit Prakash Shukla 
569b72ea1fSAmit Prakash Shukla static int
graph_pcap_default_path_get(char ** dir_path)579b72ea1fSAmit Prakash Shukla graph_pcap_default_path_get(char **dir_path)
589b72ea1fSAmit Prakash Shukla {
599b72ea1fSAmit Prakash Shukla 	struct passwd *pwd;
609b72ea1fSAmit Prakash Shukla 	char *home_dir;
619b72ea1fSAmit Prakash Shukla 
629b72ea1fSAmit Prakash Shukla 	/* First check for shell environment variable */
639b72ea1fSAmit Prakash Shukla 	home_dir = getenv("HOME");
649b72ea1fSAmit Prakash Shukla 	if (home_dir == NULL) {
659b72ea1fSAmit Prakash Shukla 		graph_warn("Home env not preset.");
669b72ea1fSAmit Prakash Shukla 		/* Fallback to password file entry */
679b72ea1fSAmit Prakash Shukla 		pwd = getpwuid(getuid());
689b72ea1fSAmit Prakash Shukla 		if (pwd == NULL)
699b72ea1fSAmit Prakash Shukla 			return -EINVAL;
709b72ea1fSAmit Prakash Shukla 
719b72ea1fSAmit Prakash Shukla 		home_dir = pwd->pw_dir;
729b72ea1fSAmit Prakash Shukla 	}
739b72ea1fSAmit Prakash Shukla 
749b72ea1fSAmit Prakash Shukla 	/* Append default pcap file to directory */
759b72ea1fSAmit Prakash Shukla 	if (asprintf(dir_path, "%s/%s", home_dir, GRAPH_PCAP_FILE_NAME) == -1)
769b72ea1fSAmit Prakash Shukla 		return -ENOMEM;
779b72ea1fSAmit Prakash Shukla 
789b72ea1fSAmit Prakash Shukla 	return 0;
799b72ea1fSAmit Prakash Shukla }
809b72ea1fSAmit Prakash Shukla 
819b72ea1fSAmit Prakash Shukla int
graph_pcap_file_open(const char * filename)829b72ea1fSAmit Prakash Shukla graph_pcap_file_open(const char *filename)
839b72ea1fSAmit Prakash Shukla {
84df5908c9SStephen Hemminger 	int fd, ret;
85df5908c9SStephen Hemminger 	uint16_t portid;
869b72ea1fSAmit Prakash Shukla 	char file_name[RTE_GRAPH_PCAP_FILE_SZ];
879b72ea1fSAmit Prakash Shukla 	char *pcap_dir;
889b72ea1fSAmit Prakash Shukla 
899b72ea1fSAmit Prakash Shukla 	if (pcapng_fd)
909b72ea1fSAmit Prakash Shukla 		goto done;
919b72ea1fSAmit Prakash Shukla 
929b72ea1fSAmit Prakash Shukla 	if (!filename || filename[0] == '\0') {
939b72ea1fSAmit Prakash Shukla 		if (graph_pcap_default_path_get(&pcap_dir) < 0)
949b72ea1fSAmit Prakash Shukla 			return -1;
959b72ea1fSAmit Prakash Shukla 		snprintf(file_name, RTE_GRAPH_PCAP_FILE_SZ, "%s", pcap_dir);
969b72ea1fSAmit Prakash Shukla 		free(pcap_dir);
979b72ea1fSAmit Prakash Shukla 	} else {
989b72ea1fSAmit Prakash Shukla 		snprintf(file_name, RTE_GRAPH_PCAP_FILE_SZ, "%s_XXXXXX.pcapng",
999b72ea1fSAmit Prakash Shukla 			 filename);
1009b72ea1fSAmit Prakash Shukla 	}
1019b72ea1fSAmit Prakash Shukla 
1029b72ea1fSAmit Prakash Shukla 	fd = mkstemps(file_name, strlen(".pcapng"));
1039b72ea1fSAmit Prakash Shukla 	if (fd < 0) {
1049b72ea1fSAmit Prakash Shukla 		graph_err("mkstemps() failure");
1059b72ea1fSAmit Prakash Shukla 		return -1;
1069b72ea1fSAmit Prakash Shukla 	}
1079b72ea1fSAmit Prakash Shukla 
1089b72ea1fSAmit Prakash Shukla 	graph_info("pcap filename: %s", file_name);
1099b72ea1fSAmit Prakash Shukla 
1109b72ea1fSAmit Prakash Shukla 	/* Open a capture file */
1119b72ea1fSAmit Prakash Shukla 	pcapng_fd = rte_pcapng_fdopen(fd, NULL, NULL, "Graph pcap tracer",
1129b72ea1fSAmit Prakash Shukla 				      NULL);
1139b72ea1fSAmit Prakash Shukla 	if (pcapng_fd == NULL) {
1149b72ea1fSAmit Prakash Shukla 		graph_err("Graph rte_pcapng_fdopen failed.");
115df5908c9SStephen Hemminger 		goto error;
116df5908c9SStephen Hemminger 	}
117df5908c9SStephen Hemminger 
118df5908c9SStephen Hemminger 	/* Add the configured interfaces as possible capture ports */
119df5908c9SStephen Hemminger 	RTE_ETH_FOREACH_DEV(portid) {
120df5908c9SStephen Hemminger 		ret = rte_pcapng_add_interface(pcapng_fd, portid,
121df5908c9SStephen Hemminger 					       NULL, NULL, NULL);
122df5908c9SStephen Hemminger 		if (ret < 0) {
123df5908c9SStephen Hemminger 			graph_err("Graph rte_pcapng_add_interface port %u failed: %d",
124df5908c9SStephen Hemminger 				  portid, ret);
125df5908c9SStephen Hemminger 			goto error;
126df5908c9SStephen Hemminger 		}
1279b72ea1fSAmit Prakash Shukla 	}
1289b72ea1fSAmit Prakash Shukla 
1299b72ea1fSAmit Prakash Shukla done:
1309b72ea1fSAmit Prakash Shukla 	return 0;
131df5908c9SStephen Hemminger error:
132df5908c9SStephen Hemminger 	if (pcapng_fd != NULL) {
133df5908c9SStephen Hemminger 		rte_pcapng_close(pcapng_fd);
134df5908c9SStephen Hemminger 		pcapng_fd = NULL;
135df5908c9SStephen Hemminger 	}
136df5908c9SStephen Hemminger 	close(fd);
137df5908c9SStephen Hemminger 	return -1;
1389b72ea1fSAmit Prakash Shukla }
1399b72ea1fSAmit Prakash Shukla 
1409b72ea1fSAmit Prakash Shukla int
graph_pcap_mp_init(void)1419b72ea1fSAmit Prakash Shukla graph_pcap_mp_init(void)
1429b72ea1fSAmit Prakash Shukla {
1439b72ea1fSAmit Prakash Shukla 	pkt_mp = rte_mempool_lookup(GRAPH_PCAP_PKT_POOL);
1449b72ea1fSAmit Prakash Shukla 	if (pkt_mp)
1459b72ea1fSAmit Prakash Shukla 		goto done;
1469b72ea1fSAmit Prakash Shukla 
1479b72ea1fSAmit Prakash Shukla 	/* Make a pool for cloned packets */
1489b72ea1fSAmit Prakash Shukla 	pkt_mp = rte_pktmbuf_pool_create_by_ops(GRAPH_PCAP_PKT_POOL,
1499b72ea1fSAmit Prakash Shukla 			IOV_MAX + RTE_GRAPH_BURST_SIZE,	0, 0,
1509b72ea1fSAmit Prakash Shukla 			rte_pcapng_mbuf_size(RTE_MBUF_DEFAULT_BUF_SIZE),
1519b72ea1fSAmit Prakash Shukla 			SOCKET_ID_ANY, "ring_mp_mc");
1529b72ea1fSAmit Prakash Shukla 	if (pkt_mp == NULL) {
1539b72ea1fSAmit Prakash Shukla 		graph_err("Cannot create mempool for graph pcap capture.");
1549b72ea1fSAmit Prakash Shukla 		return -1;
1559b72ea1fSAmit Prakash Shukla 	}
1569b72ea1fSAmit Prakash Shukla 
1579b72ea1fSAmit Prakash Shukla done:
1589b72ea1fSAmit Prakash Shukla 	return 0;
1599b72ea1fSAmit Prakash Shukla }
1609b72ea1fSAmit Prakash Shukla 
1619b72ea1fSAmit Prakash Shukla int
graph_pcap_init(struct graph * graph)1629b72ea1fSAmit Prakash Shukla graph_pcap_init(struct graph *graph)
1639b72ea1fSAmit Prakash Shukla {
1649b72ea1fSAmit Prakash Shukla 	struct rte_graph *graph_data = graph->graph;
1659b72ea1fSAmit Prakash Shukla 
1669b72ea1fSAmit Prakash Shukla 	if (graph_pcap_file_open(graph->pcap_filename) < 0)
1679b72ea1fSAmit Prakash Shukla 		goto error;
1689b72ea1fSAmit Prakash Shukla 
1699b72ea1fSAmit Prakash Shukla 	if (graph_pcap_mp_init() < 0)
1709b72ea1fSAmit Prakash Shukla 		goto error;
1719b72ea1fSAmit Prakash Shukla 
1729b72ea1fSAmit Prakash Shukla 	/* User configured number of packets to capture. */
1739b72ea1fSAmit Prakash Shukla 	if (graph->num_pkt_to_capture)
1749b72ea1fSAmit Prakash Shukla 		graph_data->nb_pkt_to_capture = graph->num_pkt_to_capture;
1759b72ea1fSAmit Prakash Shukla 	else
1769b72ea1fSAmit Prakash Shukla 		graph_data->nb_pkt_to_capture = GRAPH_PCAP_NUM_PACKETS;
1779b72ea1fSAmit Prakash Shukla 
1789b72ea1fSAmit Prakash Shukla 	/* All good. Now populate data for secondary process. */
1799b72ea1fSAmit Prakash Shukla 	rte_strscpy(graph_data->pcap_filename, graph->pcap_filename, RTE_GRAPH_PCAP_FILE_SZ);
1809b72ea1fSAmit Prakash Shukla 	graph_data->pcap_enable = 1;
1819b72ea1fSAmit Prakash Shukla 
1829b72ea1fSAmit Prakash Shukla 	return 0;
1839b72ea1fSAmit Prakash Shukla 
1849b72ea1fSAmit Prakash Shukla error:
1859b72ea1fSAmit Prakash Shukla 	graph_pcap_exit(graph_data);
1869b72ea1fSAmit Prakash Shukla 	graph_pcap_enable(0);
1879b72ea1fSAmit Prakash Shukla 	graph_err("Graph pcap initialization failed. Disabling pcap trace.");
1889b72ea1fSAmit Prakash Shukla 	return -1;
1899b72ea1fSAmit Prakash Shukla }
1909b72ea1fSAmit Prakash Shukla 
1919b72ea1fSAmit Prakash Shukla uint16_t
graph_pcap_dispatch(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)1929b72ea1fSAmit Prakash Shukla graph_pcap_dispatch(struct rte_graph *graph,
1939b72ea1fSAmit Prakash Shukla 			      struct rte_node *node, void **objs,
1949b72ea1fSAmit Prakash Shukla 			      uint16_t nb_objs)
1959b72ea1fSAmit Prakash Shukla {
1969b72ea1fSAmit Prakash Shukla 	struct rte_mbuf *mbuf_clones[RTE_GRAPH_BURST_SIZE];
1979b72ea1fSAmit Prakash Shukla 	char buffer[GRAPH_PCAP_BUF_SZ];
1989b72ea1fSAmit Prakash Shukla 	uint64_t i, num_packets;
1999b72ea1fSAmit Prakash Shukla 	struct rte_mbuf *mbuf;
2009b72ea1fSAmit Prakash Shukla 	ssize_t len;
2019b72ea1fSAmit Prakash Shukla 
2029b72ea1fSAmit Prakash Shukla 	if (!nb_objs || (graph->nb_pkt_captured >= graph->nb_pkt_to_capture))
2039b72ea1fSAmit Prakash Shukla 		goto done;
2049b72ea1fSAmit Prakash Shukla 
2059b72ea1fSAmit Prakash Shukla 	num_packets = graph->nb_pkt_to_capture - graph->nb_pkt_captured;
2069b72ea1fSAmit Prakash Shukla 	/* nb_objs will never be greater than RTE_GRAPH_BURST_SIZE */
2079b72ea1fSAmit Prakash Shukla 	if (num_packets > nb_objs)
2089b72ea1fSAmit Prakash Shukla 		num_packets = nb_objs;
2099b72ea1fSAmit Prakash Shukla 
2109b72ea1fSAmit Prakash Shukla 	snprintf(buffer, GRAPH_PCAP_BUF_SZ, "%s: %s", graph->name, node->name);
2119b72ea1fSAmit Prakash Shukla 
2129b72ea1fSAmit Prakash Shukla 	for (i = 0; i < num_packets; i++) {
2139b72ea1fSAmit Prakash Shukla 		struct rte_mbuf *mc;
2149b72ea1fSAmit Prakash Shukla 		mbuf = (struct rte_mbuf *)objs[i];
2159b72ea1fSAmit Prakash Shukla 
2169b72ea1fSAmit Prakash Shukla 		mc = rte_pcapng_copy(mbuf->port, 0, mbuf, pkt_mp, mbuf->pkt_len,
217*16659193SStephen Hemminger 				     0, buffer);
2189b72ea1fSAmit Prakash Shukla 		if (mc == NULL)
2199b72ea1fSAmit Prakash Shukla 			break;
2209b72ea1fSAmit Prakash Shukla 
2219b72ea1fSAmit Prakash Shukla 		mbuf_clones[i] = mc;
2229b72ea1fSAmit Prakash Shukla 	}
2239b72ea1fSAmit Prakash Shukla 
2249b72ea1fSAmit Prakash Shukla 	/* write it to capture file */
2259b72ea1fSAmit Prakash Shukla 	len = rte_pcapng_write_packets(pcapng_fd, mbuf_clones, i);
2269b72ea1fSAmit Prakash Shukla 	rte_pktmbuf_free_bulk(mbuf_clones, i);
2279b72ea1fSAmit Prakash Shukla 	if (len <= 0)
2289b72ea1fSAmit Prakash Shukla 		goto done;
2299b72ea1fSAmit Prakash Shukla 
2309b72ea1fSAmit Prakash Shukla 	graph->nb_pkt_captured += i;
2319b72ea1fSAmit Prakash Shukla 
2329b72ea1fSAmit Prakash Shukla done:
2339b72ea1fSAmit Prakash Shukla 	return node->original_process(graph, node, objs, nb_objs);
2349b72ea1fSAmit Prakash Shukla }
235