1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2023 Marvell.
3 */
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <getopt.h>
8 #include <signal.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/select.h>
13 #include <unistd.h>
14
15 #include <rte_cycles.h>
16 #include <rte_eal.h>
17 #include <rte_launch.h>
18
19 #include "module_api.h"
20
21 volatile bool force_quit;
22 struct conn *conn;
23
24 static const char usage[] = "%s EAL_ARGS -- -s SCRIPT [-h HOST] [-p PORT] [--enable-graph-stats] "
25 "[--help]\n";
26
27 static struct app_params {
28 struct conn_params conn;
29 char *script_name;
30 bool enable_graph_stats;
31 } app = {
32 .conn = {
33 .welcome = "\nWelcome!\n\n",
34 .prompt = "graph> ",
35 .addr = "0.0.0.0",
36 .port = 8086,
37 .buf_size = 1024 * 1024,
38 .msg_in_len_max = 1024,
39 .msg_out_len_max = 1024 * 1024,
40 .msg_handle = cli_process,
41 .msg_handle_arg = NULL, /* set later. */
42 },
43 .script_name = NULL,
44 .enable_graph_stats = false,
45 };
46
47 static void
signal_handler(int signum)48 signal_handler(int signum)
49 {
50 if (signum == SIGINT || signum == SIGTERM) {
51 printf("\n\nSignal %d received, preparing to exit...\n", signum);
52 force_quit = true;
53 }
54 }
55
56 static int
app_args_parse(int argc,char ** argv)57 app_args_parse(int argc, char **argv)
58 {
59 struct option lgopts[] = {
60 {"help", 0, 0, 'H'},
61 {"enable-graph-stats", 0, 0, 'g'},
62 };
63 int h_present, p_present, s_present, n_args, i;
64 char *app_name = argv[0];
65 int opt, option_index;
66
67 /* Skip EAL input args */
68 n_args = argc;
69 for (i = 0; i < n_args; i++)
70 if (strcmp(argv[i], "--") == 0) {
71 argc -= i;
72 argv += i;
73 break;
74 }
75
76 if (i == n_args)
77 return 0;
78
79 /* Parse args */
80 h_present = 0;
81 p_present = 0;
82 s_present = 0;
83
84 while ((opt = getopt_long(argc, argv, "h:p:s:", lgopts, &option_index)) != EOF) {
85 switch (opt) {
86 case 'h':
87 if (h_present) {
88 printf("Error: Multiple -h arguments\n");
89 return -1;
90 }
91 h_present = 1;
92
93 if (!strlen(optarg)) {
94 printf("Error: Argument for -h not provided\n");
95 return -1;
96 }
97
98 app.conn.addr = strdup(optarg);
99 if (app.conn.addr == NULL) {
100 printf("Error: Not enough memory\n");
101 return -1;
102 }
103 break;
104
105 case 'p':
106 if (p_present) {
107 printf("Error: Multiple -p arguments\n");
108 return -1;
109 }
110 p_present = 1;
111
112 if (!strlen(optarg)) {
113 printf("Error: Argument for -p not provided\n");
114 return -1;
115 }
116
117 app.conn.port = (uint16_t)strtoul(optarg, NULL, 10);
118 break;
119
120 case 's':
121 if (s_present) {
122 printf("Error: Multiple -s arguments\n");
123 return -1;
124 }
125 s_present = 1;
126
127 if (!strlen(optarg)) {
128 printf("Error: Argument for -s not provided\n");
129 return -1;
130 }
131
132 app.script_name = strdup(optarg);
133 if (app.script_name == NULL) {
134 printf("Error: Not enough memory\n");
135 return -1;
136 }
137 break;
138
139 case 'g':
140 app.enable_graph_stats = true;
141 printf("WARNING! Telnet session can not be accessed with"
142 "--enable-graph-stats");
143 break;
144
145 case 'H':
146 default:
147 printf(usage, app_name);
148 return -1;
149 }
150 }
151 optind = 1; /* reset getopt lib */
152
153 return 0;
154 }
155
156 bool
app_graph_stats_enabled(void)157 app_graph_stats_enabled(void)
158 {
159 return app.enable_graph_stats;
160 }
161
162 bool
app_graph_exit(void)163 app_graph_exit(void)
164 {
165 struct timeval tv;
166 fd_set fds;
167 int ret;
168 char c;
169
170 FD_ZERO(&fds);
171 FD_SET(0, &fds);
172 tv.tv_sec = 0;
173 tv.tv_usec = 100;
174 ret = select(1, &fds, NULL, NULL, &tv);
175 if ((ret < 0 && errno == EINTR) || (ret == 1 && read(0, &c, 1) > 0))
176 return true;
177 else
178 return false;
179
180 }
181
182 int
main(int argc,char ** argv)183 main(int argc, char **argv)
184 {
185 int rc;
186
187 /* Parse application arguments */
188 rc = app_args_parse(argc, argv);
189 if (rc < 0)
190 return rc;
191
192 /* EAL */
193 rc = rte_eal_init(argc, argv);
194 if (rc < 0) {
195 printf("Error: EAL initialization failed (%d)\n", rc);
196 return rc;
197 };
198
199 force_quit = false;
200 signal(SIGINT, signal_handler);
201 signal(SIGTERM, signal_handler);
202
203 cli_init();
204
205 /* Script */
206 if (app.script_name) {
207 cli_script_process(app.script_name, app.conn.msg_in_len_max,
208 app.conn.msg_out_len_max, NULL);
209 }
210
211 /* Connectivity */
212 app.conn.msg_handle_arg = NULL;
213 conn = conn_init(&app.conn);
214 if (!conn) {
215 printf("Error: Connectivity initialization failed\n");
216 goto exit;
217 };
218
219 rte_delay_ms(1);
220 printf("Press enter to exit\n");
221
222 /* Dispatch loop */
223 while (!force_quit) {
224 conn_req_poll(conn);
225
226 conn_msg_poll(conn);
227 if (app_graph_exit())
228 force_quit = true;
229 }
230
231 exit:
232 conn_free(conn);
233 ethdev_stop();
234 cli_exit();
235 rte_eal_cleanup();
236 return 0;
237 }
238