From: Quentin Young Date: Thu, 1 Sep 2016 21:27:33 +0000 (+0000) Subject: lib: Generalize graph to work for any data type X-Git-Tag: frr-3.0-branchpoint~129^2~246 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=16d7c05093f0f3a24d09f9780afc1ea114e73f94;p=matthieu%2Ffrr.git lib: Generalize graph to work for any data type Signed-off-by: Quentin Young --- diff --git a/lib/Makefile.am b/lib/Makefile.am index 2df5ed61f4..d12f9ed6d9 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -11,7 +11,7 @@ libzebra_la_LDFLAGS = -version-info 0:0:0 libzebra_la_SOURCES = \ network.c pid_output.c getopt.c getopt1.c daemon.c \ checksum.c vector.c linklist.c vty.c \ - command_graph.c command_parse.y command_lex.l command_match.c grammar_sandbox.c \ + graph.c command_parse.y command_lex.l command_match.c grammar_sandbox.c \ command.c \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ @@ -28,7 +28,7 @@ libzebra_la_LIBADD = @LIB_REGEX@ @LIBCAP@ pkginclude_HEADERS = \ buffer.h checksum.h filter.h getopt.h hash.h \ if.h linklist.h log.h \ - command_graph.h command_match.h grammar_sandbox.h \ + graph.h command_match.h grammar_sandbox.h \ command.h \ memory.h network.h prefix.h routemap.h distribute.h sockunion.h \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ diff --git a/lib/command_graph.c b/lib/command_graph.c deleted file mode 100644 index 323bd3e953..0000000000 --- a/lib/command_graph.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Graph data structure and companion routines for CLI backend. - * - * -- - * Copyright (C) 2016 Cumulus Networks, Inc. - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ -#include -#include "command_graph.h" -#include "memory.h" - -struct graph_node * -graphnode_add_child (struct graph_node *parent, struct graph_node *child) -{ - vector_set (parent->children, child); - child->refs++; - return child; -} - -struct graph_node * -graphnode_new (enum graph_node_type type) -{ - struct graph_node *node = - XCALLOC(MTYPE_CMD_TOKENS, sizeof(struct graph_node)); - - node->type = type; - node->children = vector_init(VECTOR_MIN_SIZE); - - return node; -} - -void -graphnode_delete (struct graph_node *node) -{ - if (!node) return; - if (node->children) vector_free (node->children); - if (node->element) free_cmd_element (node->element); - free (node->text); - free (node->arg); - free (node); -} - -void -graphnode_delete_graph (struct graph_node *start) -{ - if (start && start->children && vector_active (start->children) > 0) - { - for (unsigned int i = 0; i < vector_active (start->children); i++) - { - graphnode_delete (vector_slot(start->children, i)); - vector_unset (start->children, i); - } - } - - if (--(start->refs) == 0) - graphnode_delete (start); -} diff --git a/lib/command_graph.h b/lib/command_graph.h deleted file mode 100644 index a2f84e3a0f..0000000000 --- a/lib/command_graph.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Graph data structure and companion routines for CLI backend. - * - * -- - * Copyright (C) 2016 Cumulus Networks, Inc. - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef _ZEBRA_COMMAND_GRAPH_H -#define _ZEBRA_COMMAND_GRAPH_H - -#include "command.h" - -/** - * Types for graph nodes. - * - * The node type determines what kind of data the node can match (in the - * matching use case) or hold (in the argv use case). - */ -enum graph_node_type -{ - IPV4_GN, // IPV4 addresses - IPV4_PREFIX_GN, // IPV4 network prefixes - IPV6_GN, // IPV6 prefixes - IPV6_PREFIX_GN, // IPV6 network prefixes - WORD_GN, // words - RANGE_GN, // integer ranges - NUMBER_GN, // numbers - VARIABLE_GN, // almost anything - /* plumbing types */ - SELECTOR_GN, // marks beginning of selector subgraph - OPTION_GN, // marks beginning of option subgraph - NUL_GN, // transparent node with various uses - START_GN, // first node in the graph (has no parents) - END_GN // leaf node in the graph, has pointer to cmd_element -}; - -/** - * Command graph node. - * Used for matching and passing arguments to vtysh commands. - */ -struct graph_node -{ - enum graph_node_type type; // data type this node matches or holds - vector children; // this node's children - - char *text; // original format text - char *doc; // docstring for this node - long long value; // for NUMBER_GN - long long min, max; // for RANGE_GN - - /* cmd_element struct pointer, only valid for END_GN */ - struct cmd_element *element; - - /* used for passing arguments to command functions */ - char *arg; - - /* refcount for node parents */ - unsigned int refs; -}; - -/** - * Adds a node as a child of another node. - * - * @param[in] parent node - * @param[in] child node - * @return child node - */ -struct graph_node * -graphnode_add_child (struct graph_node *parent, struct graph_node *child); - -/** - * Creates a new node, initializes all fields to default values and sets the - * node type. - * - * @param[in] type node type - * @return pointer to the created node - */ -struct graph_node * -graphnode_new (enum graph_node_type type); - -/** - * Deletes a graph node without deleting its children. - * - * @param[out] node pointer to node to delete - */ -void -graphnode_delete (struct graph_node *node); - -/** - * Deletes a graph node and recursively deletes all its direct and indirect - * children. - * - * @param[out] node start node of graph to free - */ -void -graphnode_delete_graph (struct graph_node *node); - -#endif /* _ZEBRA_COMMAND_GRAPH_H */ diff --git a/lib/graph.c b/lib/graph.c new file mode 100644 index 0000000000..a46f71449d --- /dev/null +++ b/lib/graph.c @@ -0,0 +1,113 @@ +/* + * Graph data structure. + * + * -- + * Copyright (C) 2016 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include +#include "command_graph.h" +#include "memory.h" + + +struct graph_node * +graph_new_node (struct graph *graph, void *data, void (*del) (void*)) +{ + struct graph_node *node = + XCALLOC(MTYPE_CMD_TOKENS, sizeof(struct graph_node)); + + node->from = vector_init(VECTOR_MIN_SIZE); + node->to = vector_init(VECTOR_MIN_SIZE); + node->data = data; + node->del = del; + + vector_set (graph->nodes, node); + + return node; +} + +void +graph_delete_node (struct graph *graph, struct graph_node *node) +{ + if (!node) return; + + // an adjacent node + struct graph_node *adj; + + // for all nodes that have an edge to us, remove us from their ->to + for (int i = 0; i < vector_active (node->from); i++) + { + adj = vector_slot (node->from, i); + for (int j = 0; j < vector_active (adj->to); j++) + if (vector_slot (adj->to, j) == node) + vector_unset (adj->to, j); + + // if the node is orphaned, delete it + if (vector_active (adj->to) == 0 && vector_active (adj->from) == 0) + graph_delete_node (adj); + } + + // for all nodes that we have an edge to, remove us from their ->from + for (int i = 0; i < vector_active (node->to); i++) + { + adj = vector_slot (node->to, i); + for (int j = 0; j < vector_active (adj->from); j++) + if (vector_slot (adj->from, j) == node) + vector_unset (adj->from, j); + + // if the node is orphaned, delete it + if (vector_active (adj->to) == 0 && vector_active (adj->from) == 0) + graph_delete_node (adj); + } + + // if there is a deletion callback, call it! + if (node->del && node->data) + (*node->del) (node->data); + + // free adjacency lists + vector_free (node->to); + vector_free (node->from); + + // remove node from graph->nodes + for (int i = 0; i < vector_active (graph->nodes); i++) + if (vector_slot (graph->nodes, i) == node) + vector_unset (graph->nodes, i); + + // free the node itself + free (node); +} + +struct graph_node * +graph_add_edge (struct graph_node *from, struct graph_node *to) +{ + vector_set (from->to, to); + vector_set (to->from, from); + return to; +} + +void +graph_delete_graph (struct graph *graph) +{ + // delete each node in the graph + for (int i = 0; i < vector_active (graph->nodes); i++) + graph_delete_node (vector_slot (graph->nodes, i)); + + vector_free (graph->nodes); + free (graph); +} diff --git a/lib/graph.h b/lib/graph.h new file mode 100644 index 0000000000..7c0f848001 --- /dev/null +++ b/lib/graph.h @@ -0,0 +1,99 @@ +/* + * Graph data structure. + * + * -- + * Copyright (C) 2016 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_COMMAND_GRAPH_H +#define _ZEBRA_COMMAND_GRAPH_H + +#include "vector.h" + +/** + * Graph structure. + */ +struct graph +{ + vector nodes; // all nodes in the graph +} + +/** + * Graph node / vertex. + */ +struct graph_node +{ + vector from; // nodes which have edges to this node + vector to; // nodes which this node has edges to + + void *data; // node data + void (*del) (void *data) // deletion callback +}; + +/** + * Creates a new node. + * + * @struct graph the graph this node exists in + * @param[in] data this node's data + * @param[in] del data deletion callback + * @return the new node + */ +struct graph_node * +graph_new_node (struct graph *graph, void *data, void (*del) (void*)); + +/** + * Deletes a node. + * + * Before deletion, this function removes all edges to and from this node from + * any neighbor nodes. + * + * If, as a result of this operation, any neighbor node has no edges either to + * or from itself, that node will be deleted as well. If the graph topology is + * e.g. a star this will result in the deletion of all nodes. + * + * If *data and *del are non-null, the following call is made: + * (*node->del) (node->data); + * + * @param[out] node pointer to node to delete + */ +void +graph_delete_node (struct graph *graph, struct graph_node *node); + +/** + * Makes a directed edge between two nodes. + * + * @param[in] from + * @param[in] to + * @return to + */ +struct graph_node * +graph_add_edge (struct graph_node *from, struct graph_node *to); + +/** + * Deletes a graph. + * + * Calls graph_delete_node on each node before freeing the graph struct itself. + * + * @param graph the graph to delete + */ +void +graph_delete_graph (struct graph *graph); + +#endif /* _ZEBRA_COMMAND_GRAPH_H */