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