1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2023 Marvell International Ltd. 3 */ 4 5 #include <errno.h> 6 #include <pwd.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 10 #include <rte_mbuf.h> 11 #include <rte_pcapng.h> 12 13 #include "rte_graph_worker.h" 14 15 #include "graph_pcap_private.h" 16 17 #define GRAPH_PCAP_BUF_SZ 128 18 #define GRAPH_PCAP_NUM_PACKETS 1024 19 #define GRAPH_PCAP_PKT_POOL "graph_pcap_pkt_pool" 20 #define GRAPH_PCAP_FILE_NAME "dpdk_graph_pcap_capture_XXXXXX.pcapng" 21 22 /* For multi-process, packets are captured in separate files. */ 23 static rte_pcapng_t *pcapng_fd; 24 static bool pcap_enable; 25 struct rte_mempool *pkt_mp; 26 27 void 28 graph_pcap_enable(bool val) 29 { 30 pcap_enable = val; 31 } 32 33 int 34 graph_pcap_is_enable(void) 35 { 36 return pcap_enable; 37 } 38 39 void 40 graph_pcap_exit(struct rte_graph *graph) 41 { 42 if (rte_eal_process_type() == RTE_PROC_PRIMARY) 43 rte_mempool_free(pkt_mp); 44 45 if (pcapng_fd) { 46 rte_pcapng_close(pcapng_fd); 47 pcapng_fd = NULL; 48 } 49 50 /* Disable pcap. */ 51 graph->pcap_enable = 0; 52 graph_pcap_enable(0); 53 } 54 55 static int 56 graph_pcap_default_path_get(char **dir_path) 57 { 58 struct passwd *pwd; 59 char *home_dir; 60 61 /* First check for shell environment variable */ 62 home_dir = getenv("HOME"); 63 if (home_dir == NULL) { 64 graph_warn("Home env not preset."); 65 /* Fallback to password file entry */ 66 pwd = getpwuid(getuid()); 67 if (pwd == NULL) 68 return -EINVAL; 69 70 home_dir = pwd->pw_dir; 71 } 72 73 /* Append default pcap file to directory */ 74 if (asprintf(dir_path, "%s/%s", home_dir, GRAPH_PCAP_FILE_NAME) == -1) 75 return -ENOMEM; 76 77 return 0; 78 } 79 80 int 81 graph_pcap_file_open(const char *filename) 82 { 83 int fd; 84 char file_name[RTE_GRAPH_PCAP_FILE_SZ]; 85 char *pcap_dir; 86 87 if (pcapng_fd) 88 goto done; 89 90 if (!filename || filename[0] == '\0') { 91 if (graph_pcap_default_path_get(&pcap_dir) < 0) 92 return -1; 93 snprintf(file_name, RTE_GRAPH_PCAP_FILE_SZ, "%s", pcap_dir); 94 free(pcap_dir); 95 } else { 96 snprintf(file_name, RTE_GRAPH_PCAP_FILE_SZ, "%s_XXXXXX.pcapng", 97 filename); 98 } 99 100 fd = mkstemps(file_name, strlen(".pcapng")); 101 if (fd < 0) { 102 graph_err("mkstemps() failure"); 103 return -1; 104 } 105 106 graph_info("pcap filename: %s", file_name); 107 108 /* Open a capture file */ 109 pcapng_fd = rte_pcapng_fdopen(fd, NULL, NULL, "Graph pcap tracer", 110 NULL); 111 if (pcapng_fd == NULL) { 112 graph_err("Graph rte_pcapng_fdopen failed."); 113 close(fd); 114 return -1; 115 } 116 117 done: 118 return 0; 119 } 120 121 int 122 graph_pcap_mp_init(void) 123 { 124 pkt_mp = rte_mempool_lookup(GRAPH_PCAP_PKT_POOL); 125 if (pkt_mp) 126 goto done; 127 128 /* Make a pool for cloned packets */ 129 pkt_mp = rte_pktmbuf_pool_create_by_ops(GRAPH_PCAP_PKT_POOL, 130 IOV_MAX + RTE_GRAPH_BURST_SIZE, 0, 0, 131 rte_pcapng_mbuf_size(RTE_MBUF_DEFAULT_BUF_SIZE), 132 SOCKET_ID_ANY, "ring_mp_mc"); 133 if (pkt_mp == NULL) { 134 graph_err("Cannot create mempool for graph pcap capture."); 135 return -1; 136 } 137 138 done: 139 return 0; 140 } 141 142 int 143 graph_pcap_init(struct graph *graph) 144 { 145 struct rte_graph *graph_data = graph->graph; 146 147 if (graph_pcap_file_open(graph->pcap_filename) < 0) 148 goto error; 149 150 if (graph_pcap_mp_init() < 0) 151 goto error; 152 153 /* User configured number of packets to capture. */ 154 if (graph->num_pkt_to_capture) 155 graph_data->nb_pkt_to_capture = graph->num_pkt_to_capture; 156 else 157 graph_data->nb_pkt_to_capture = GRAPH_PCAP_NUM_PACKETS; 158 159 /* All good. Now populate data for secondary process. */ 160 rte_strscpy(graph_data->pcap_filename, graph->pcap_filename, RTE_GRAPH_PCAP_FILE_SZ); 161 graph_data->pcap_enable = 1; 162 163 return 0; 164 165 error: 166 graph_pcap_exit(graph_data); 167 graph_pcap_enable(0); 168 graph_err("Graph pcap initialization failed. Disabling pcap trace."); 169 return -1; 170 } 171 172 uint16_t 173 graph_pcap_dispatch(struct rte_graph *graph, 174 struct rte_node *node, void **objs, 175 uint16_t nb_objs) 176 { 177 struct rte_mbuf *mbuf_clones[RTE_GRAPH_BURST_SIZE]; 178 char buffer[GRAPH_PCAP_BUF_SZ]; 179 uint64_t i, num_packets; 180 struct rte_mbuf *mbuf; 181 ssize_t len; 182 183 if (!nb_objs || (graph->nb_pkt_captured >= graph->nb_pkt_to_capture)) 184 goto done; 185 186 num_packets = graph->nb_pkt_to_capture - graph->nb_pkt_captured; 187 /* nb_objs will never be greater than RTE_GRAPH_BURST_SIZE */ 188 if (num_packets > nb_objs) 189 num_packets = nb_objs; 190 191 snprintf(buffer, GRAPH_PCAP_BUF_SZ, "%s: %s", graph->name, node->name); 192 193 for (i = 0; i < num_packets; i++) { 194 struct rte_mbuf *mc; 195 mbuf = (struct rte_mbuf *)objs[i]; 196 197 mc = rte_pcapng_copy(mbuf->port, 0, mbuf, pkt_mp, mbuf->pkt_len, 198 rte_get_tsc_cycles(), 0, buffer); 199 if (mc == NULL) 200 break; 201 202 mbuf_clones[i] = mc; 203 } 204 205 /* write it to capture file */ 206 len = rte_pcapng_write_packets(pcapng_fd, mbuf_clones, i); 207 rte_pktmbuf_free_bulk(mbuf_clones, i); 208 if (len <= 0) 209 goto done; 210 211 graph->nb_pkt_captured += i; 212 213 done: 214 return node->original_process(graph, node, objs, nb_objs); 215 } 216