xref: /dpdk/examples/ntb/ntb_fwd.c (revision 089e5ed727a15da2729cfee9b63533dd120bd04c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  */
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <inttypes.h>
7 #include <unistd.h>
8 #include <signal.h>
9 #include <string.h>
10 #include <getopt.h>
11 
12 #include <cmdline_parse_string.h>
13 #include <cmdline_socket.h>
14 #include <cmdline.h>
15 #include <rte_common.h>
16 #include <rte_rawdev.h>
17 #include <rte_lcore.h>
18 
19 #define NTB_DRV_NAME_LEN	7
20 static uint64_t max_file_size = 0x400000;
21 static uint8_t interactive = 1;
22 static uint16_t dev_id;
23 
24 /* *** Help command with introduction. *** */
25 struct cmd_help_result {
26 	cmdline_fixed_string_t help;
27 };
28 
29 static void cmd_help_parsed(__attribute__((unused)) void *parsed_result,
30 			    struct cmdline *cl,
31 			    __attribute__((unused)) void *data)
32 {
33 	cmdline_printf(
34 		cl,
35 		"\n"
36 		"The following commands are currently available:\n\n"
37 		"Control:\n"
38 		"    quit                                      :"
39 		" Quit the application.\n"
40 		"\nFile transmit:\n"
41 		"    send [path]                               :"
42 		" Send [path] file. (No more than %"PRIu64")\n"
43 		"    recv [path]                            :"
44 		" Receive file to [path]. Make sure sending is done"
45 		" on the other side.\n",
46 		max_file_size
47 	);
48 
49 }
50 
51 cmdline_parse_token_string_t cmd_help_help =
52 	TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
53 
54 cmdline_parse_inst_t cmd_help = {
55 	.f = cmd_help_parsed,
56 	.data = NULL,
57 	.help_str = "show help",
58 	.tokens = {
59 		(void *)&cmd_help_help,
60 		NULL,
61 	},
62 };
63 
64 /* *** QUIT *** */
65 struct cmd_quit_result {
66 	cmdline_fixed_string_t quit;
67 };
68 
69 static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
70 			    struct cmdline *cl,
71 			    __attribute__((unused)) void *data)
72 {
73 	/* Stop traffic and Close port. */
74 	rte_rawdev_stop(dev_id);
75 	rte_rawdev_close(dev_id);
76 
77 	cmdline_quit(cl);
78 }
79 
80 cmdline_parse_token_string_t cmd_quit_quit =
81 		TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
82 
83 cmdline_parse_inst_t cmd_quit = {
84 	.f = cmd_quit_parsed,
85 	.data = NULL,
86 	.help_str = "exit application",
87 	.tokens = {
88 		(void *)&cmd_quit_quit,
89 		NULL,
90 	},
91 };
92 
93 /* *** SEND FILE PARAMETERS *** */
94 struct cmd_sendfile_result {
95 	cmdline_fixed_string_t send_string;
96 	char filepath[];
97 };
98 
99 static void
100 cmd_sendfile_parsed(void *parsed_result,
101 		    __attribute__((unused)) struct cmdline *cl,
102 		    __attribute__((unused)) void *data)
103 {
104 	struct cmd_sendfile_result *res = parsed_result;
105 	struct rte_rawdev_buf *pkts_send[1];
106 	uint64_t rsize, size, link;
107 	uint8_t *buff;
108 	uint32_t val;
109 	FILE *file;
110 
111 	if (!rte_rawdevs[dev_id].started) {
112 		printf("Device needs to be up first. Try later.\n");
113 		return;
114 	}
115 
116 	rte_rawdev_get_attr(dev_id, "link_status", &link);
117 	if (!link) {
118 		printf("Link is not up, cannot send file.\n");
119 		return;
120 	}
121 
122 	file = fopen(res->filepath, "r");
123 	if (file == NULL) {
124 		printf("Fail to open the file.\n");
125 		return;
126 	}
127 
128 	if (fseek(file, 0, SEEK_END) < 0) {
129 		printf("Fail to get file size.\n");
130 		return;
131 	}
132 	size = ftell(file);
133 	if (fseek(file, 0, SEEK_SET) < 0) {
134 		printf("Fail to get file size.\n");
135 		return;
136 	}
137 
138 	/**
139 	 * No FIFO now. Only test memory. Limit sending file
140 	 * size <= max_file_size.
141 	 */
142 	if (size > max_file_size) {
143 		printf("Warning: The file is too large. Only send first"
144 		       " %"PRIu64" bits.\n", max_file_size);
145 		size = max_file_size;
146 	}
147 
148 	buff = (uint8_t *)malloc(size);
149 	rsize = fread(buff, size, 1, file);
150 	if (rsize != 1) {
151 		printf("Fail to read file.\n");
152 		fclose(file);
153 		free(buff);
154 		return;
155 	}
156 
157 	/* Tell remote about the file size. */
158 	val = size >> 32;
159 	rte_rawdev_set_attr(dev_id, "spad_user_0", val);
160 	val = size;
161 	rte_rawdev_set_attr(dev_id, "spad_user_1", val);
162 
163 	pkts_send[0] = (struct rte_rawdev_buf *)malloc
164 			(sizeof(struct rte_rawdev_buf));
165 	pkts_send[0]->buf_addr = buff;
166 
167 	if (rte_rawdev_enqueue_buffers(dev_id, pkts_send, 1,
168 				       (void *)(size_t)size)) {
169 		printf("Fail to enqueue.\n");
170 		goto clean;
171 	}
172 	printf("Done sending file.\n");
173 
174 clean:
175 	fclose(file);
176 	free(buff);
177 	free(pkts_send[0]);
178 }
179 
180 cmdline_parse_token_string_t cmd_send_file_send =
181 	TOKEN_STRING_INITIALIZER(struct cmd_sendfile_result, send_string,
182 				 "send");
183 cmdline_parse_token_string_t cmd_send_file_filepath =
184 	TOKEN_STRING_INITIALIZER(struct cmd_sendfile_result, filepath, NULL);
185 
186 
187 cmdline_parse_inst_t cmd_send_file = {
188 	.f = cmd_sendfile_parsed,
189 	.data = NULL,
190 	.help_str = "send <file_path>",
191 	.tokens = {
192 		(void *)&cmd_send_file_send,
193 		(void *)&cmd_send_file_filepath,
194 		NULL,
195 	},
196 };
197 
198 /* *** RECEIVE FILE PARAMETERS *** */
199 struct cmd_recvfile_result {
200 	cmdline_fixed_string_t recv_string;
201 	char filepath[];
202 };
203 
204 static void
205 cmd_recvfile_parsed(void *parsed_result,
206 		    __attribute__((unused)) struct cmdline *cl,
207 		    __attribute__((unused)) void *data)
208 {
209 	struct cmd_sendfile_result *res = parsed_result;
210 	struct rte_rawdev_buf *pkts_recv[1];
211 	uint8_t *buff;
212 	uint64_t val;
213 	size_t size;
214 	FILE *file;
215 
216 	if (!rte_rawdevs[dev_id].started) {
217 		printf("Device needs to be up first. Try later.\n");
218 		return;
219 	}
220 
221 	rte_rawdev_get_attr(dev_id, "link_status", &val);
222 	if (!val) {
223 		printf("Link is not up, cannot receive file.\n");
224 		return;
225 	}
226 
227 	file = fopen(res->filepath, "w");
228 	if (file == NULL) {
229 		printf("Fail to open the file.\n");
230 		return;
231 	}
232 
233 	rte_rawdev_get_attr(dev_id, "spad_user_0", &val);
234 	size = val << 32;
235 	rte_rawdev_get_attr(dev_id, "spad_user_1", &val);
236 	size |= val;
237 
238 	buff = (uint8_t *)malloc(size);
239 	pkts_recv[0] = (struct rte_rawdev_buf *)malloc
240 			(sizeof(struct rte_rawdev_buf));
241 	pkts_recv[0]->buf_addr = buff;
242 
243 	if (rte_rawdev_dequeue_buffers(dev_id, pkts_recv, 1, (void *)size)) {
244 		printf("Fail to dequeue.\n");
245 		goto clean;
246 	}
247 
248 	fwrite(buff, size, 1, file);
249 	printf("Done receiving to file.\n");
250 
251 clean:
252 	fclose(file);
253 	free(buff);
254 	free(pkts_recv[0]);
255 }
256 
257 cmdline_parse_token_string_t cmd_recv_file_recv =
258 	TOKEN_STRING_INITIALIZER(struct cmd_recvfile_result, recv_string,
259 				 "recv");
260 cmdline_parse_token_string_t cmd_recv_file_filepath =
261 	TOKEN_STRING_INITIALIZER(struct cmd_recvfile_result, filepath, NULL);
262 
263 
264 cmdline_parse_inst_t cmd_recv_file = {
265 	.f = cmd_recvfile_parsed,
266 	.data = NULL,
267 	.help_str = "recv <file_path>",
268 	.tokens = {
269 		(void *)&cmd_recv_file_recv,
270 		(void *)&cmd_recv_file_filepath,
271 		NULL,
272 	},
273 };
274 
275 /* list of instructions */
276 cmdline_parse_ctx_t main_ctx[] = {
277 	(cmdline_parse_inst_t *)&cmd_help,
278 	(cmdline_parse_inst_t *)&cmd_send_file,
279 	(cmdline_parse_inst_t *)&cmd_recv_file,
280 	(cmdline_parse_inst_t *)&cmd_quit,
281 	NULL,
282 };
283 
284 /* prompt function, called from main on MASTER lcore */
285 static void
286 prompt(void)
287 {
288 	struct cmdline *cl;
289 
290 	cl = cmdline_stdin_new(main_ctx, "ntb> ");
291 	if (cl == NULL)
292 		return;
293 
294 	cmdline_interact(cl);
295 	cmdline_stdin_exit(cl);
296 }
297 
298 static void
299 signal_handler(int signum)
300 {
301 	if (signum == SIGINT || signum == SIGTERM) {
302 		printf("\nSignal %d received, preparing to exit...\n", signum);
303 		signal(signum, SIG_DFL);
304 		kill(getpid(), signum);
305 	}
306 }
307 
308 static void
309 ntb_usage(const char *prgname)
310 {
311 	printf("%s [EAL options] -- [options]\n"
312 	       "-i : run in interactive mode (default value is 1)\n",
313 	       prgname);
314 }
315 
316 static int
317 parse_args(int argc, char **argv)
318 {
319 	char *prgname = argv[0], **argvopt = argv;
320 	int opt, ret;
321 
322 	/* Only support interactive mode to send/recv file first. */
323 	while ((opt = getopt(argc, argvopt, "i")) != EOF) {
324 		switch (opt) {
325 		case 'i':
326 			printf("Interactive-mode selected\n");
327 			interactive = 1;
328 			break;
329 
330 		default:
331 			ntb_usage(prgname);
332 			return -1;
333 		}
334 	}
335 
336 	if (optind >= 0)
337 		argv[optind-1] = prgname;
338 
339 	ret = optind-1;
340 	optind = 1; /* reset getopt lib */
341 	return ret;
342 }
343 
344 int
345 main(int argc, char **argv)
346 {
347 	int ret, i;
348 
349 	signal(SIGINT, signal_handler);
350 	signal(SIGTERM, signal_handler);
351 
352 	ret = rte_eal_init(argc, argv);
353 	if (ret < 0)
354 		rte_exit(EXIT_FAILURE, "Error with EAL initialization.\n");
355 
356 	/* Find 1st ntb rawdev. */
357 	for (i = 0; i < RTE_RAWDEV_MAX_DEVS; i++)
358 		if (rte_rawdevs[i].driver_name &&
359 		    (strncmp(rte_rawdevs[i].driver_name, "raw_ntb",
360 		    NTB_DRV_NAME_LEN) == 0) && (rte_rawdevs[i].attached == 1))
361 			break;
362 
363 	if (i == RTE_RAWDEV_MAX_DEVS)
364 		rte_exit(EXIT_FAILURE, "Cannot find any ntb device.\n");
365 
366 	dev_id = i;
367 
368 	argc -= ret;
369 	argv += ret;
370 
371 	ret = parse_args(argc, argv);
372 	if (ret < 0)
373 		rte_exit(EXIT_FAILURE, "Invalid arguments\n");
374 
375 	rte_rawdev_start(dev_id);
376 
377 	if (interactive) {
378 		sleep(1);
379 		prompt();
380 	}
381 
382 	return 0;
383 }
384