Creating a Commands Menu Array

To represent the commands expected by your daemon, you must define menu arrays to specify the command hierarchy, the arguments a command can take, and the code that is executed to retrieve the data required by the command.

You also create DDL definitions to make system database objects for the commands, and ODL definitions to create XML tags for the commands' output; for information on these tasks, see Creating a User Interface with DDL and ODL.

Defining the Array

Your daemon should have a file named daemon-name/_ui.c that contains several arrays defined according to the typedef parse_menu_t, which is defined in the ms_parse.h file in libjuniper. The system uses these arrays to build a tree of tokens used to respond to commands sent from the management daemon (mgd) to your daemon.

The parse_menu_t structure is declared as follows in the header file ms_parse.h, in libjuniper:

typedef struct parse_menu_s {
   const char *                command;  /* Command the user enters*/     
   const char *                help;     /* Help string for errors */      
   int                         subcode;  /* Unparsed data to be processed in
                                            the callback function */      
   const struct parse_menu_s * next;     /* Sub-command - reads next menu down */      
   parse_func_t                function; /* Callback function */       
 } parse_menu_t;

The DDL for the show version command this example parses is as follows:

command juniper-command {

      command show {
        command jnx-ifinfo {
            require view;
            help "Show ifinfo service information";
            hidden unreleased;

            command version {
                help "Show ifinfo service version";
		argument level {
                flag nokeyword explicit;
		type enum int {
			choice brief{
			help "Display brief";
			value OPT_BRIEF;
			choice detail{
			help "Display detail";
			value OPT_DETAIL;
                    default brief;

For example, if the user types show version brief in the CLI, the CLI first sends the command to mgd. The following then occurs:

  1. mgd validates the command, determines which system daemon should handle the command, and sends that daemon the string show version brief.

  2. In that daemon, the ms_parse_line() function takes the parse_menu_t arrays and decodes the stream for every token in the stream. That is:

    1. The first token is show, so the first-level array in the daemon code should have a string entry show.

    2. If the first-level array specifies a function in the function field, it is called. In this case, the field is null.

    3. If the first-level array specifies a sub-array in the next field, that array is read for the next token. In this case, the next array should specify version, with the subcode brief. The token brief is passed directly to the callback function for processing.

Setting Up the Menu

The previous example is coded as follows.

Each menu array is terminated with a final row containing only NULL entries. This is required to signify the end of the menu.
At the the first level, this daemon expects show ... or clear ...:

 parse_menu_t ifinfo_menu_main[] = {
    { "show",   NULL,     0,    ifinfo_menu_show,    NULL },
    { "clear",  NULL,     0,    ifinfo_menu_clear,   NULL },
    { NULL,     NULL,     0,    NULL,              NULL }

The next level specifies the tokens that are available to the show ? command. In this case, the options are show interfaces and show version:

 parse_menu_t ifinfo_menu_show[] = {
    { "interfaces",  NULL,  0,  ifinfo_menu_show_interfaces,    NULL },
    { "version",     NULL,  0,  ifinfo_menu_show_version,      NULL },
    { NULL,          NULL,  0,  NULL,                          NULL }

The third level specifies leaf nodes that do something. show version brief and show version detail will call the C function show_ifinfo_version(). DISP_BRIEF or DISP_DETAIL are set as the subcode field in the parse_status_t argument passed into the function.

 parse_menu_t ifinfo_menu_show_version[] = {
     { "brief",   NULL,     DISP_BRIEF,    NULL,        show_ifinfo_version },
     { "detail",  NULL,     DISP_DETAIL,   NULL,        show_ifinfo_version },
     { NULL,      NULL,          0,        NULL,        NULL }

 show_ifinfo_version (mgmt_sock_t msp, parse_status_t pstatus, char *rest)
      int detail_level;

      detail_level = ms_parse_get_subcode();

      if ((detail_level==DISP_BRIEF))
         { do something }

The subcode field stores application specific information. This information can be a modifier, such as BRIEF/DETAIL, or it can be a command argument.

The subcode is defined, and its data is processed, by the application itself; it is not part of the command DDL. The menu parser searches for the instance of parse_menu_t that matches a given menu token; whatever doesn't match is sent back to the callback function as an unparsed character. The callback function is then free to handle the data. In other words, the subcode serves as an indirect argument to the callback function.

In this example, DISP_BRIEF or DISP_DETAIL is passed directly to show_ifinfo_version(), which receives the string in the rest parameter, and stores it in the detail_level variable.

2007-2009 Juniper Networks, Inc. All rights reserved. The information contained herein is confidential information of Juniper Networks, Inc., and may not be used, disclosed, distributed, modified, or copied without the prior written consent of Juniper Networks, Inc. in an express license. This information is subject to change by Juniper Networks, Inc. Juniper Networks, the Juniper Networks logo, and JUNOS are registered trademarks of Juniper Networks, Inc. in the United States and other countries. All other trademarks, service marks, registered trademarks, or registered service marks are the property of their respective owners.
Generated on Sun May 30 20:26:47 2010 for Juniper Networks Partner Solution Development Platform JUNOS SDK 10.2R1 by Doxygen 1.4.5