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