API Reference Manual  1.46.0
odp_cli.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2021-2024 Nokia
3  */
4 
15 #include <odp_api.h>
16 #include <odp/helper/odph_api.h>
17 
18 #include <stdio.h>
19 #include <stdint.h>
20 #include <signal.h>
21 
22 typedef struct {
23  int time;
24  char *addr;
25  uint16_t port;
26 } options_t;
27 
28 static void usage(const char *prog)
29 {
30  printf("\n"
31  "Usage: %s [options]\n"
32  "\n"
33  "OPTIONS:\n"
34  " -t, --time <sec> Keep CLI open for <sec> seconds. (default -1 (infinite))\n"
35  " -a, --address <addr> Bind listening socket to IP address <addr>.\n"
36  " -p, --port <port> Bind listening socket to port <port>.\n"
37  "\n"
38  "ODP helper defaults are used for address and port, if the options are\n"
39  "not given.\n"
40  "\n",
41  prog);
42 }
43 
44 static void parse_args(int argc, char *argv[], options_t *opt)
45 {
46  static const struct option longopts[] = {
47  { "time", required_argument, NULL, 't' },
48  { "address", required_argument, NULL, 'a' },
49  { "port", required_argument, NULL, 'p' },
50  { "help", no_argument, NULL, 'h' },
51  { NULL, 0, NULL, 0 }
52  };
53 
54  static const char *shortopts = "+t:a:p:h";
55 
56  while (1) {
57  int c = getopt_long(argc, argv, shortopts, longopts, NULL);
58 
59  if (c == -1)
60  break; /* No more options */
61 
62  switch (c) {
63  case 't':
64  opt->time = atoi(optarg);
65  break;
66  case 'a':
67  opt->addr = optarg;
68  break;
69  case 'p':
70  opt->port = atoi(optarg);
71  break;
72  default:
73  usage(argv[0]);
74  exit(EXIT_SUCCESS);
75  break;
76  }
77  }
78 
79  optind = 1; /* reset 'extern optind' from the getopt lib */
80 }
81 
82 static volatile int shutdown_sig;
83 
84 static void sig_handler(int signo)
85 {
86  (void)signo;
87 
88  shutdown_sig = 1;
89 }
90 
91 static void my_cmd(int argc, char *argv[])
92 {
93  odph_cli_log("%s(%d): %s\n", __FILE__, __LINE__, __func__);
94 
95  for (int i = 0; i < argc; i++)
96  odph_cli_log("argv[%d]: %s\n", i, argv[i]);
97 }
98 
99 static int cli_server(void *arg ODP_UNUSED)
100 {
101  /* Run CLI server. */
102  if (odph_cli_run()) {
103  ODPH_ERR("odph_cli_run() failed.\n");
104  return -1;
105  }
106 
107  return 0;
108 }
109 
110 int main(int argc, char *argv[])
111 {
112  signal(SIGINT, sig_handler);
113 
114  odph_helper_options_t helper_options;
115 
116  /* Let helper collect its own arguments (e.g. --odph_proc) */
117  argc = odph_parse_options(argc, argv);
118  if (odph_options(&helper_options)) {
119  ODPH_ERR("Error: reading ODP helper options failed.\n");
120  exit(EXIT_FAILURE);
121  }
122 
123  odp_init_t init;
124 
125  odp_init_param_init(&init);
126  init.mem_model = helper_options.mem_model;
127 
128  options_t opt = {
129  .time = -1,
130  .addr = NULL,
131  .port = 0,
132  };
133 
134  parse_args(argc, argv, &opt);
135 
136  /* Initialize ODP. */
137 
138  odp_instance_t inst;
139 
140  if (odp_init_global(&inst, &init, NULL)) {
141  ODPH_ERR("Global init failed.\n");
142  exit(EXIT_FAILURE);
143  }
144 
145  if (odp_init_local(inst, ODP_THREAD_CONTROL)) {
146  ODPH_ERR("Local init failed.\n");
147  exit(EXIT_FAILURE);
148  }
149 
150  /* Prepare CLI parameters. */
151 
152  odph_cli_param_t cli_param;
153 
154  odph_cli_param_init(&cli_param);
155 
156  if (opt.addr)
157  cli_param.address = opt.addr;
158 
159  if (opt.port)
160  cli_param.port = opt.port;
161 
162  /* Initialize CLI helper. */
163  if (odph_cli_init(&cli_param)) {
164  ODPH_ERR("CLI helper initialization failed.\n");
165  exit(EXIT_FAILURE);
166  }
167 
168  /* Register user command. */
169  if (odph_cli_register_command("my_command", my_cmd,
170  "Example user command.")) {
171  ODPH_ERR("Registering user command failed.\n");
172  exit(EXIT_FAILURE);
173  }
174 
175  /* Create server thread. */
176 
177  odp_cpumask_t cpumask;
178  odph_thread_common_param_t thr_common;
179  odph_thread_param_t thr_param;
180  odph_thread_t thr_server;
181  odph_thread_join_result_t res;
182 
183  if (odp_cpumask_default_control(&cpumask, 1) != 1) {
184  ODPH_ERR("Failed to get default CPU mask.\n");
185  exit(EXIT_FAILURE);
186  }
187 
188  odph_thread_common_param_init(&thr_common);
189  thr_common.instance = inst;
190  thr_common.cpumask = &cpumask;
191 
192  odph_thread_param_init(&thr_param);
193  thr_param.thr_type = ODP_THREAD_CONTROL;
194  thr_param.start = cli_server;
195 
196  memset(&thr_server, 0, sizeof(thr_server));
197 
198  if (odph_thread_create(&thr_server, &thr_common, &thr_param, 1) != 1) {
199  ODPH_ERR("Failed to create server thread.\n");
200  exit(EXIT_FAILURE);
201  }
202 
203  printf("CLI server started on %s:%d.\n", cli_param.address,
204  cli_param.port);
205 
206  /* Wait for the given number of seconds. */
207  for (int i = 0; (opt.time < 0 || i < opt.time) && !shutdown_sig; i++)
209 
210  printf("Stopping CLI server.\n");
211 
212  /* Stop CLI server. */
213  if (odph_cli_stop()) {
214  ODPH_ERR("CLI stop failed.\n");
215  exit(EXIT_FAILURE);
216  }
217 
218  /* Wait for server thread to exit. */
219  if (odph_thread_join_result(&thr_server, &res, 1) != 1) {
220  ODPH_ERR("Failed to join server thread.\n");
221  exit(EXIT_FAILURE);
222  }
223 
224  if (res.is_sig || res.ret != 0) {
225  ODPH_ERR("Worker thread failure%s: %d.\n", res.is_sig ? " (signaled)" : "",
226  res.ret);
227  exit(EXIT_FAILURE);
228  }
229 
230  /* Terminate CLI helper. */
231  if (odph_cli_term()) {
232  ODPH_ERR("CLI helper termination failed.\n");
233  exit(EXIT_FAILURE);
234  }
235 
236  /* Terminate ODP. */
237 
238  if (odp_term_local()) {
239  ODPH_ERR("Local term failed.\n");
240  exit(EXIT_FAILURE);
241  }
242 
243  if (odp_term_global(inst)) {
244  ODPH_ERR("Global term failed.\n");
245  exit(EXIT_FAILURE);
246  }
247 
248  return 0;
249 }
#define ODP_UNUSED
Intentionally unused variables of functions.
Definition: spec/hints.h:54
int odp_cpumask_default_control(odp_cpumask_t *mask, int num)
Default CPU mask for control threads.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
@ ODP_THREAD_CONTROL
Control thread.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
void odp_time_wait_ns(uint64_t ns)
Wait the specified number of nanoseconds.
The OpenDataPlane API.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.