summaryrefslogtreecommitdiffstats
path: root/lib/table.h
diff options
context:
space:
mode:
authorAvneesh Sachdev <avneesh@opensourcerouting.org>2012-08-17 17:19:50 +0200
committerDavid Lamparter <equinox@opensourcerouting.org>2012-09-26 21:50:48 +0200
commit28971c8cb1138700e87dc7da673e59b5596bb51b (patch)
tree0e55c3f830681449cd96bb36eb04a6a1293d8b44 /lib/table.h
parentbgpd: make bgp_table a wrapper around table library (diff)
downloadfrr-28971c8cb1138700e87dc7da673e59b5596bb51b.tar.xz
frr-28971c8cb1138700e87dc7da673e59b5596bb51b.zip
lib/table: add route_table_get_next() and iterator
* lib/table.[ch] - Add a function (route_table_get_next()) to get the route_node in a tree that succeeds a given prefix in iteration order. This allows one to reliably walk nodes in a tree while allowing modifications, and is useful for achieving scale and performance. Other approaches are also possible -- the main plus point of this one is that it does not require any state about the walk to be maintained in the table data structures. - Add an iterator for walking the nodes in a tree. This introduces a new structure (route_table_iter_t) and the following main functions. route_table_iter_init() route_table_iter_pause() route_table_iter_next() route_table_iter_cleanup() The iterator normally uses node pointers and the existing route_next() function to walk nodes efficiently. When an iteration is 'paused' with route_table_iter_pause(), it stores the last prefix processed. The next call to route_table_iter_next() transparently invokes route_table_get_next() with the prefix to resume iteration. * bgpd/bgp_table.[ch] Add wrappers for the new table features described above. * tests/table_test.c Add tests for the new table code. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'lib/table.h')
-rw-r--r--lib/table.h126
1 files changed, 126 insertions, 0 deletions
diff --git a/lib/table.h b/lib/table.h
index 4d3eddb1d..ab357a074 100644
--- a/lib/table.h
+++ b/lib/table.h
@@ -98,6 +98,43 @@ struct route_node
#define l_right link[1]
};
+typedef struct route_table_iter_t_ route_table_iter_t;
+
+typedef enum
+{
+ RT_ITER_STATE_INIT,
+ RT_ITER_STATE_ITERATING,
+ RT_ITER_STATE_PAUSED,
+ RT_ITER_STATE_DONE
+} route_table_iter_state_t;
+
+/*
+ * route_table_iter_t
+ *
+ * Structure that holds state for iterating over a route table.
+ */
+struct route_table_iter_t_
+{
+
+ route_table_iter_state_t state;
+
+ /*
+ * Routing table that we are iterating over. The caller must ensure
+ * that that table outlives the iterator.
+ */
+ struct route_table *table;
+
+ /*
+ * The node that the iterator is currently on.
+ */
+ struct route_node *current;
+
+ /*
+ * The last prefix that the iterator processed before it was paused.
+ */
+ struct prefix pause_prefix;
+};
+
/* Prototypes. */
extern struct route_table *route_table_init (void);
@@ -125,4 +162,93 @@ extern struct route_node *route_node_match_ipv6 (const struct route_table *,
#endif /* HAVE_IPV6 */
extern unsigned long route_table_count (const struct route_table *);
+
+extern struct route_node *
+route_table_get_next (const struct route_table *table, struct prefix *p);
+extern int
+route_table_prefix_iter_cmp (struct prefix *p1, struct prefix *p2);
+
+/*
+ * Iterator functions.
+ */
+extern void route_table_iter_init (route_table_iter_t *iter,
+ struct route_table *table);
+extern void route_table_iter_pause (route_table_iter_t *iter);
+extern void route_table_iter_cleanup (route_table_iter_t *iter);
+
+/*
+ * Inline functions.
+ */
+
+/*
+ * route_table_iter_next
+ *
+ * Get the next node in the tree.
+ */
+static inline struct route_node *
+route_table_iter_next (route_table_iter_t * iter)
+{
+ struct route_node *node;
+
+ switch (iter->state)
+ {
+
+ case RT_ITER_STATE_INIT:
+
+ /*
+ * We're just starting the iteration.
+ */
+ node = route_top (iter->table);
+ break;
+
+ case RT_ITER_STATE_ITERATING:
+ node = route_next (iter->current);
+ break;
+
+ case RT_ITER_STATE_PAUSED:
+
+ /*
+ * Start with the node following pause_prefix.
+ */
+ node = route_table_get_next (iter->table, &iter->pause_prefix);
+ break;
+
+ case RT_ITER_STATE_DONE:
+ return NULL;
+
+ default:
+ assert (0);
+ }
+
+ iter->current = node;
+ if (node)
+ iter->state = RT_ITER_STATE_ITERATING;
+ else
+ iter->state = RT_ITER_STATE_DONE;
+
+ return node;
+}
+
+/*
+ * route_table_iter_is_done
+ *
+ * Returns TRUE if the iteration is complete.
+ */
+static inline int
+route_table_iter_is_done (route_table_iter_t *iter)
+{
+ return iter->state == RT_ITER_STATE_DONE;
+}
+
+/*
+ * route_table_iter_started
+ *
+ * Returns TRUE if this iterator has started iterating over the tree.
+ */
+static inline int
+route_table_iter_started (route_table_iter_t *iter)
+{
+ return iter->state != RT_ITER_STATE_INIT;
+}
+
#endif /* _ZEBRA_TABLE_H */