Skip to content

Commit

Permalink
cmdgen, test: add arg-name support and doc strings, added nethop tests (
Browse files Browse the repository at this point in the history
#17)

* cmdgen, test: add arg-name support and doc strings, added nethop tests
  • Loading branch information
Ali-aqrabawi authored Feb 23, 2024
1 parent f61caaf commit 1ebcac2
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 77 deletions.
2 changes: 1 addition & 1 deletion iproute2
Submodule iproute2 updated from 6b79bc to d9b886
178 changes: 107 additions & 71 deletions src/lib/change_cmdgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,6 @@

#define CMD_LINE_SIZE 1024

typedef enum {
// list extensions
CMD_START_EXT,
CMD_ADD_EXT,
CMD_DELETE_EXT,
CMD_UPDATE_EXT,

// leaf extensions
ARG_NAME_EXT,
FLAG_EXT,
VALUE_ONLY_EXT,
VALUE_ONLY_ON_UPDATE_EXT


} extension_t;

char *yang_ext_map[] = {
[CMD_START_EXT] = "cmd-start",
[CMD_ADD_EXT] = "cmd-add",
Expand Down Expand Up @@ -75,8 +59,29 @@ void free_argv(char **argv, int argc)
free(argv);
}

/*
void free_cmds_info(struct cmd_info **cmds_info)
{
// Free the memory allocated for cmds
for (int i = 0; i < CMDS_ARRAY_SIZE; i++) {
if (cmds_info[i] != NULL) {
// Free the argv array for cmd_args[i]
for (int j = 0; j < cmds_info[i]->argc; j++) {
free(cmds_info[i]->argv[j]);
}
// Free the argv array itself
free(cmds_info[i]->argv);
// Free the cmd_args struct itself
free(cmds_info[i]);
}
}
// Free the cmds array itself
free(cmds_info);
}

/**
* if input is "iproute2-ip-link:dummy" it return "dummy"
* @param [in] input string to be stripped.
* @return the extracted string
*/
char *strip_yang_iden_prefix(const char *input)
{
Expand Down Expand Up @@ -110,7 +115,11 @@ char *strip_yang_iden_prefix(const char *input)
}
}


/**
* get the yang operation from the lyd_node (create, replace, delete)
* @param [in]dnode lyd_node
* @return oper_t the time of the operation found on this lyd_node.
*/
oper_t get_operation(const struct lyd_node *dnode)
{
struct lyd_meta *next;
Expand All @@ -130,8 +139,11 @@ oper_t get_operation(const struct lyd_node *dnode)
return UNKNOWN_OPR;
}

/*
* return true if the node has ipr2cgen:cmd-start extension.
/**
* check if this node is cmd-start node.
* example in yang the list nexthop is where the cmd-start ext added.
* @param [in] dnode lyd_node
* @return 1 if ext found.
*/
int is_startcmd_node(struct lyd_node *dnode)
{
Expand All @@ -147,10 +159,12 @@ int is_startcmd_node(struct lyd_node *dnode)
return 0;
}

/*
* this function search if the provided ex_t exist in the node,
* if not exist it return EXIT_FAILURE, if exist return EXIT_SUCCESS,
* if value is not NULL, the extension value will be dup to value.
/**
* get the extension from lyd_node,
* @param [in] ex_t extension_t to be captured from lyd_node.
* @param [in] dnode lyd_node where to search for provided ext.
* @param [out] value extension value if found. can be null.
* @return EXIT_SUCCESS if ext found, EXIT_FAILURE if not found
*/
int get_extension(extension_t ex_t, const struct lyd_node *dnode, char **value)
{
Expand All @@ -170,8 +184,11 @@ int get_extension(extension_t ex_t, const struct lyd_node *dnode, char **value)
return EXIT_FAILURE;
}

/*
* this function will convert the command line string to argc, argv
/**
* parse the command line and convert it to argc, argv
* @param [in] command command line string "ip link add ..."
* @param [out] argc parsed argv count
* @param [out] argv parsed argv
*/
void parse_command(const char *command, int *argc, char ***argv)
{
Expand Down Expand Up @@ -207,8 +224,15 @@ void parse_command(const char *command, int *argc, char ***argv)
free(cmd_copy);
}

void add_command(char *cmd_line, struct cmd_info **cmds, int *cmd_idx,
char **oper2cmd_prefix, const struct lyd_node *start_dnode)
/**
* this function take cmd_line string, convert it to argc, argv and then append it to the cmds array
* @param [in] cmd_line command line string "ip link add name lo0 type dummy"
* @param [in] start_dnode start_cmd node to be added to the cmd_info struct.
* @param [in,out] cmds array of cmd_info.
* @param [in,out] cmd_idx current index of cmds.
*/
void add_command(char *cmd_line,const struct lyd_node *start_dnode,
struct cmd_info **cmds, int *cmd_idx)
{
int argc;
char **argv;
Expand Down Expand Up @@ -237,20 +261,21 @@ struct cmd_info **lyd2cmds(const struct lyd_node *change_node)
char *result;
int cmd_idx = 0;
char cmd_line[CMD_LINE_SIZE] = {0};
struct cmd_info **cmds = malloc(CMDS_ARRAY_SIZE * sizeof(struct cmd_info *));
// Set all elements of the array to NULL
for (int i = 0; i < CMDS_ARRAY_SIZE; i++) {
cmds[i] = NULL;
}

lyd_print_mem(&result, change_node, LYD_XML, 0);
printf("--%s", result);

struct cmd_info **cmds = malloc(CMDS_ARRAY_SIZE * sizeof(struct cmd_info *));
if (cmds == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return NULL;
}

// Set all elements of the array to NULL
for (int i = 0; i < CMDS_ARRAY_SIZE; i++) {
cmds[i] = NULL;
}

// this will hold the add, update and delete cmd prefixes.
char *oper2cmd_prefix[3] = {NULL};

Expand All @@ -274,68 +299,79 @@ struct cmd_info **lyd2cmds(const struct lyd_node *change_node)
return NULL;
}


oper_t op_val;
struct lyd_node *next, *startcmd_node;
LYD_TREE_DFS_BEGIN(change_node, next)
{
LY_DATA_TYPE type;
// if this is startcmd node (schema has ipr2cgen:cmd-start), then start building a new command
if (is_startcmd_node(next)) {
startcmd_node = next;
// check if the cmd is not empty (first cmd)
if (cmd_line[0] != 0)
add_command(cmd_line, cmds, &cmd_idx, oper2cmd_prefix, startcmd_node);
add_command(cmd_line, startcmd_node, cmds, &cmd_idx);


// prepare for new command
op_val = get_operation(next);
if (op_val == UNKNOWN_OPR) {
fprintf(stderr, "%s: unknown operation for startcmd node (%s) \n",
fprintf(stderr, "%s: unknown operation for startcmd node \"%s\" \n",
__func__, next->schema->name);
free_cmds_info(cmds);
return NULL;
}
strlcpy(cmd_line, oper2cmd_prefix[op_val], sizeof(cmd_line));
} else if (next->schema->nodetype != LYS_CONTAINER) {
// not a startcmd, get key-value pair and apped to cmd_line

if (next->schema->nodetype == LYS_LEAF) {
char *key=NULL, *value = NULL;
// if list operation is delete, get the keys only
if (op_val == DELETE_OPR && !lysc_is_key(next->schema))
goto next_iter;
// if FLAG extension, add schema name to the cmd and go to next iter.
if (get_extension(FLAG_EXT, next, NULL) == EXIT_SUCCESS) {
if (!strcmp("true", lyd_get_value(next)))
value = strdup(next->schema->name);
goto next_iter;
}
// if value only, don't include the schema->name (key) in the command.
if (get_extension(VALUE_ONLY_EXT, next, NULL) == EXIT_SUCCESS)
goto next_iter;
else
} else if (next->schema->nodetype == LYS_LEAF) {
char *key = NULL, *value = NULL;

// if list operation is delete, get the keys only
if (op_val == DELETE_OPR && !lysc_is_key(next->schema))
goto next_iter;

// if FLAG extension, add schema name to the cmd and go to next iter.
if (get_extension(FLAG_EXT, next, NULL) == EXIT_SUCCESS) {
if (!strcmp("true", lyd_get_value(next)))
key = strdup(next->schema->name);
// set the value
// special case for identity leaf, where the module prefix might be added (e.g iproute-link:vti)
LY_DATA_TYPE type = ((struct lysc_node_leaf *) next->schema)->type->basetype;
if (type == LY_TYPE_IDENT)
value = strip_yang_iden_prefix(lyd_get_value(next));
else
value = (char *) lyd_get_value(next);
next_iter:
if (key != NULL) {
strlcat(cmd_line, " ", sizeof(cmd_line));
strlcat(cmd_line, key, sizeof(cmd_line));
}
if (value != NULL){
strlcat(cmd_line, " ", sizeof(cmd_line));
strlcat(cmd_line, value, sizeof(cmd_line));
}
goto next_iter;
}

// if value only extension, don't include the schema->name (key) in the command.
if (get_extension(VALUE_ONLY_EXT, next, NULL) == EXIT_SUCCESS)
goto next_iter;

// if arg_name extension, key will be set to the arg-name value.
if (get_extension(ARG_NAME_EXT, next, &key) == EXIT_SUCCESS) {
if (key == NULL) {
fprintf(stderr, "%s: ipr2cgen:arg-name extension found but failed to "
"get the arg-name value for node \"%s\"\n",
__func__, next->schema->name);
free_cmds_info(cmds);
return NULL;
}
} else
key = strdup(next->schema->name);

// set the value
// special case for identity leaf, where the module prefix might be added (e.g iproute-link:vti)
type = ((struct lysc_node_leaf *) next->schema)->type->basetype;
if (type == LY_TYPE_IDENT)
value = strip_yang_iden_prefix(lyd_get_value(next));
else
value = (char *) lyd_get_value(next);
next_iter:
if (key != NULL) {
strlcat(cmd_line, " ", sizeof(cmd_line));
strlcat(cmd_line, key, sizeof(cmd_line));
}
if (value != NULL) {
strlcat(cmd_line, " ", sizeof(cmd_line));
strlcat(cmd_line, value, sizeof(cmd_line));
}
}
LYD_TREE_DFS_END(change_node, next);
}
if (cmd_line[0] != 0)
add_command(cmd_line, cmds, &cmd_idx, oper2cmd_prefix, startcmd_node);
add_command(cmd_line,startcmd_node,cmds,&cmd_idx);

return cmds;
}
42 changes: 37 additions & 5 deletions src/lib/cmdgen.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

#define CMDS_ARRAY_SIZE 1024

/**
* extension to extension name map.
*/
extern char *yang_ext_map[];

/**
* @brief data struct to store cmd operation.
*
Expand All @@ -17,6 +22,26 @@ typedef enum {
UNKNOWN_OPR,
} oper_t;

/**
* definition of yang's extension_t.
*/
typedef enum {
// list extensions
CMD_START_EXT,
// root container extensions
CMD_ADD_EXT,
CMD_DELETE_EXT,
CMD_UPDATE_EXT,

// leaf extensions
ARG_NAME_EXT,
FLAG_EXT,
VALUE_ONLY_EXT,
VALUE_ONLY_ON_UPDATE_EXT


} extension_t;

/**
* @brief data struct to store command information.
*/
Expand Down Expand Up @@ -46,12 +71,19 @@ struct cmd_info** lyd2cmds(const struct lyd_node *change_node);
struct cmd_info* lyd2rollback_cmd(const struct lyd_node *change_node);

/**
* @brief get the change operation from change lyd_node.
*
*
* @param[in] lyd_node change node.
* @return oper_t
* get the yang operation from the lyd_node (create, replace, delete)
* @param [in]dnode lyd_node
* @return oper_t the time of the operation found on this lyd_node.
*/
oper_t get_operation(const struct lyd_node *dnode);

/**
* get the extension from lyd_node,
* @param [in] ex_t extension_t to be captured from lyd_node.
* @param [in] dnode lyd_node where to search for provided ext.
* @param [out] value extension value if found. can be null.
* @return EXIT_SUCCESS if ext found, EXIT_FAILURE if not found
*/
int get_extension(extension_t ex_t, const struct lyd_node *dnode, char **value);

#endif// IPROUTE2_SYSREPO_CMDGEN_H
File renamed without changes.
Loading

0 comments on commit 1ebcac2

Please sign in to comment.