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 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 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 157 app_graph_stats_enabled(void) 158 { 159 return app.enable_graph_stats; 160 } 161 162 bool 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 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