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