xref: /dpdk/doc/guides/prog_guide/cmdline.rst (revision 449dc649212b24f9dbf65454be709f165fb43823)
1*449dc649SBruce Richardson..  SPDX-License-Identifier: BSD-3-Clause
2*449dc649SBruce Richardson    Copyright(c) 2023 Intel Corporation.
3*449dc649SBruce Richardson
4*449dc649SBruce RichardsonCommand-line Library
5*449dc649SBruce Richardson====================
6*449dc649SBruce Richardson
7*449dc649SBruce RichardsonSince its earliest versions, DPDK has included a command-line library -
8*449dc649SBruce Richardsonprimarily for internal use by, for example, ``dpdk-testpmd`` and the ``dpdk-test`` binaries,
9*449dc649SBruce Richardsonbut the library is also exported on install and can be used by any end application.
10*449dc649SBruce RichardsonThis chapter covers the basics of the command-line library and how to use it in an application.
11*449dc649SBruce Richardson
12*449dc649SBruce RichardsonLibrary Features
13*449dc649SBruce Richardson----------------
14*449dc649SBruce Richardson
15*449dc649SBruce RichardsonThe DPDK command-line library supports the following features:
16*449dc649SBruce Richardson
17*449dc649SBruce Richardson* Tab-completion available for interactive terminal sessions
18*449dc649SBruce Richardson
19*449dc649SBruce Richardson* Ability to read and process commands taken from an input file, e.g. startup script
20*449dc649SBruce Richardson
21*449dc649SBruce Richardson* Parameterized commands able to take multiple parameters with different datatypes:
22*449dc649SBruce Richardson
23*449dc649SBruce Richardson   * Strings
24*449dc649SBruce Richardson   * Signed/unsigned 16/32/64-bit integers
25*449dc649SBruce Richardson   * IP Addresses
26*449dc649SBruce Richardson   * Ethernet Addresses
27*449dc649SBruce Richardson
28*449dc649SBruce Richardson* Ability to multiplex multiple commands to a single callback function
29*449dc649SBruce Richardson
30*449dc649SBruce RichardsonAdding Command-line to an Application
31*449dc649SBruce Richardson-------------------------------------
32*449dc649SBruce Richardson
33*449dc649SBruce RichardsonAdding a command-line instance to an application involves a number of coding steps.
34*449dc649SBruce Richardson
35*449dc649SBruce Richardson#. Define the result structure for the command, specifying the command parameters
36*449dc649SBruce Richardson
37*449dc649SBruce Richardson#. Provide an initializer for each field in the result
38*449dc649SBruce Richardson
39*449dc649SBruce Richardson#. Define the callback function for the command
40*449dc649SBruce Richardson
41*449dc649SBruce Richardson#. Provide a parse result structure instance for the command, linking the callback to the command
42*449dc649SBruce Richardson
43*449dc649SBruce Richardson#. Add the parse result structure to a command-line context
44*449dc649SBruce Richardson
45*449dc649SBruce Richardson#. Within your main application code, create a new command-line instance passing in the context.
46*449dc649SBruce Richardson
47*449dc649SBruce RichardsonThe next few subsections will cover each of these steps in more detail,
48*449dc649SBruce Richardsonworking through an example to add two commands to a command-line instance.
49*449dc649SBruce RichardsonThose two commands will be:
50*449dc649SBruce Richardson
51*449dc649SBruce Richardson#. ``quit`` - as the name suggests, to close the application
52*449dc649SBruce Richardson
53*449dc649SBruce Richardson#. ``show port stats <n>`` - to display on-screen the statistics for a given ethernet port
54*449dc649SBruce Richardson
55*449dc649SBruce Richardson.. note::
56*449dc649SBruce Richardson
57*449dc649SBruce Richardson   For further examples of use of the command-line, see
58*449dc649SBruce Richardson   :doc:`cmdline example application <../sample_app_ug/cmd_line>`
59*449dc649SBruce Richardson
60*449dc649SBruce RichardsonDefining Command Result Structure
61*449dc649SBruce Richardson~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
62*449dc649SBruce Richardson
63*449dc649SBruce RichardsonThe first structure to be defined is the structure which will be created on successful parse of a command.
64*449dc649SBruce RichardsonThis structure contains one member field for each token, or word, in the command.
65*449dc649SBruce RichardsonThe simplest case is for a one-word command, like ``quit``.
66*449dc649SBruce RichardsonFor this, we only need to define a structure with a single string parameter to contain that word.
67*449dc649SBruce Richardson
68*449dc649SBruce Richardson.. code-block:: c
69*449dc649SBruce Richardson
70*449dc649SBruce Richardson   struct cmd_quit_result {
71*449dc649SBruce Richardson      cmdline_fixed_string_t quit;
72*449dc649SBruce Richardson   };
73*449dc649SBruce Richardson
74*449dc649SBruce RichardsonFor readability, the name of the struct member should match that of the token in the command.
75*449dc649SBruce Richardson
76*449dc649SBruce RichardsonFor our second command, we need a structure with four member fields in it,
77*449dc649SBruce Richardsonas there are four words/tokens in our command.
78*449dc649SBruce RichardsonThe first three are strings, and the final one is a 16-bit numeric value.
79*449dc649SBruce RichardsonThe resulting struct looks like:
80*449dc649SBruce Richardson
81*449dc649SBruce Richardson.. code-block:: c
82*449dc649SBruce Richardson
83*449dc649SBruce Richardson   struct cmd_show_port_stats_result {
84*449dc649SBruce Richardson      cmdline_fixed_string_t show;
85*449dc649SBruce Richardson      cmdline_fixed_string_t port;
86*449dc649SBruce Richardson      cmdline_fixed_string_t stats;
87*449dc649SBruce Richardson      uint16_t n;
88*449dc649SBruce Richardson   };
89*449dc649SBruce Richardson
90*449dc649SBruce RichardsonAs before, we choose names to match the tokens in the command.
91*449dc649SBruce RichardsonSince our numeric parameter is a 16-bit value, we use ``uint16_t`` type for it.
92*449dc649SBruce RichardsonAny of the standard sized integer types can be used as parameters, depending on the desired result.
93*449dc649SBruce Richardson
94*449dc649SBruce RichardsonBeyond the standard integer types,
95*449dc649SBruce Richardsonthe library also allows variable parameters to be of a number of other types,
96*449dc649SBruce Richardsonas called out in the feature list above.
97*449dc649SBruce Richardson
98*449dc649SBruce Richardson* For variable string parameters,
99*449dc649SBruce Richardson  the type should be ``cmdline_fixed_string_t`` - the same as for fixed tokens,
100*449dc649SBruce Richardson  but these will be initialized differently (as described below).
101*449dc649SBruce Richardson
102*449dc649SBruce Richardson* For ethernet addresses use type ``struct rte_ether_addr``
103*449dc649SBruce Richardson
104*449dc649SBruce Richardson* For IP addresses use type ``cmdline_ipaddr_t``
105*449dc649SBruce Richardson
106*449dc649SBruce RichardsonProviding Field Initializers
107*449dc649SBruce Richardson~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108*449dc649SBruce Richardson
109*449dc649SBruce RichardsonEach field of our result structure needs an initializer.
110*449dc649SBruce RichardsonFor fixed string tokens, like "quit", "show" and "port", the initializer will be the string itself.
111*449dc649SBruce Richardson
112*449dc649SBruce Richardson.. code-block:: c
113*449dc649SBruce Richardson
114*449dc649SBruce Richardson   static cmdline_parse_token_string_t cmd_quit_quit_tok =
115*449dc649SBruce Richardson      TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
116*449dc649SBruce Richardson
117*449dc649SBruce RichardsonThe convention for naming used here is to include the base name of the overall result structure -
118*449dc649SBruce Richardson``cmd_quit`` in this case,
119*449dc649SBruce Richardsonas well as the name of the field within that structure - ``quit`` in this case, followed by ``_tok``.
120*449dc649SBruce Richardson(This is why there is a double ``quit`` in the name above).
121*449dc649SBruce Richardson
122*449dc649SBruce RichardsonThis naming convention is seen in our second example,
123*449dc649SBruce Richardsonwhich also demonstrates how to define a numeric initializer.
124*449dc649SBruce Richardson
125*449dc649SBruce Richardson
126*449dc649SBruce Richardson.. code-block:: c
127*449dc649SBruce Richardson
128*449dc649SBruce Richardson   static cmdline_parse_token_string_t cmd_show_port_stats_show_tok =
129*449dc649SBruce Richardson      TOKEN_STRING_INITIALIZER(struct cmd_show_port_stats_result, show, "show");
130*449dc649SBruce Richardson   static cmdline_parse_token_string_t cmd_show_port_stats_port_tok =
131*449dc649SBruce Richardson      TOKEN_STRING_INITIALIZER(struct cmd_show_port_stats_result, port, "port");
132*449dc649SBruce Richardson   static cmdline_parse_token_string_t cmd_show_port_stats_stats_tok =
133*449dc649SBruce Richardson      TOKEN_STRING_INITIALIZER(struct cmd_show_port_stats_result, stats, "stats");
134*449dc649SBruce Richardson   static cmdline_parse_token_num_t cmd_show_port_stats_n_tok =
135*449dc649SBruce Richardson      TOKEN_NUM_INITIALIZER(struct cmd_show_port_stats_result, n, RTE_UINT16);
136*449dc649SBruce Richardson
137*449dc649SBruce RichardsonFor variable string tokens, the same ``TOKEN_STRING_INITIALIZER`` macro should be used.
138*449dc649SBruce RichardsonHowever, the final parameter should be ``NULL`` rather than a hard-coded token string.
139*449dc649SBruce Richardson
140*449dc649SBruce RichardsonFor numeric parameters, the final parameter to the ``TOKEN_NUM_INITIALIZER`` macro should be the
141*449dc649SBruce Richardsoncmdline type matching the variable type defined in the result structure,
142*449dc649SBruce Richardsone.g. RTE_UINT8, RTE_UINT32, etc.
143*449dc649SBruce Richardson
144*449dc649SBruce RichardsonFor IP addresses, the macro ``TOKEN_IPADDR_INITIALIZER`` should be used.
145*449dc649SBruce Richardson
146*449dc649SBruce RichardsonFor ethernet addresses, the macro ``TOKEN_ETHERADDR_INITIALIZER`` should be used.
147*449dc649SBruce Richardson
148*449dc649SBruce RichardsonDefining Callback Function
149*449dc649SBruce Richardson~~~~~~~~~~~~~~~~~~~~~~~~~~
150*449dc649SBruce Richardson
151*449dc649SBruce RichardsonFor each command, we need to define a function to be called once the command has been recognised.
152*449dc649SBruce RichardsonThe callback function should have type:
153*449dc649SBruce Richardson
154*449dc649SBruce Richardson.. code:: c
155*449dc649SBruce Richardson
156*449dc649SBruce Richardson   void (*f)(void *, struct cmdline *, void *)
157*449dc649SBruce Richardson
158*449dc649SBruce Richardsonwhere the first parameter is a pointer to the result structure defined above,
159*449dc649SBruce Richardsonthe second parameter is the command-line instance,
160*449dc649SBruce Richardsonand the final parameter is a user-defined pointer provided when we associate the callback with the command.
161*449dc649SBruce RichardsonMost callback functions only use the first parameter, or none at all,
162*449dc649SBruce Richardsonbut the additional two parameters provide some extra flexibility,
163*449dc649SBruce Richardsonto allow the callback to work with non-global state in your application.
164*449dc649SBruce Richardson
165*449dc649SBruce RichardsonFor our two example commands, the relevant callback functions would look very similar in definition.
166*449dc649SBruce RichardsonHowever, within the function body,
167*449dc649SBruce Richardsonwe assume that the user would need to reference the result structure to extract the port number in
168*449dc649SBruce Richardsonthe second case.
169*449dc649SBruce Richardson
170*449dc649SBruce Richardson.. code:: c
171*449dc649SBruce Richardson
172*449dc649SBruce Richardson   void
173*449dc649SBruce Richardson   cmd_quit_parsed(void *parsed_result, struct cmdline *cl, void *data)
174*449dc649SBruce Richardson   {
175*449dc649SBruce Richardson      quit = 1;
176*449dc649SBruce Richardson   }
177*449dc649SBruce Richardson   void
178*449dc649SBruce Richardson   cmd_show_port_stats_parsed(void *parsed_result, struct cmdline *cl, void *data)
179*449dc649SBruce Richardson   {
180*449dc649SBruce Richardson      struct cmd_show_port_stats_result *res = parsed_result;
181*449dc649SBruce Richardson      uint16_t port_id = res->n;
182*449dc649SBruce Richardson      ...
183*449dc649SBruce Richardson   }
184*449dc649SBruce Richardson
185*449dc649SBruce Richardson
186*449dc649SBruce RichardsonAssociating Callback and Command
187*449dc649SBruce Richardson~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
188*449dc649SBruce Richardson
189*449dc649SBruce RichardsonThe ``cmdline_parse_inst_t`` type defines a "parse instance",
190*449dc649SBruce Richardsoni.e. a sequence of tokens to be matched and then an associated function to be called.
191*449dc649SBruce RichardsonAlso included in the instance type are a field for help text for the command,
192*449dc649SBruce Richardsonand any additional user-defined parameter to be passed to the callback functions referenced above.
193*449dc649SBruce RichardsonFor example, for our simple "quit" command:
194*449dc649SBruce Richardson
195*449dc649SBruce Richardson.. code-block:: c
196*449dc649SBruce Richardson
197*449dc649SBruce Richardson   static cmdline_parse_inst_t cmd_quit = {
198*449dc649SBruce Richardson       .f = cmd_quit_parsed,
199*449dc649SBruce Richardson       .data = NULL,
200*449dc649SBruce Richardson       .help_str = "Close the application",
201*449dc649SBruce Richardson       .tokens = {
202*449dc649SBruce Richardson           (void *)&cmd_quit_quit_tok,
203*449dc649SBruce Richardson           NULL
204*449dc649SBruce Richardson       }
205*449dc649SBruce Richardson   };
206*449dc649SBruce Richardson
207*449dc649SBruce RichardsonIn this case, we firstly identify the callback function to be called,
208*449dc649SBruce Richardsonthen set the user-defined parameter to NULL,
209*449dc649SBruce Richardsonprovide a help message to be given, on request, to the user explaining the command,
210*449dc649SBruce Richardsonbefore finally listing out the single token to be matched for this command instance.
211*449dc649SBruce Richardson
212*449dc649SBruce RichardsonFor our second, port stats, example,
213*449dc649SBruce Richardsonas well as making things a little more complicated by having multiple tokens to be matched,
214*449dc649SBruce Richardsonwe can also demonstrate passing in a parameter to the function.
215*449dc649SBruce RichardsonLet us suppose that our application does not always use all the ports available to it,
216*449dc649SBruce Richardsonbut instead only uses a subset of the ports, stored in an array called ``active_ports``.
217*449dc649SBruce RichardsonOur stats command, therefore, should only display stats for the currently in-use ports,
218*449dc649SBruce Richardsonso we pass this ``active_ports`` array.
219*449dc649SBruce Richardson(For simplicity of illustration, we shall assume that the array uses a terminating marker,
220*449dc649SBruce Richardsone.g. -1 for the end of the port list, so we don't need to pass in a length parameter too.)
221*449dc649SBruce Richardson
222*449dc649SBruce Richardson.. code-block:: c
223*449dc649SBruce Richardson
224*449dc649SBruce Richardson   extern int16_t active_ports[];
225*449dc649SBruce Richardson   ...
226*449dc649SBruce Richardson   static cmdline_parse_inst_t cmd_show_port_stats = {
227*449dc649SBruce Richardson       .f = cmd_show_port_stats_parsed,
228*449dc649SBruce Richardson       .data = active_ports,
229*449dc649SBruce Richardson       .help_str = "Show statistics for active network ports",
230*449dc649SBruce Richardson       .tokens = {
231*449dc649SBruce Richardson           (void *)&cmd_show_port_stats_show_tok,
232*449dc649SBruce Richardson           (void *)&cmd_show_port_stats_port_tok,
233*449dc649SBruce Richardson           (void *)&cmd_show_port_stats_stats_tok,
234*449dc649SBruce Richardson           (void *)&cmd_show_port_stats_n_tok,
235*449dc649SBruce Richardson           NULL
236*449dc649SBruce Richardson       }
237*449dc649SBruce Richardson   };
238*449dc649SBruce Richardson
239*449dc649SBruce Richardson
240*449dc649SBruce RichardsonAdding Command to Command-line Context
241*449dc649SBruce Richardson~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
242*449dc649SBruce Richardson
243*449dc649SBruce RichardsonNow that we have configured each individual command and callback,
244*449dc649SBruce Richardsonwe need to merge these into a single array of command-line "contexts".
245*449dc649SBruce RichardsonThis context array will be used to create the actual command-line instance in the application.
246*449dc649SBruce RichardsonThankfully, each context entry is the same as each parse instance,
247*449dc649SBruce Richardsonso our array is defined by simply listing out the previously defined command parse instances.
248*449dc649SBruce Richardson
249*449dc649SBruce Richardson.. code-block:: c
250*449dc649SBruce Richardson
251*449dc649SBruce Richardson   static cmdline_parse_ctx_t ctx[] = {
252*449dc649SBruce Richardson       &cmd_quit,
253*449dc649SBruce Richardson       &cmd_show_port_stats,
254*449dc649SBruce Richardson       NULL
255*449dc649SBruce Richardson   };
256*449dc649SBruce Richardson
257*449dc649SBruce RichardsonThe context list must be terminated by a NULL entry.
258*449dc649SBruce Richardson
259*449dc649SBruce RichardsonCreating a Command-line Instance
260*449dc649SBruce Richardson~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
261*449dc649SBruce Richardson
262*449dc649SBruce RichardsonOnce we have our ``ctx`` variable defined,
263*449dc649SBruce Richardsonwe now just need to call the API to create the new command-line instance in our application.
264*449dc649SBruce RichardsonThe basic API is ``cmdline_new`` which will create an interactive command-line with all commands available.
265*449dc649SBruce RichardsonHowever, if additional features for interactive use - such as tab-completion -
266*449dc649SBruce Richardsonare desired, it is recommended that ``cmdline_new_stdin`` be used instead.
267*449dc649SBruce Richardson
268*449dc649SBruce RichardsonA pattern that can be used in applications is to use ``cmdline_new`` for processing any startup commands,
269*449dc649SBruce Richardsoneither from file or from the environment (as is done in the "dpdk-test" application),
270*449dc649SBruce Richardsonand then using ``cmdline_stdin_new`` thereafter to handle the interactive part.
271*449dc649SBruce RichardsonFor example, to handle a startup file and then provide an interactive prompt:
272*449dc649SBruce Richardson
273*449dc649SBruce Richardson.. code-block:: c
274*449dc649SBruce Richardson
275*449dc649SBruce Richardson   struct cmdline *cl;
276*449dc649SBruce Richardson   int fd = open(startup_file, O_RDONLY);
277*449dc649SBruce Richardson
278*449dc649SBruce Richardson   if (fd >= 0) {
279*449dc649SBruce Richardson       cl = cmdline_new(ctx, "", fd, STDOUT_FILENO);
280*449dc649SBruce Richardson       if (cl == NULL) {
281*449dc649SBruce Richardson           /* error handling */
282*449dc649SBruce Richardson       }
283*449dc649SBruce Richardson       cmdline_interact(cl);
284*449dc649SBruce Richardson       cmdline_quit(cl);
285*449dc649SBruce Richardson       close(fd);
286*449dc649SBruce Richardson   }
287*449dc649SBruce Richardson
288*449dc649SBruce Richardson   cl = cmdline_stdin_new(ctx, "Proxy>> ");
289*449dc649SBruce Richardson   if (cl == NULL) {
290*449dc649SBruce Richardson       /* error handling */
291*449dc649SBruce Richardson   }
292*449dc649SBruce Richardson   cmdline_interact(cl);
293*449dc649SBruce Richardson   cmdline_stdin_exit(cl);
294*449dc649SBruce Richardson
295*449dc649SBruce Richardson
296*449dc649SBruce RichardsonMultiplexing Multiple Commands to a Single Function
297*449dc649SBruce Richardson~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
298*449dc649SBruce Richardson
299*449dc649SBruce RichardsonTo reduce the amount of boiler-plate code needed when creating a command-line for an application,
300*449dc649SBruce Richardsonit is possible to merge a number of commands together to have them call a separate function.
301*449dc649SBruce RichardsonThis can be done in a number of different ways:
302*449dc649SBruce Richardson
303*449dc649SBruce Richardson* A callback function can be used as the target for a number of different commands.
304*449dc649SBruce Richardson  Which command was used for entry to the function can be determined by examining the first parameter,
305*449dc649SBruce Richardson  ``parsed_result`` in our examples above.
306*449dc649SBruce Richardson
307*449dc649SBruce Richardson* For simple string commands, multiple options can be concatenated using the "#" character.
308*449dc649SBruce Richardson  For example: ``exit#quit``, specified as a token initializer,
309*449dc649SBruce Richardson  will match either on the string "exit" or the string "quit".
310*449dc649SBruce Richardson
311*449dc649SBruce RichardsonAs a concrete example,
312*449dc649SBruce Richardsonthese two techniques are used in the DPDK unit test application ``dpdk-test``,
313*449dc649SBruce Richardsonwhere a single command ``cmdline_parse_t`` instance is used for all the "dump_<item>" test cases.
314*449dc649SBruce Richardson
315*449dc649SBruce Richardson.. literalinclude:: ../../../app/test/commands.c
316*449dc649SBruce Richardson    :language: c
317*449dc649SBruce Richardson    :start-after: Add the dump_* tests cases 8<
318*449dc649SBruce Richardson    :end-before: >8 End of add the dump_* tests cases
319*449dc649SBruce Richardson
320*449dc649SBruce Richardson
321*449dc649SBruce RichardsonExamples of Command-line Use in DPDK
322*449dc649SBruce Richardson------------------------------------
323*449dc649SBruce Richardson
324*449dc649SBruce RichardsonTo help the user follow the steps provided above,
325*449dc649SBruce Richardsonthe following DPDK files can be consulted for examples of command-line use.
326*449dc649SBruce Richardson
327*449dc649SBruce Richardson.. note::
328*449dc649SBruce Richardson
329*449dc649SBruce Richardson   This is not an exhaustive list of examples of command-line use in DPDK.
330*449dc649SBruce Richardson   It is simply a list of a few files that may be of use to the application developer.
331*449dc649SBruce Richardson   Some of these referenced files contain more complex examples of use that others.
332*449dc649SBruce Richardson
333*449dc649SBruce Richardson* ``commands.c/.h`` in ``examples/cmdline``
334*449dc649SBruce Richardson
335*449dc649SBruce Richardson* ``mp_commands.c/.h`` in ``examples/multi_process/simple_mp``
336*449dc649SBruce Richardson
337*449dc649SBruce Richardson* ``commands.c`` in ``app/test``
338