mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-15 04:47:05 +00:00
doc: clean up CLI docs
Update, embellish, clarify. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
parent
d1890d041e
commit
a42f781889
@ -1,67 +1,141 @@
|
|||||||
FRR Command Line Interface
|
Command Line Interface
|
||||||
==========================
|
======================
|
||||||
|
|
||||||
|
FRR features a flexible modal command line interface. Often when adding new
|
||||||
|
features or modifying existing code it is necessary to create or modify CLI
|
||||||
|
commands. FRR has a powerful internal CLI system that does most of the heavy
|
||||||
|
lifting for you.
|
||||||
|
|
||||||
|
All definitions for the CLI system are exposed in ``lib/command.h``. In this
|
||||||
|
header there are a set of macros used to define commands. These macros are
|
||||||
|
collectively referred to as "DEFUNs", because of their syntax:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
DEFUN(command_name,
|
||||||
|
command_name_cmd,
|
||||||
|
"example command FOO...",
|
||||||
|
"Examples\n"
|
||||||
|
"CLI command\n"
|
||||||
|
"Argument\n")
|
||||||
|
{
|
||||||
|
// ...command handler...
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUNs generally take four arguments which are expanded into the appropriate
|
||||||
|
constructs for hooking into the CLI. In order these are:
|
||||||
|
|
||||||
|
- **Function name** - the name of the handler function for the command
|
||||||
|
- **Command name** - the identifier of the ``struct cmd_element`` for the
|
||||||
|
command. By convention this should be the function name with ``_cmd``
|
||||||
|
appended.
|
||||||
|
- **Command definition** - an expression in FRR's CLI grammar that defines the
|
||||||
|
form of the command and its arguments, if any
|
||||||
|
- **Doc string** - a newline-delimited string that documents each element in
|
||||||
|
the command definition
|
||||||
|
|
||||||
|
In the above example, ``command_name`` is the function name,
|
||||||
|
``command_name_cmd`` is the command name, ``"example..."`` is the definition
|
||||||
|
and the last argument is the doc string. The block following the macro is the
|
||||||
|
body of the handler function, details on which are presented later in this
|
||||||
|
section.
|
||||||
|
|
||||||
|
In order to make the command show up to the user it must be installed into the
|
||||||
|
CLI graph. To do this, call:
|
||||||
|
|
||||||
|
``install_element(NODE, &command_name_cmd);``
|
||||||
|
|
||||||
|
This will install the command into the specified CLI node. Usually these calls
|
||||||
|
are grouped together in a CLI initialization function for a set of commands,
|
||||||
|
and the DEFUNs themselves are grouped into the same source file to avoid
|
||||||
|
cluttering the codebase. The names of these files follow the form
|
||||||
|
``*_vty.[ch]`` by convention. Please do not scatter individual CLI commands in
|
||||||
|
the middle of source files; instead expose the necessary functions in a header
|
||||||
|
and place the command definition in a ``*_vty.[ch]`` file.
|
||||||
|
|
||||||
Definition Grammar
|
Definition Grammar
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
This is a reference for the syntax used when defining new CLI commands.
|
FRR uses its own grammar for defining CLI commands. The grammar draws from
|
||||||
An example definition is:
|
syntax commonly seen in \*nix manpages and should be fairly intuitive. The
|
||||||
|
parser is implemented in Bison and the lexer in Flex. These may be found in
|
||||||
|
``lib/command_lex.l`` and ``lib/command_parse.y``, respectively.
|
||||||
|
|
||||||
|
**ProTip**: if you define a new command and find that the parser is
|
||||||
|
throwing syntax or other errors, the parser is the last place you want
|
||||||
|
to look. Bison is very stable and if it detects a syntax error, 99% of
|
||||||
|
the time it will be a syntax error in your definition.
|
||||||
|
|
||||||
|
Tokens
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
Each element in a command definition is assigned a type by the parser based on a set of regular expression rules.
|
||||||
|
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| Token type | Syntax | Description |
|
||||||
|
+=================+=================+=============================================================+
|
||||||
|
| ``WORD`` | ``show ip bgp`` | Matches itself. In the given example every token is a WORD. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| ``MAC`` | ``M:A:C`` | Matches a 48-bit mac address. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| ``MAC_PREFIX`` | ``M:A:C/M`` | Matches a 48-bit mac address with a mask. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| ``VARIABLE`` | ``FOOBAR`` | Matches anything. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. |
|
||||||
|
+-----------------+-----------------+-------------------------------------------------------------+
|
||||||
|
|
||||||
|
When presented with user input, the parser will search over all defined
|
||||||
|
commands in the current context to find a match. It is aware of the various
|
||||||
|
types of user input and has a ranking system to help disambiguate commands. For
|
||||||
|
instance, suppose the following commands are defined in the user's current
|
||||||
|
context:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
DEFUN (command_name,
|
example command FOO
|
||||||
command_name_cmd,
|
example command (22-49)
|
||||||
--> "example <command|line [interface]> DEFINITION...",
|
example command A.B.C.D/X
|
||||||
<..doc strings..>)
|
|
||||||
|
|
||||||
The arrowed part is the definition string.
|
The following table demonstrates the matcher's choice for a selection of
|
||||||
|
possible user input.
|
||||||
|
|
||||||
Explicit syntax rules in Flex and Bison may be found in
|
+-----------------------------+---------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
lib/command\_lex.l and lib/command\_parse.y, respectively. If you can
|
| Input | Matched command | Reason |
|
||||||
read BNF and regex those will be more useful than this document.
|
+=============================+===========================+==============================================================================================================+
|
||||||
|
| example command eLi7eH4xx0r | example command FOO | ``eLi7eH4xx0r`` is not an integer or IPv4 prefix, |
|
||||||
If the parser is throwing syntax or other errors and you can't figure
|
| | | but FOO is a variable and matches all input. |
|
||||||
out why, it's unlikely to be a bug in the parser. If the error message
|
+-----------------------------+---------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
is not useful, please file a bug for a better error message. If all else
|
| example command 42 | example command (22-49) | ``42`` is not an IPv4 prefix. It does match both |
|
||||||
fails, read the token definitions in the lexer source and the Bison BNF
|
| | | ``(22-49)`` and ``FOO``, but RANGE tokens are more specific and have a higher priority than VARIABLE tokens. |
|
||||||
in the parser source.
|
+-----------------------------+---------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
|
| example command 10.3.3.0/24 | example command A.B.C.D/X | The user entered an IPv4 prefix, which is best matched by the last command. |
|
||||||
Characters allowed in each token type:
|
+-----------------------------+---------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
Tokens
|
|
||||||
------
|
|
||||||
|
|
||||||
- ``WORD`` -- A token that begins with +, -, or a lowercase letter. It
|
|
||||||
is an unchanging part of the command and will only match itself.
|
|
||||||
Example: "show ip bgp", every token is a WORD.
|
|
||||||
- ``IPV4`` -- 'A.B.C.D', matches an IPv4 address.
|
|
||||||
- ``IPV6`` -- 'X:X::X:X', matches an IPv6 address.
|
|
||||||
- ``IPV4_PREFIX`` -- 'A.B.C.D/M', matches an IPv4 prefix in CIDR
|
|
||||||
notation.
|
|
||||||
- ``IPV6_PREFIX`` -- 'X:X::X:X/M', matches an IPv6 prefix in CIDR
|
|
||||||
notation.
|
|
||||||
- ``MAC`` -- 'M:A:C', matches a 48-bit mac address
|
|
||||||
- ``MAC_PREFIX`` -- 'M:A:C/M', matches a 48-bit mac address with a mask
|
|
||||||
- ``VARIABLE`` -- Begins with a capital letter. Matches any input.
|
|
||||||
- ``RANGE`` -- Numeric range delimited by parentheses, e.g. (-100 -
|
|
||||||
100) or (10-20). Will only match numbers in the range.
|
|
||||||
|
|
||||||
Rules
|
Rules
|
||||||
-----
|
~~~~~
|
||||||
|
|
||||||
- ``<angle|brackets>`` -- Contain sequences of tokens separated by
|
There are also constructs which allow optional tokens, mutual exclusion, one-or-more selection and repetition.
|
||||||
pipes and provide mutual exclusion. Sequences may contain
|
|
||||||
``<mutual|exclusion>`` but not as the first token. Disallowed:
|
- ``<angle|brackets>`` -- Contain sequences of tokens separated by pipes and
|
||||||
``"example <<a|b> c|d>"`` Allowed: ``"example <a c|b c|d>"``
|
provide mutual exclusion. User input matches at most one option.
|
||||||
- ``[square brackets]`` -- Contains sequences of tokens that are
|
- ``[square brackets]`` -- Contains sequences of tokens that can be omitted.
|
||||||
optional (can be omitted). ``[<a|b>]`` can be shortened to ``[a|b]``.
|
``[<a|b>]`` can be shortened to ``[a|b]``.
|
||||||
- ``{curly|braces}`` -- similar to angle brackets, but instead of
|
- ``{curly|braces}`` -- similar to angle brackets, but instead of mutual
|
||||||
mutual exclusion, curly braces indicate that one or more of the
|
exclusion, curly braces indicate that one or more of the pipe-separated
|
||||||
pipe-separated sequences may be provided in any order.
|
sequences may be provided in any order.
|
||||||
- ``VARIADICS...`` -- Any token which accepts input (so anything except
|
- ``VARIADICS...`` -- Any token which accepts input (anything except WORD)
|
||||||
WORD) and that occurs as the last token of a line may be followed by
|
which occurs as the last token of a line may be followed by an ellipsis,
|
||||||
an ellipsis, which indicates that input matching the token may be
|
which indicates that input matching the token may be repeated an unlimited
|
||||||
repeated an unlimited number of times.
|
number of times.
|
||||||
- ``$name`` -- Specify a variable name for the preceding token. See
|
- ``$name`` -- Specify a variable name for the preceding token. See
|
||||||
"Variable Names" below.
|
"Variable Names" below.
|
||||||
|
|
||||||
@ -69,18 +143,13 @@ Some general notes:
|
|||||||
|
|
||||||
- Options are allowed at the beginning of the command. The developer is
|
- Options are allowed at the beginning of the command. The developer is
|
||||||
entreated to use these extremely sparingly. They are most useful for
|
entreated to use these extremely sparingly. They are most useful for
|
||||||
implementing the 'no' form of configuration commands. Please think
|
implementing the 'no' form of configuration commands. Please think carefully
|
||||||
carefully before using them for anything else. There is usually a
|
before using them for anything else. There is usually a better solution, even
|
||||||
better solution, even if it is just separating out the command
|
if it is just separating out the command definition into separate ones.
|
||||||
definition into separate ones.
|
- The developer should judiciously apply separation of concerns when defining
|
||||||
|
commands. CLI definitions for two unrelated or vaguely related commands or
|
||||||
- The developer should judiciously apply separation of concerns when
|
configuration items should be defined in separate commands. Clarity is
|
||||||
defining
|
preferred over LOC (within reason).
|
||||||
|
|
||||||
CLI. CLI definitions for two unrelated or vaguely related commands or
|
|
||||||
configuration items should be defined in separate commands. Clarity
|
|
||||||
is preferred over LOC (within reason).
|
|
||||||
|
|
||||||
- The maximum number of space-separated tokens that can be entered is
|
- The maximum number of space-separated tokens that can be entered is
|
||||||
presently limited to 256. Please keep this limit in mind when
|
presently limited to 256. Please keep this limit in mind when
|
||||||
implementing new CLI.
|
implementing new CLI.
|
||||||
@ -159,53 +228,53 @@ explicitly given variable name.
|
|||||||
Type rules
|
Type rules
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| Token(s) | Type | Value if omitted by user |
|
| Token(s) | Type | Value if omitted by user |
|
||||||
+==============================+==================================+============================+
|
+=============================+================================+==========================+
|
||||||
| ``A.B.C.D`` | ``struct in_addr`` | 0.0.0.0 |
|
| ``A.B.C.D`` | ``struct in_addr`` | 0.0.0.0 |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| ``X:X::X:X`` | ``struct in6_addr`` | :: |
|
| ``X:X::X:X`` | ``struct in6_addr`` | \:: |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| ``A.B.C.D + X:X::X:X`` | ``const union sockunion *`` | NULL |
|
| ``A.B.C.D + X:X::X:X`` | ``const union sockunion *`` | NULL |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| ``A.B.C.D/M`` | ``const struct prefix_ipv4 *`` | NULL |
|
| ``A.B.C.D/M`` | ``const struct prefix_ipv4 *`` | NULL |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| ``X:X::X:X/M`` | ``const struct prefix_ipv6 *`` | NULL |
|
| ``X:X::X:X/M`` | ``const struct prefix_ipv6 *`` | NULL |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| ``A.B.C.D/M + X:X::X:X/M`` | ``const struct prefix *`` | NULL |
|
| ``A.B.C.D/M + X:X::X:X/M`` | ``const struct prefix *`` | NULL |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| ``(0-9)`` | ``long`` | 0 |
|
| ``(0-9)`` | ``long`` | 0 |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| ``VARIABLE`` | ``const char *`` | NULL |
|
| ``VARIABLE`` | ``const char *`` | NULL |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| ``word`` | ``const char *`` | NULL |
|
| ``word`` | ``const char *`` | NULL |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
| *all other* | ``const char *`` | NULL |
|
| *all other* | ``const char *`` | NULL |
|
||||||
+------------------------------+----------------------------------+----------------------------+
|
+-----------------------------+--------------------------------+--------------------------+
|
||||||
|
|
||||||
Note the following details:
|
Note the following details:
|
||||||
|
|
||||||
- not all parameters are pointers, some are passed as values.
|
- Not all parameters are pointers, some are passed as values.
|
||||||
- when the type is not ``const char *``, there will be an extra
|
- When the type is not ``const char *``, there will be an extra
|
||||||
``_str`` argument with type ``const char *``.
|
``_str`` argument with type ``const char *``.
|
||||||
- you can give a variable name not only to ``VARIABLE`` tokens but also
|
- You can give a variable name not only to ``VARIABLE`` tokens but also
|
||||||
to ``word`` tokens (e.g. constant words). This is useful if some
|
to ``word`` tokens (e.g. constant words). This is useful if some
|
||||||
parts of a command are optional. The type will be ``const char *``.
|
parts of a command are optional. The type will be ``const char *``.
|
||||||
- ``[no]`` will be passed as ``const char *no``.
|
- ``[no]`` will be passed as ``const char *no``.
|
||||||
- pointers will be NULL when the argument is optional and the user did
|
- Pointers will be NULL when the argument is optional and the user did
|
||||||
not use it.
|
not use it.
|
||||||
- if a parameter is not a pointer, but is optional and the user didn't
|
- If a parameter is not a pointer, but is optional and the user didn't
|
||||||
use it, the default value will be passed. Check the ``_str`` argument
|
use it, the default value will be passed. Check the ``_str`` argument
|
||||||
if you need to determine whether the parameter was omitted.
|
if you need to determine whether the parameter was omitted.
|
||||||
- if the definition contains multiple parameters with the same variable
|
- If the definition contains multiple parameters with the same variable
|
||||||
name, they will be collapsed into a single function parameter. The
|
name, they will be collapsed into a single function parameter. The
|
||||||
python code will detect if the types are compatible (i.e. IPv4 + IPv6
|
python code will detect if the types are compatible (i.e. IPv4 + IPv6
|
||||||
variantes) and choose a corresponding C type.
|
variantes) and choose a corresponding C type.
|
||||||
- the standard DEFUN parameters (self, vty, argc, argv) are still
|
- The standard DEFUN parameters (self, vty, argc, argv) are still
|
||||||
present and can be used. A DEFUN can simply be **edited into a DEFPY
|
present and can be used. A DEFUN can simply be **edited into a DEFPY
|
||||||
without further changes and it will still work**; this allows easy
|
without further changes and it will still work**; this allows easy
|
||||||
forward migration.
|
forward migration.
|
||||||
- a file may contain both DEFUN and DEFPY statements.
|
- A file may contain both DEFUN and DEFPY statements.
|
||||||
|
|
||||||
Getting a parameter dump
|
Getting a parameter dump
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -264,12 +333,11 @@ requirement)
|
|||||||
Doc Strings
|
Doc Strings
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Each token in a command definition should be documented with a brief doc
|
Each token in a command definition should be documented with a brief doc string
|
||||||
string that informs a user of the meaning and/or purpose of the
|
that informs a user of the meaning and/or purpose of the subsequent command
|
||||||
subsequent command tree. These strings are provided as the last
|
tree. These strings are provided as the last parameter to DEFUN macros,
|
||||||
parameter to DEFUN macros, concatenated together and separated by an
|
concatenated together and separated by an escaped newline (\n). These are best
|
||||||
escaped newline (':raw-latex:`\n`'). These are best explained by
|
explained by example.
|
||||||
example.
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -411,8 +479,9 @@ The block that follows a CLI definition is executed when a user enters
|
|||||||
input that matches the definition. Its function signature looks like
|
input that matches the definition. Its function signature looks like
|
||||||
this:
|
this:
|
||||||
|
|
||||||
int (*func) (const struct cmd\_element *, struct vty *, int, struct
|
::
|
||||||
cmd\_token *\ []);
|
|
||||||
|
int (*func) (const struct cmd_element *, struct vty *, int, struct cmd_token *[]);
|
||||||
|
|
||||||
The first argument is the command definition struct. The last argument
|
The first argument is the command definition struct. The last argument
|
||||||
is an ordered array of tokens that correspond to the path taken through
|
is an ordered array of tokens that correspond to the path taken through
|
||||||
|
Loading…
Reference in New Issue
Block a user