This is an old revision of the document!
Adding a menu entry for the CLI
This document shows how to add a menu entry for the CLI. Usually the first thing anyone would want to do for their protocol implementation is to enable that protocol for some of the available interfaces. Thus, in describing the steps to follow, we'll consider adding an Enable option for the RSTP protocol.
Step 1 : setting up protocol information
Most protocols have a small number of configurable parameters that influence the protocol's behaviour. Naturally, we'll want to store these parameters' values somewhere. LiSA stores all such information in a shared memory structure that is protected from concurrent accesses. So the first step is to define our own structure that contains protocol-specific data. Since all we want to do is enable the protocol, our structure will only have a field called enabled. We'll create a header file called rstp_client.h in the userspace/include/ folder where we'll keep CLI-interaction related information. We have to include this header in include/shared.h so our structure will be recognized. In this header file we add the following:
struct rstp_configuration { unsigned char enabled; };
Next, add an entry of this type in the shared memory structure found in lib/shared.c
struct shared { //... /* CDP configuration */ struct cdp_configuration cdp; /* RSTP configuration */ struct rstp_configuration rstp; //... };
Finally, we want to be able to access the information we just added so we define setter/getter routines in lib/shared.c
void shared_set_rstp(struct rstp_configuration *rstp) { assert(rstp); mm_lock(mm); memcpy(&SHM->rstp, rstp, sizeof(struct rstp_configuration)); mm_unlock(mm); } void shared_get_rstp(struct rstp_configuration *rstp) { assert(rstp); mm_lock(mm); memcpy(rstp, &SHM->rstp, sizeof(struct rstp_configuration)); mm_unlock(mm); }
Step 2 : adding menu entries
Now that we have the protocol infrastructure in place, we can add the menu entry. We want the menu entry to be available only for the selected interface. Only after we've given the commands conf t and int EthX should the entry become available. So we have to edit the cli/menu/config_if.c file, because that's where interface-related commands are. To add the enable option to the menu, we add this to the mentioned file:
//... struct menu_node config_if_main = { /* Root node, .name is used as prompt */ .name = "config-if", .subtree = (struct menu_node *[]) { /* #rstp */ & (struct menu_node){ .name = "rstp", .help = "RSTP interface subcommands", .mask = CLI_MASK(PRIV(2), IFF_SWITCHED), .tokenize = NULL, .run = NULL, .subtree = (struct menu_node *[]) { /* #rstp enable */ & (struct menu_node){ .name = "enable", .help = "Enable RSTP on interface", .mask = CLI_MASK(PRIV(2)), .tokenize = NULL, .run = cmd_rstp_if_set, .subtree = NULL }, NULL } }, //...
The result of this is that the first entry from the config-if submenu is rstp enable. To position the entry elsewhere (that is, to make it be the 2nd,3rd entry etc.) simply move the piece of code after the similar entries found in struct config_if_main. Of course we also have to add the disable option. To keep things similar to Cisco commands, we add the following piece of code under the no submenu:
//...
/* #no */
& (struct menu_node){
.name = "no",
.help = "Negate a command or set its defaults",
.mask = CLI_MASK(PRIV(2)),
.tokenize = NULL,
.run = NULL,
.subtree = (struct menu_node *[]) { /*{{{*/
/* #no rstp */
& (struct menu_node){
.name = "rstp",
.help = "RSTP interface subcommands",
.mask = CLI_MASK(PRIV(2)),
.tokenize = NULL,
.run = NULL,
.subtree = (struct menu_node *[]) { /*{{{*/
/* #no rstp enable */
& (struct menu_node){
.name = "enable",
.help = "Enable RSTP on interface",
.mask = CLI_MASK(PRIV(2)),
.tokenize = NULL,
.run = cmd_rstp_if_set,
.subtree = NULL
},
NULL
} /*}}}*/
},
//...
