From c6a3a68548be5ce0d9bae958b8e76627f6aaca5b Mon Sep 17 00:00:00 2001 From: "G. Paul Ziemba" Date: Fri, 3 Sep 2021 07:46:29 -0700 Subject: [PATCH 1/2] doc/developer: how to add a CLI node Signed-off-by: G. Paul Ziemba --- doc/developer/cli.rst | 128 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index edabe61d92..b8f3180480 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -767,6 +767,134 @@ User input: ``ip`` partially matches ``ipv6`` but exactly matches ``ip``, so ``ip`` will win. +Adding a CLI Node +----------------- + +To add a new CLI node, you should: + +- define a new numerical node constant +- define a node structure in the relevant daemon +- call ``install_node()`` in the relevant daemon +- define and install the new node in vtysh +- define corresponding node entry commands in daemon and vtysh + +Defining the numerical node constant +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Add your new node value to the enum before ``NODE_TYPE_MAX`` in +``lib/command.h``: + +.. code-block:: c + + enum node_type { + AUTH_NODE, // Authentication mode of vty interface. + VIEW_NODE, // View node. Default mode of vty interface. + [...] + MY_NEW_NODE, + NODE_TYPE_MAX, // maximum + }; + +Defining a node structure +^^^^^^^^^^^^^^^^^^^^^^^^^ +In your daemon-specific code where you define your new commands that +attach to the new node, add a node definition: + +.. code-block:: c + + static struct cmd_node my_new_node = { + .name = "my new node name", + .node = MY_NEW_NODE, // enum node_type lib/command.h + .parent_node = CONFIG_NODE, + .prompt = "%s(my-new-node-prompt)# ", + .config_write = my_new_node_config_write, + }; + +You will need to define ``my_new_node_config_write(struct vty \*vty)`` +(or omit this field if you have no relevant configuration to save). + +Calling ``install_node()`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ +In the daemon's initialization function, before installing your new commands +with ``install_element()``, add a call ``install_node(&my_new_node)``. + +Defining and installing the new node in vtysh +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The build tools automatically collect command definitions for vtysh. +However, new nodes must be coded in vtysh specifically. + +In ``vtysh/vtysh.c``, define a stripped-down node structure and +call ``install_node()``: + +.. code-block:: c + + static struct cmd_node my_new_node = { + .name = "my new node name", + .node = MY_NEW_NODE, /* enum node_type lib/command.h */ + .parent_node = CONFIG_NODE, + .prompt = "%s(my-new-node-prompt)# ", + }; + [...] + void vtysh_init_vty(void) + { + [...] + install_node(&my_new_node) + [...] + } + +Defining corresponding node entry commands in daemon and vtysh +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The command that descends into the new node is typically programmed +with ``VTY_PUSH_CONTEXT`` or equivalent in the daemon's CLI handler function. +In vtysh, you must implement a corresponding node change so that vtysh +tracks the daemon's movement through the node tree. + +Although the build tools typically scan daemon code for CLI definitions +to replicate their parsing in vtysh, the node-descent function in the +daemon must be blocked from this replication so that a hand-coded +skeleton can be written in ``vtysh.c``. + +Accordingly, use one of the ``*_NOSH`` macros such as ``DEFUN_NOSH`` or +``DEFPY_NOSH`` for the daemon's node-descent CLI definition, and use +``DEFUNSH`` in ``vtysh.c`` for the vtysh equivalent. + +.. seealso:: :ref:`vtysh-special-defuns` + +Examples: + +``zebra_whatever.c`` + +.. code-block:: c + + DEFPY_NOSH(my_new_node, + my_new_node_cmd, + "my-new-node foo", + "New Thing\n" + "A foo\n") + { + [...] + VTY_PUSH_CONTEXT(MY_NEW_NODE, bar); + [...] + } + + +``vtysh.c`` + +.. code-block:: c + + DEFUNSH(VTYSH_ZEBRA, my_new_node, + my_new_node_cmd, + "my-new-node foo", + "New Thing\n" + "A foo\n") + { + vty->node = MY_NEW_NODE; + return CMD_SUCCESS; + } + [...] + install_element(CONFIG_NODE, &my_new_node_cmd); + + + + Inspection & Debugging ---------------------- From d3bb30f5883b20b0191f204eafd3a64e5467ad49 Mon Sep 17 00:00:00 2001 From: "G. Paul Ziemba" Date: Fri, 3 Sep 2021 12:23:45 -0700 Subject: [PATCH 2/2] doc/developer: adding a CLI node: mention frr-reload.py and VTY_PUSH_XPATH Signed-off-by: G. Paul Ziemba --- doc/developer/cli.rst | 44 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index b8f3180480..4ef08b1ba6 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -777,6 +777,7 @@ To add a new CLI node, you should: - call ``install_node()`` in the relevant daemon - define and install the new node in vtysh - define corresponding node entry commands in daemon and vtysh +- add a new entry to the ``ctx_keywords`` dictionary in ``tools/frr-reload.py`` Defining the numerical node constant ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -844,6 +845,9 @@ Defining corresponding node entry commands in daemon and vtysh ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The command that descends into the new node is typically programmed with ``VTY_PUSH_CONTEXT`` or equivalent in the daemon's CLI handler function. +(If the CLI has been updated to use the new northbound architecture, +``VTY_PUSH_XPATH`` is used instead.) + In vtysh, you must implement a corresponding node change so that vtysh tracks the daemon's movement through the node tree. @@ -852,9 +856,9 @@ to replicate their parsing in vtysh, the node-descent function in the daemon must be blocked from this replication so that a hand-coded skeleton can be written in ``vtysh.c``. -Accordingly, use one of the ``*_NOSH`` macros such as ``DEFUN_NOSH`` or -``DEFPY_NOSH`` for the daemon's node-descent CLI definition, and use -``DEFUNSH`` in ``vtysh.c`` for the vtysh equivalent. +Accordingly, use one of the ``*_NOSH`` macros such as ``DEFUN_NOSH``, +``DEFPY_NOSH``, or ``DEFUN_YANG_NOSH`` for the daemon's node-descent +CLI definition, and use ``DEFUNSH`` in ``vtysh.c`` for the vtysh equivalent. .. seealso:: :ref:`vtysh-special-defuns` @@ -876,6 +880,22 @@ Examples: } +``ripd_whatever.c`` + +.. code-block:: c + + DEFPY_YANG_NOSH(my_new_node, + my_new_node_cmd, + "my-new-node foo", + "New Thing\n" + "A foo\n") + { + [...] + VTY_PUSH_XPATH(MY_NEW_NODE, xbar); + [...] + } + + ``vtysh.c`` .. code-block:: c @@ -893,6 +913,24 @@ Examples: install_element(CONFIG_NODE, &my_new_node_cmd); +Adding a new entry to the ``ctx_keywords`` dictionary +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In file ``tools/frr-reload.py``, the ``ctx_keywords`` dictionary +describes the various node relationships. +Add a new node entry at the appropriate level in this dictionary. + +.. code-block:: python + + ctx_keywords = { + [...] + "key chain ": { + "key ": {} + }, + [...] + "my-new-node": {}, + [...] + } + Inspection & Debugging