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