summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_clist.c14
-rw-r--r--bgpd/bgp_filter.c29
-rw-r--r--bgpd/bgp_filter.h4
-rw-r--r--bgpd/bgp_main.c4
-rw-r--r--bgpd/bgp_routemap.c639
-rw-r--r--bgpd/bgp_vty.c53
-rw-r--r--bgpd/bgp_zebra.c19
-rw-r--r--bgpd/bgp_zebra.h1
-rw-r--r--bgpd/bgpd.c76
-rw-r--r--bgpd/bgpd.h8
-rw-r--r--lib/filter.c5
-rw-r--r--lib/memtypes.c1
-rw-r--r--lib/plist.c14
-rw-r--r--lib/routemap.c547
-rw-r--r--lib/routemap.h33
-rw-r--r--zebra/Makefile.am2
-rw-r--r--zebra/zebra_rib.c24
-rw-r--r--zebra/zebra_routemap.c321
-rw-r--r--zebra/zebra_vty.c108
-rw-r--r--zebra/zserv.h8
20 files changed, 1513 insertions, 397 deletions
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index b91ab81fa..80564df4b 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -644,7 +644,10 @@ community_list_set (struct community_list_handler *ch,
if (community_list_dup_check (list, entry))
community_entry_free (entry);
else
- community_list_entry_add (list, entry);
+ {
+ community_list_entry_add (list, entry);
+ route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
+ }
return 0;
}
@@ -670,6 +673,7 @@ community_list_unset (struct community_list_handler *ch,
if (!str)
{
community_list_delete (list);
+ route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
return 0;
}
@@ -695,6 +699,7 @@ community_list_unset (struct community_list_handler *ch,
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
community_list_entry_delete (list, entry, style);
+ route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
return 0;
}
@@ -763,7 +768,10 @@ extcommunity_list_set (struct community_list_handler *ch,
if (community_list_dup_check (list, entry))
community_entry_free (entry);
else
- community_list_entry_add (list, entry);
+ {
+ community_list_entry_add (list, entry);
+ route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
+ }
return 0;
}
@@ -789,6 +797,7 @@ extcommunity_list_unset (struct community_list_handler *ch,
if (!str)
{
community_list_delete (list);
+ route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
}
@@ -814,6 +823,7 @@ extcommunity_list_unset (struct community_list_handler *ch,
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
community_list_entry_delete (list, entry, style);
+ route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
}
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index fd8ece659..fa0889cdb 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -47,10 +47,10 @@ struct as_list_master
struct as_list_list str;
/* Hook function which is executed when new access_list is added. */
- void (*add_hook) (void);
+ void (*add_hook) (char *);
/* Hook function which is executed when access_list is deleted. */
- void (*delete_hook) (void);
+ void (*delete_hook) (char *);
};
/* Element of AS path filter. */
@@ -150,6 +150,11 @@ as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
else
aslist->head = asfilter;
aslist->tail = asfilter;
+
+ /* Run hook function. */
+ if (as_list_master.add_hook)
+ (*as_list_master.add_hook) (aslist->name);
+
}
/* Lookup as_list from list of as_list by name. */
@@ -283,13 +288,7 @@ as_list_get (const char *name)
aslist = as_list_lookup (name);
if (aslist == NULL)
- {
- aslist = as_list_insert (name);
-
- /* Run hook function. */
- if (as_list_master.add_hook)
- (*as_list_master.add_hook) ();
- }
+ aslist = as_list_insert (name);
return aslist;
}
@@ -350,6 +349,8 @@ as_list_empty (struct as_list *aslist)
static void
as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
{
+ char *name = strdup (aslist->name);
+
if (asfilter->next)
asfilter->next->prev = asfilter->prev;
else
@@ -368,7 +369,9 @@ as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
/* Run hook function. */
if (as_list_master.delete_hook)
- (*as_list_master.delete_hook) ();
+ (*as_list_master.delete_hook) (name);
+ if (name)
+ free(name);
}
static int
@@ -401,14 +404,14 @@ as_list_apply (struct as_list *aslist, void *object)
/* Add hook function. */
void
-as_list_add_hook (void (*func) (void))
+as_list_add_hook (void (*func) (char *))
{
as_list_master.add_hook = func;
}
/* Delete hook function. */
void
-as_list_delete_hook (void (*func) (void))
+as_list_delete_hook (void (*func) (char *))
{
as_list_master.delete_hook = func;
}
@@ -572,7 +575,7 @@ DEFUN (no_ip_as_path_all,
/* Run hook function. */
if (as_list_master.delete_hook)
- (*as_list_master.delete_hook) ();
+ (*as_list_master.delete_hook) (argv[0]);
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h
index c1da90412..80feb1ccb 100644
--- a/bgpd/bgp_filter.h
+++ b/bgpd/bgp_filter.h
@@ -33,7 +33,7 @@ extern void bgp_filter_reset (void);
extern enum as_filter_type as_list_apply (struct as_list *, void *);
extern struct as_list *as_list_lookup (const char *);
-extern void as_list_add_hook (void (*func) (void));
-extern void as_list_delete_hook (void (*func) (void));
+extern void as_list_add_hook (void (*func) (char *));
+extern void as_list_delete_hook (void (*func) (char *));
#endif /* _QUAGGA_BGP_FILTER_H */
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 584bfa761..ae73afc0a 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -263,8 +263,8 @@ bgp_exit (int status)
/* reverse bgp_route_init */
bgp_route_finish ();
- /* reverse bgp_route_map_init/route_map_init */
- route_map_finish ();
+ /* cleanup route maps */
+ bgp_route_map_terminate();
/* reverse bgp_scan_init */
bgp_scan_finish ();
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index ab543f910..3204daba5 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -39,11 +39,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#endif /* HAVE_LIBPCREPOSIX */
#include "buffer.h"
#include "sockunion.h"
+#include "hash.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_regex.h"
@@ -55,6 +57,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_debug.h"
+
/* Memo of route-map commands.
o Cisco route-map
@@ -661,9 +664,9 @@ route_match_aspath (void *rule, struct prefix *prefix,
as_list = as_list_lookup ((char *) rule);
if (as_list == NULL)
return RMAP_NOMATCH;
-
+
bgp_info = object;
-
+
/* Perform match. */
return ((as_list_apply (as_list, bgp_info->attr->aspath) == AS_FILTER_DENY) ? RMAP_NOMATCH : RMAP_MATCH);
}
@@ -2163,7 +2166,6 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix,
static void *
route_set_ipv6_nexthop_peer_compile (const char *arg)
{
- int ret;
int *rins = NULL;
rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int));
@@ -2306,7 +2308,8 @@ struct route_map_rule_cmd route_set_originator_id_cmd =
/* Add bgp route map rule. */
static int
bgp_route_match_add (struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
@@ -2323,29 +2326,64 @@ bgp_route_match_add (struct vty *vty, struct route_map_index *index,
return CMD_WARNING;
}
}
+
+ if (type != RMAP_EVENT_MATCH_ADDED)
+ {
+ route_map_upd8_dependency (type, arg, index->map->name);
+ }
+
return CMD_SUCCESS;
}
/* Delete bgp route map rule. */
static int
bgp_route_match_delete (struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
+ char *dep_name = (char *)arg;
+ const char *tmpstr;
+ char *rmap_name = NULL;
- ret = route_map_delete_match (index, command, arg);
+ if (type != RMAP_EVENT_MATCH_DELETED)
+ {
+ /* ignore the mundane, the types without any dependency */
+ if (arg == NULL)
+ {
+ if ((tmpstr = route_map_get_match_arg(index, command)) != NULL)
+ dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
+ }
+ rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
+ }
+
+ ret = route_map_delete_match (index, command, dep_name);
if (ret)
{
switch (ret)
{
case RMAP_RULE_MISSING:
vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
- return CMD_WARNING;
+ break;
case RMAP_COMPILE_ERROR:
vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
- return CMD_WARNING;
+ break;
}
+ if (arg == NULL && dep_name)
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ if (rmap_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+ return CMD_WARNING;
}
+
+ if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
+ route_map_upd8_dependency(type, dep_name, rmap_name);
+
+ if (arg == NULL && dep_name)
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ if (rmap_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+
return CMD_SUCCESS;
}
@@ -2395,163 +2433,365 @@ bgp_route_set_delete (struct vty *vty, struct route_map_index *index,
return CMD_SUCCESS;
}
-/* Hook function for updating route_map assignment. */
+/*
+ * This is the workhorse routine for processing in/out/import/export routemap
+ * modifications.
+ */
static void
-bgp_route_map_update (const char *unused)
+bgp_route_map_process_peer (char *rmap_name, struct peer *peer,
+ int afi, int safi, int route_update)
{
- int i;
- afi_t afi;
- safi_t safi;
- int direct;
- struct listnode *node, *nnode;
- struct listnode *mnode, *mnnode;
- struct bgp *bgp;
- struct peer *peer;
- struct peer_group *group;
+
+ int update;
struct bgp_filter *filter;
- struct bgp_node *bn;
- struct bgp_static *bgp_static;
- /* For neighbor route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+ if (!peer || !rmap_name)
+ return;
+
+ filter = &peer->filter[afi][safi];
+ /*
+ * in is for non-route-server clients,
+ * import/export is for route-server clients,
+ * out is for all peers
+ */
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_RSERVER_CLIENT))
{
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &peer->filter[afi][safi];
-
- for (direct = RMAP_IN; direct < RMAP_MAX; direct++)
- {
- if (filter->map[direct].name)
- filter->map[direct].map =
- route_map_lookup_by_name (filter->map[direct].name);
- else
- filter->map[direct].map = NULL;
- }
-
- if (filter->usmap.name)
- filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
- else
- filter->usmap.map = NULL;
- }
- }
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
+ if (filter->map[RMAP_IN].name &&
+ (strcmp(rmap_name, filter->map[RMAP_IN].name) == 0))
{
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &group->conf->filter[afi][safi];
-
- for (direct = RMAP_IN; direct < RMAP_MAX; direct++)
- {
- if (filter->map[direct].name)
- filter->map[direct].map =
- route_map_lookup_by_name (filter->map[direct].name);
- else
- filter->map[direct].map = NULL;
- }
-
- if (filter->usmap.name)
- filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
- else
- filter->usmap.map = NULL;
- }
+ filter->map[RMAP_IN].map =
+ route_map_lookup_by_name (filter->map[RMAP_IN].name);
+
+ if (route_update)
+ {
+ if (CHECK_FLAG (peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ {
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on "
+ "peer %s (inbound, soft-reconfig)",
+ rmap_name, peer->host);
+
+ bgp_soft_reconfig_in (peer, afi, safi);
+ }
+ else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ {
+
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on "
+ "peer %s (inbound, route-refresh)",
+ rmap_name, peer->host);
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ }
+ }
}
}
- /* For default-originate route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_RSERVER_CLIENT))
{
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ update = 0;
+
+ if (filter->map[RMAP_IMPORT].name &&
+ (strcmp(rmap_name, filter->map[RMAP_IMPORT].name) == 0))
{
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- if (peer->default_rmap[afi][safi].name)
- peer->default_rmap[afi][safi].map =
- route_map_lookup_by_name (peer->default_rmap[afi][safi].name);
- else
- peer->default_rmap[afi][safi].map = NULL;
- }
+ filter->map[RMAP_IMPORT].map =
+ route_map_lookup_by_name (filter->map[RMAP_IMPORT].name);
+ update = 1;
+ }
+
+ if (filter->map[RMAP_EXPORT].name &&
+ (strcmp(rmap_name, filter->map[RMAP_EXPORT].name) == 0))
+ {
+ filter->map[RMAP_EXPORT].map =
+ route_map_lookup_by_name (filter->map[RMAP_EXPORT].name);
+
+ update = 1;
+ }
+
+ if (update && route_update)
+ {
+ if (CHECK_FLAG (peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ {
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on "
+ "peer %s (import, soft-reconfig)",
+ rmap_name, peer->host);
+
+ bgp_soft_reconfig_in (peer, afi, safi);
+ }
+ else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ {
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on "
+ "peer %s (import, route-refresh)",
+ rmap_name, peer->host);
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ }
+ /* DD: Else, what else do we do ? Reset peer ? */
}
}
- /* For table route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+ if (filter->map[RMAP_OUT].name &&
+ (strcmp(rmap_name, filter->map[RMAP_OUT].name) == 0))
+ {
+ filter->map[RMAP_OUT].map =
+ route_map_lookup_by_name (filter->map[RMAP_OUT].name);
+
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on peer %s (outbound)",
+ rmap_name, peer->host);
+
+ if (route_update)
+ bgp_announce_route_all(peer);
+ }
+
+ if (filter->usmap.name &&
+ (strcmp(rmap_name, filter->usmap.name) == 0))
{
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- if (bgp->table_map[afi][safi].name)
- {
- bgp->table_map[afi][safi].map =
- route_map_lookup_by_name (bgp->table_map[afi][safi].name);
- bgp_zebra_announce_table(bgp, afi, safi);
- }
- else
- bgp->table_map[afi][safi].map = NULL;
- }
+ filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
+ if (route_update)
+ bgp_announce_route_all(peer);
}
+}
- /* For network route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+static void
+bgp_route_map_update_peer_group(char *rmap_name, struct bgp *bgp)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct bgp_filter *filter;
+ int afi, safi;
+ int direct;
+
+ if (!bgp)
+ return;
+
+ /* All the peers have been updated correctly already. This is
+ * just updating the placeholder data. No real update required.
+ */
+ for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ filter = &group->conf->filter[afi][safi];
+
+ for (direct = RMAP_IN; direct < RMAP_MAX; direct++)
+ {
+ if ((filter->map[direct].name) &&
+ (strcmp(rmap_name, filter->map[direct].name) == 0))
+ filter->map[direct].map =
+ route_map_lookup_by_name (filter->map[direct].name);
+ }
+
+ if (filter->usmap.name &&
+ (strcmp(rmap_name, filter->usmap.name) == 0))
+ filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
+ }
+}
+
+static int
+bgp_route_map_process_update (void *arg, char *rmap_name, int route_update)
+{
+ int i;
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+ struct bgp_node *bn;
+ struct bgp_static *bgp_static;
+ struct bgp *bgp = (struct bgp *)arg;
+ struct listnode *node, *nnode;
+ char buf[INET6_ADDRSTRLEN];
+
+ if (!bgp)
+ return;
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
+
+ /* Ignore dummy peer-group structure */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ continue;
+
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- for (bn = bgp_table_top (bgp->route[afi][safi]); bn;
- bn = bgp_route_next (bn))
- if ((bgp_static = bn->info) != NULL)
+ {
+ /* Ignore inactive AFI/SAFI */
+ if (! peer->afc[afi][safi])
+ continue;
+
+ /* process in/out/import/export route-maps */
+ bgp_route_map_process_peer(rmap_name, peer, afi, safi, route_update);
+
+ /* process default-originate route-map */
+ if (peer->default_rmap[afi][safi].name &&
+ (strcmp (rmap_name, peer->default_rmap[afi][safi].name) == 0))
{
- if (bgp_static->rmap.name)
- bgp_static->rmap.map =
- route_map_lookup_by_name (bgp_static->rmap.name);
- else
- bgp_static->rmap.map = NULL;
+ peer->default_rmap[afi][safi].map =
+ route_map_lookup_by_name (peer->default_rmap[afi][safi].name);
+
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on "
+ "default-originate", rmap_name);
+
+ if (route_update)
+ bgp_default_originate (peer, afi, safi, 0);
}
+ }
}
+ bgp_route_map_update_peer_group(rmap_name, bgp);
+
+ /* For table route-map updates. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (bgp->table_map[afi][safi].name &&
+ (strcmp(rmap_name, bgp->table_map[afi][safi].name) == 0))
+ {
+ bgp->table_map[afi][safi].map =
+ route_map_lookup_by_name (bgp->table_map[afi][safi].name);
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on "
+ "table map", rmap_name);
+ if (route_update)
+ bgp_zebra_announce_table(bgp, afi, safi);
+ }
+ }
+
+ /* For network route-map updates. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ for (bn = bgp_table_top (bgp->route[afi][safi]); bn;
+ bn = bgp_route_next (bn))
+ if ((bgp_static = bn->info) != NULL)
+ {
+ if (bgp_static->rmap.name &&
+ (strcmp(rmap_name, bgp_static->rmap.name) == 0))
+ {
+ bgp_static->rmap.map =
+ route_map_lookup_by_name (bgp_static->rmap.name);
+ if (route_update)
+ if (!bgp_static->backdoor)
+ {
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on "
+ "static route %s", rmap_name,
+ inet_ntop (bn->p.family, &bn->p.u.prefix,
+ buf, INET6_ADDRSTRLEN));
+ bgp_static_update (bgp, &bn->p, bgp_static, afi, safi);
+ }
+ }
+ }
+
/* For redistribute route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (bgp->rmap[afi][i].name &&
+ (strcmp(rmap_name, bgp->rmap[afi][i].name) == 0))
+ {
+ bgp->rmap[afi][i].map =
+ route_map_lookup_by_name (bgp->rmap[afi][i].name);
+
+ if (bgp->redist[afi][i] && route_update)
+ {
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Processing route_map %s update on "
+ "redistributed routes", rmap_name);
+
+ bgp_redistribute_resend (bgp, afi, i);
+ }
+ }
+ }
+
+ return (0);
+}
+
+static int
+bgp_route_map_process_update_cb (void *arg, char *rmap_name)
+{
+ return bgp_route_map_process_update (arg, rmap_name, 1);
+}
+
+int
+bgp_route_map_update_timer(struct thread *thread)
+{
+ struct bgp *bgp = THREAD_ARG(thread);
+
+ bgp->t_rmap_update = NULL;
+
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Started processing route map update");
+
+ route_map_walk_update_list((void *)bgp, bgp_route_map_process_update_cb);
+
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Finished processing route map update");
+
+ return (0);
+}
+
+static void
+bgp_route_map_mark_update (char *rmap_name)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
{
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ if (bgp->t_rmap_update == NULL)
{
- if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name)
- bgp->rmap[ZEBRA_FAMILY_IPV4][i].map =
- route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name);
-#ifdef HAVE_IPV6
- if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name)
- bgp->rmap[ZEBRA_FAMILY_IPV6][i].map =
- route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name);
-#endif /* HAVE_IPV6 */
+ if (BGP_DEBUG(events, EVENTS))
+ zlog_debug("Starting route map update timer (in %d secs)",
+ bgp->rmap_update_timer);
+ /* rmap_update_timer of 0 means don't do route updates */
+ if (bgp->rmap_update_timer)
+ bgp->t_rmap_update =
+ thread_add_timer(master, bgp_route_map_update_timer, bgp,
+ bgp->rmap_update_timer);
+ else
+ bgp_route_map_process_update((void *)bgp, rmap_name, 0);
}
}
}
static void
-bgp_route_map_add (const char *unused)
+bgp_route_map_add (const char *rmap_name)
{
if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("received route-map add");
+ zlog_debug ("received route-map add of %s", rmap_name);
+
+ if (route_map_mark_updated(rmap_name, 0) == 0)
+ bgp_route_map_mark_update(rmap_name);
- bgp_route_map_update(unused);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
+
static void
-bgp_route_map_delete (const char *unused)
+bgp_route_map_delete (const char *rmap_name)
{
if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("received route-map delete");
+ zlog_debug ("received route-map delete of %s", rmap_name);
+
+ if (route_map_mark_updated(rmap_name, 1) == 0)
+ bgp_route_map_mark_update(rmap_name);
- bgp_route_map_update(unused);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
+
static void
-bgp_route_map_event (route_map_event_t event, const char *unused)
+bgp_route_map_event (route_map_event_t event, const char *rmap_name)
{
if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("received route-map event");
+ zlog_debug ("received route-map event for %s", rmap_name);
- bgp_route_map_update(unused);
+ if (route_map_mark_updated(rmap_name, 0) == 0)
+ bgp_route_map_mark_update(rmap_name);
+
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
@@ -2563,7 +2803,8 @@ DEFUN (match_peer,
"IPv6 address of peer\n"
"IP address of peer\n")
{
- return bgp_route_match_add (vty, vty->index, "peer", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "peer", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (match_peer_local,
@@ -2573,7 +2814,8 @@ DEFUN (match_peer_local,
"Match peer address\n"
"Static or Redistributed routes\n")
{
- return bgp_route_match_add (vty, vty->index, "peer", "local");
+ return bgp_route_match_add (vty, vty->index, "peer", "local",
+ RMAP_EVENT_MATCH_DELETED);
}
DEFUN (no_match_peer,
@@ -2584,9 +2826,11 @@ DEFUN (no_match_peer,
"Match peer address\n")
{
if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "peer", NULL);
+ return bgp_route_match_delete (vty, vty->index, "peer", NULL,
+ RMAP_EVENT_MATCH_DELETED);
- return bgp_route_match_delete (vty, vty->index, "peer", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "peer", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_peer,
@@ -2616,7 +2860,8 @@ DEFUN (match_ip_address,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip address", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_address,
@@ -2628,9 +2873,11 @@ DEFUN (no_match_ip_address,
"Match address of route\n")
{
if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip address", NULL);
+ return bgp_route_match_delete (vty, vty->index, "ip address", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return bgp_route_match_delete (vty, vty->index, "ip address", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_address,
@@ -2654,7 +2901,8 @@ DEFUN (match_ip_next_hop,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_next_hop,
@@ -2666,9 +2914,11 @@ DEFUN (no_match_ip_next_hop,
"Match next-hop address of route\n")
{
if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_next_hop,
@@ -2691,7 +2941,8 @@ DEFUN (match_probability,
"Match portion of routes defined by percentage value\n"
"Percentage of routes\n")
{
- return bgp_route_match_add (vty, vty->index, "probability", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "probability", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_probability,
@@ -2701,7 +2952,8 @@ DEFUN (no_match_probability,
MATCH_STR
"Match portion of routes defined by percentage value\n")
{
- return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL);
+ return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL,
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_probability,
@@ -2724,7 +2976,8 @@ DEFUN (match_ip_route_source,
"IP access-list number (expanded range)\n"
"IP standard access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip route-source", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip route-source", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_route_source,
@@ -2736,9 +2989,11 @@ DEFUN (no_match_ip_route_source,
"Match advertising source address of route\n")
{
if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip route-source", NULL);
+ return bgp_route_match_delete (vty, vty->index, "ip route-source", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return bgp_route_match_delete (vty, vty->index, "ip route-source", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip route-source",
+ argv[0], RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_route_source,
@@ -2761,7 +3016,8 @@ DEFUN (match_ip_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_address_prefix_list,
@@ -2773,10 +3029,9 @@ DEFUN (no_match_ip_address_prefix_list,
"Match address of route\n"
"Match entries of prefix-lists\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
-
- return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip address prefix-list",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_address_prefix_list,
@@ -2798,7 +3053,8 @@ DEFUN (match_ip_next_hop_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_next_hop_prefix_list,
@@ -2810,10 +3066,9 @@ DEFUN (no_match_ip_next_hop_prefix_list,
"Match next-hop address of route\n"
"Match entries of prefix-lists\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
-
- return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_next_hop_prefix_list,
@@ -2835,7 +3090,8 @@ DEFUN (match_ip_route_source_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip route-source prefix-list", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip route-source prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_route_source_prefix_list,
@@ -2847,10 +3103,9 @@ DEFUN (no_match_ip_route_source_prefix_list,
"Match advertising source address of route\n"
"Match entries of prefix-lists\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", NULL);
-
- return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_route_source_prefix_list,
@@ -2870,7 +3125,8 @@ DEFUN (match_metric,
"Match metric of route\n"
"Metric value\n")
{
- return bgp_route_match_add (vty, vty->index, "metric", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "metric", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_metric,
@@ -2880,10 +3136,9 @@ DEFUN (no_match_metric,
MATCH_STR
"Match metric of route\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "metric", NULL);
-
- return bgp_route_match_delete (vty, vty->index, "metric", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "metric",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_metric,
@@ -2901,7 +3156,8 @@ DEFUN (match_local_pref,
"Match local-preference of route\n"
"Metric value\n")
{
- return bgp_route_match_add (vty, vty->index, "local-preference", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "local-preference", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_local_pref,
@@ -2911,10 +3167,12 @@ DEFUN (no_match_local_pref,
MATCH_STR
"Match local preference of route\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "local-preference", NULL);
+ return bgp_route_match_delete (vty, vty->index, "local-preference",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_MATCH_DELETED);
- return bgp_route_match_delete (vty, vty->index, "local-preference", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "local-preference", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_local_pref,
@@ -2934,7 +3192,8 @@ DEFUN (match_community,
"Community-list number (expanded)\n"
"Community-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "community", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "community", argv[0],
+ RMAP_EVENT_CLIST_ADDED);
}
DEFUN (match_community_exact,
@@ -2955,7 +3214,8 @@ DEFUN (match_community_exact,
sprintf (argstr, "%s exact-match", argv[0]);
- ret = bgp_route_match_add (vty, vty->index, "community", argstr);
+ ret = bgp_route_match_add (vty, vty->index, "community", argstr,
+ RMAP_EVENT_CLIST_ADDED);
XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr);
@@ -2969,7 +3229,8 @@ DEFUN (no_match_community,
MATCH_STR
"Match BGP community list\n")
{
- return bgp_route_match_delete (vty, vty->index, "community", NULL);
+ return bgp_route_match_delete (vty, vty->index, "community", NULL,
+ RMAP_EVENT_CLIST_DELETED);
}
ALIAS (no_match_community,
@@ -3002,7 +3263,8 @@ DEFUN (match_ecommunity,
"Extended community-list number (expanded)\n"
"Extended community-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "extcommunity", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "extcommunity", argv[0],
+ RMAP_EVENT_ECLIST_ADDED);
}
DEFUN (no_match_ecommunity,
@@ -3012,7 +3274,8 @@ DEFUN (no_match_ecommunity,
MATCH_STR
"Match BGP/VPN extended community list\n")
{
- return bgp_route_match_delete (vty, vty->index, "extcommunity", NULL);
+ return bgp_route_match_delete (vty, vty->index, "extcommunity", NULL,
+ RMAP_EVENT_ECLIST_DELETED);
}
ALIAS (no_match_ecommunity,
@@ -3032,7 +3295,8 @@ DEFUN (match_aspath,
"Match BGP AS path list\n"
"AS path access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "as-path", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "as-path", argv[0],
+ RMAP_EVENT_ASLIST_ADDED);
}
DEFUN (no_match_aspath,
@@ -3042,7 +3306,8 @@ DEFUN (no_match_aspath,
MATCH_STR
"Match BGP AS path list\n")
{
- return bgp_route_match_delete (vty, vty->index, "as-path", NULL);
+ return bgp_route_match_delete (vty, vty->index, "as-path", NULL,
+ RMAP_EVENT_ASLIST_DELETED);
}
ALIAS (no_match_aspath,
@@ -3063,11 +3328,14 @@ DEFUN (match_origin,
"unknown heritage\n")
{
if (strncmp (argv[0], "igp", 2) == 0)
- return bgp_route_match_add (vty, vty->index, "origin", "igp");
+ return bgp_route_match_add (vty, vty->index, "origin", "igp",
+ RMAP_EVENT_MATCH_ADDED);
if (strncmp (argv[0], "egp", 1) == 0)
- return bgp_route_match_add (vty, vty->index, "origin", "egp");
+ return bgp_route_match_add (vty, vty->index, "origin", "egp",
+ RMAP_EVENT_MATCH_ADDED);
if (strncmp (argv[0], "incomplete", 2) == 0)
- return bgp_route_match_add (vty, vty->index, "origin", "incomplete");
+ return bgp_route_match_add (vty, vty->index, "origin", "incomplete",
+ RMAP_EVENT_MATCH_ADDED);
return CMD_WARNING;
}
@@ -3079,7 +3347,8 @@ DEFUN (no_match_origin,
MATCH_STR
"BGP origin code\n")
{
- return bgp_route_match_delete (vty, vty->index, "origin", NULL);
+ return bgp_route_match_delete (vty, vty->index, "origin", NULL,
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_origin,
@@ -3749,7 +4018,8 @@ DEFUN (match_ipv6_address,
"Match IPv6 address of route\n"
"IPv6 access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ipv6_address,
@@ -3761,7 +4031,8 @@ DEFUN (no_match_ipv6_address,
"Match IPv6 address of route\n"
"IPv6 access-list name\n")
{
- return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
DEFUN (match_ipv6_next_hop,
@@ -3772,7 +4043,8 @@ DEFUN (match_ipv6_next_hop,
"Match IPv6 next-hop address of route\n"
"IPv6 address of next hop\n")
{
- return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_ipv6_next_hop,
@@ -3784,7 +4056,8 @@ DEFUN (no_match_ipv6_next_hop,
"Match IPv6 next-hop address of route\n"
"IPv6 address of next hop\n")
{
- return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
}
DEFUN (match_ipv6_address_prefix_list,
@@ -3796,7 +4069,8 @@ DEFUN (match_ipv6_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ipv6_address_prefix_list,
@@ -3809,7 +4083,8 @@ DEFUN (no_match_ipv6_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_DELETED);
}
DEFUN (set_ipv6_nexthop_peer,
@@ -4207,3 +4482,15 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &no_match_pathlimit_as_cmd);
install_element (RMAP_NODE, &no_match_pathlimit_as_val_cmd);
}
+
+void
+bgp_route_map_terminate (void)
+{
+ /* ToDo: Cleanup all the used memory */
+
+ route_map_add_hook (NULL);
+ route_map_delete_hook (NULL);
+ route_map_event_hook (NULL);
+ route_map_finish();
+
+}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index d3b21124a..10bdc1507 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -3997,6 +3997,55 @@ ALIAS (no_neighbor_advertise_interval,
"Minimum interval between sending BGP routing updates\n"
"time in seconds\n")
+/* Time to wait before processing route-map updates */
+DEFUN (bgp_set_route_map_delay_timer,
+ bgp_set_route_map_delay_timer_cmd,
+ "bgp route-map delay-timer <0-600>",
+ SET_STR
+ "BGP route-map delay timer\n"
+ "Time in secs to wait before processing route-map changes\n"
+ "0 disables the timer and no route updates happen when\n"
+ "route-maps change")
+{
+ u_int32_t rmap_delay_timer;
+ struct bgp *bgp;
+
+ bgp = vty->index;
+ if (argv[0])
+ {
+ VTY_GET_INTEGER_RANGE ("delay-timer", rmap_delay_timer, argv[0], 0, 600);
+ bgp->rmap_update_timer = rmap_delay_timer;
+
+ /* if the dynamic update handling is being disabled, and a timer is
+ * running, stop the timer and act as if the timer has already fired.
+ */
+ if (!rmap_delay_timer && bgp->t_rmap_update )
+ {
+ BGP_TIMER_OFF(bgp->t_rmap_update);
+ thread_execute (bm->master, bgp_route_map_update_timer, &bgp, 0);
+ }
+ return CMD_SUCCESS;
+ }
+ else
+ CMD_WARNING;
+}
+
+DEFUN (no_bgp_set_route_map_delay_timer,
+ no_bgp_set_route_map_delay_timer_cmd,
+ "no bgp route-map delay-timer",
+ NO_STR
+ "Default BGP route-map delay timer\n"
+ "Reset to default time to wait for processing route-map changes")
+{
+ u_int32_t rmap_delay_timer;
+ struct bgp *bgp;
+
+ bgp = vty->index;
+ bgp->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
+
+ return CMD_SUCCESS;
+}
+
/* neighbor interface */
static int
peer_interface_vty (struct vty *vty, const char *ip_str, const char *str)
@@ -9928,6 +9977,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_bgp_timers_cmd);
install_element (BGP_NODE, &no_bgp_timers_arg_cmd);
+ /* route-map delay-timer commands */
+ install_element (BGP_NODE, &bgp_set_route_map_delay_timer_cmd);
+ install_element (BGP_NODE, &no_bgp_set_route_map_delay_timer_cmd);
+
/* "bgp client-to-client reflection" commands */
install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd);
install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 58990c503..b3d110911 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1324,13 +1324,30 @@ bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type)
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type));
-
+
/* Send distribute add message to zebra. */
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
return CMD_SUCCESS;
}
+int
+bgp_redistribute_resend (struct bgp *bgp, afi_t afi, int type)
+{
+ /* Return if zebra connection is not established. */
+ if (zclient->sock < 0)
+ return -1;
+
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type));
+
+ /* Send distribute add message to zebra. */
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type);
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
+
+ return 0;
+}
+
/* Redistribute with route-map specification. */
int
bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type,
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 34e121670..eb049a47e 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -39,6 +39,7 @@ extern void bgp_zebra_announce_table (struct bgp *, afi_t, safi_t);
extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t);
extern int bgp_redistribute_set (struct bgp *, afi_t, int);
+extern int bgp_redistribute_resend (struct bgp *, afi_t, int);
extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *);
extern int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t);
extern int bgp_redistribute_unset (struct bgp *, afi_t, int);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 347c4bc5f..4332722ef 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2334,6 +2334,9 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)
bgp_router_id_set(bgp, &router_id_zebra);
*bgp_val = bgp;
+ bgp->t_rmap_update = NULL;
+ bgp->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
+
/* Create BGP server socket, if first instance. */
if (list_isempty(bm->bgp)
&& !bgp_option_check (BGP_OPT_NO_LISTEN))
@@ -2358,6 +2361,9 @@ bgp_delete (struct bgp *bgp)
afi_t afi;
int i;
+ if (bgp->t_rmap_update)
+ BGP_TIMER_OFF(bgp->t_rmap_update);
+
/* Delete static route. */
bgp_static_delete (bgp);
@@ -4416,7 +4422,7 @@ peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)
}
static void
-peer_aslist_update (void)
+peer_aslist_update (char *aslist_name)
{
afi_t afi;
safi_t safi;
@@ -4466,8 +4472,42 @@ peer_aslist_update (void)
}
}
}
+static void
+peer_aslist_add (char *aslist_name)
+{
+ peer_aslist_update (aslist_name);
+ route_map_notify_dependencies((char *)aslist_name, RMAP_EVENT_ASLIST_ADDED);
+}
+
+static void
+peer_aslist_del (char *aslist_name)
+{
+ peer_aslist_update (aslist_name);
+ route_map_notify_dependencies((char *)aslist_name, RMAP_EVENT_ASLIST_DELETED);
+}
+
/* Set route-map to the peer. */
+static void
+peer_reprocess_routes (struct peer *peer, int direct,
+ afi_t afi, safi_t safi)
+{
+ if (peer->status != Established)
+ return;
+
+ if (direct != RMAP_OUT)
+ {
+ if (CHECK_FLAG (peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ bgp_soft_reconfig_in (peer, afi, safi);
+ else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ }
+ else
+ bgp_announce_route(peer, afi, safi);
+}
+
int
peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
@@ -4491,12 +4531,15 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
if (filter->map[direct].name)
free (filter->map[direct].name);
-
+
filter->map[direct].name = strdup (name);
filter->map[direct].map = route_map_lookup_by_name (name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ peer_reprocess_routes(peer, direct, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4510,6 +4553,7 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
free (filter->map[direct].name);
filter->map[direct].name = strdup (name);
filter->map[direct].map = route_map_lookup_by_name (name);
+ peer_reprocess_routes (peer, direct, afi, safi);
}
return 0;
}
@@ -4557,7 +4601,10 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
filter->map[direct].map = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ peer_reprocess_routes(peer, direct, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4571,6 +4618,7 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
free (filter->map[direct].name);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
+ peer_reprocess_routes(peer, direct, afi, safi);
}
return 0;
}
@@ -4599,7 +4647,10 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
filter->usmap.map = route_map_lookup_by_name (name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ bgp_announce_route (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4613,6 +4664,7 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
free (filter->usmap.name);
filter->usmap.name = strdup (name);
filter->usmap.map = route_map_lookup_by_name (name);
+ bgp_announce_route (peer, afi, safi);
}
return 0;
}
@@ -4639,7 +4691,10 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
filter->usmap.map = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ bgp_announce_route(peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4653,6 +4708,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
free (filter->usmap.name);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
+ bgp_announce_route(peer, afi, safi);
}
return 0;
}
@@ -5731,6 +5787,10 @@ bgp_config_write (struct vty *vty)
vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive,
bgp->default_holdtime, VTY_NEWLINE);
+ if (bgp->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
+ vty_out (vty, " bgp route-map delay-timer %d%s", bgp->rmap_update_timer,
+ VTY_NEWLINE);
+
/* peer-group */
for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
{
@@ -5812,8 +5872,8 @@ bgp_init (void)
/* Filter list initialize. */
bgp_filter_init ();
- as_list_add_hook (peer_aslist_update);
- as_list_delete_hook (peer_aslist_update);
+ as_list_add_hook (peer_aslist_add);
+ as_list_delete_hook (peer_aslist_del);
/* Prefix list initialize.*/
prefix_list_init ();
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 7cd43cf5a..4faf452b2 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* For union sockunion. */
#include "sockunion.h"
+#include "routemap.h"
/* Typedef BGP specific types. */
typedef u_int32_t as_t;
@@ -193,6 +194,11 @@ struct bgp
/* BGP redistribute route-map. */
struct bgp_rmap rmap[AFI_MAX][ZEBRA_ROUTE_MAX];
+ /* timer to dampen route map changes */
+ struct thread *t_rmap_update; /* Handle route map updates */
+ u_int32_t rmap_update_timer; /* Route map update timer */
+#define RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
+
/* BGP distance configuration. */
u_char distance_ebgp;
u_char distance_ibgp;
@@ -1052,4 +1058,6 @@ extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type);
extern int peer_ttl_security_hops_set (struct peer *, int);
extern int peer_ttl_security_hops_unset (struct peer *);
+extern int bgp_route_map_update_timer (struct thread *thread);
+extern void bgp_route_map_terminate(void);
#endif /* _QUAGGA_BGPD_H */
diff --git a/lib/filter.c b/lib/filter.c
index 96605c7d5..ae50e6cbe 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -28,6 +28,7 @@
#include "sockunion.h"
#include "buffer.h"
#include "log.h"
+#include "routemap.h"
struct filter_cisco
{
@@ -460,6 +461,7 @@ access_list_filter_add (struct access_list *access, struct filter *filter)
/* Run hook function. */
if (access->master->add_hook)
(*access->master->add_hook) (access);
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
}
/* If access_list has no filter then return 1. */
@@ -493,6 +495,7 @@ access_list_filter_delete (struct access_list *access, struct filter *filter)
filter_free (filter);
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
/* If access_list becomes empty delete it from access_master. */
if (access_list_empty (access))
access_list_delete (access);
@@ -1337,6 +1340,7 @@ DEFUN (no_access_list_all,
master = access->master;
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
@@ -1508,6 +1512,7 @@ DEFUN (no_ipv6_access_list_all,
master = access->master;
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
diff --git a/lib/memtypes.c b/lib/memtypes.c
index f418b3d0a..00ed0a48e 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -55,6 +55,7 @@ struct memory_list memory_list_lib[] =
{ MTYPE_ROUTE_MAP_RULE, "Route map rule" },
{ MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" },
{ MTYPE_ROUTE_MAP_COMPILED, "Route map compiled" },
+ { MTYPE_ROUTE_MAP_DEP, "Route map dependency" },
{ MTYPE_CMD_TOKENS, "Command desc" },
{ MTYPE_KEY, "Key" },
{ MTYPE_KEYCHAIN, "Key chain" },
diff --git a/lib/plist.c b/lib/plist.c
index 7416ebd2f..f5950c331 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -29,6 +29,7 @@
#include "buffer.h"
#include "stream.h"
#include "log.h"
+#include "routemap.h"
/* Each prefix-list's entry. */
struct prefix_list_entry
@@ -325,13 +326,16 @@ prefix_list_delete (struct prefix_list *plist)
cleared. */
master->recent = NULL;
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
+
+ if (master->delete_hook)
+ (*master->delete_hook) (NULL);
+
if (plist->name)
XFREE (MTYPE_PREFIX_LIST_STR, plist->name);
-
+
prefix_list_free (plist);
-
- if (master->delete_hook)
- (*master->delete_hook) (NULL);
+
}
static struct prefix_list_entry *
@@ -452,6 +456,7 @@ prefix_list_entry_delete (struct prefix_list *plist,
if (update_list)
{
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
if (plist->master->delete_hook)
(*plist->master->delete_hook) (plist);
@@ -514,6 +519,7 @@ prefix_list_entry_add (struct prefix_list *plist,
if (plist->master->add_hook)
(*plist->master->add_hook) (plist);
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_ADDED);
plist->master->recent = plist;
}
diff --git a/lib/routemap.c b/lib/routemap.c
index 1e1510ebd..b884fed2a 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "command.h"
#include "vty.h"
#include "log.h"
+#include "hash.h"
/* Vector for route match rules. */
static vector route_match_vec;
@@ -60,15 +61,47 @@ struct route_map_list
void (*add_hook) (const char *);
void (*delete_hook) (const char *);
- void (*event_hook) (route_map_event_t, const char *);
+ void (*event_hook) (route_map_event_t, const char *);
};
/* Master list of route map. */
-static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
+static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL, NULL };
+
+enum route_map_upd8_type
+ {
+ ROUTE_MAP_ADD = 1,
+ ROUTE_MAP_DEL,
+ };
+
+/* all possible route-map dependency types */
+enum route_map_dep_type
+ {
+ ROUTE_MAP_DEP_RMAP = 1,
+ ROUTE_MAP_DEP_CLIST,
+ ROUTE_MAP_DEP_ECLIST,
+ ROUTE_MAP_DEP_PLIST,
+ ROUTE_MAP_DEP_ASPATH,
+ ROUTE_MAP_DEP_FILTER,
+ ROUTE_MAP_DEP_MAX,
+ };
+
+struct route_map_dep
+{
+ char *dep_name;
+ struct hash *dep_rmap_hash;
+ struct hash *this_hash; /* ptr to the hash structure this is part of */
+};
-static void
-route_map_rule_delete (struct route_map_rule_list *,
- struct route_map_rule *);
+/* Hashes maintaining dependency between various sublists used by route maps */
+struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
+
+static unsigned int route_map_dep_hash_make_key (void *p);
+static int route_map_dep_hash_cmp (const void *p1, const void *p2);
+static void route_map_init_dep_hashes (void);
+static void route_map_clear_all_references (char *rmap_name);
+static void route_map_rule_delete (struct route_map_rule_list *,
+ struct route_map_rule *);
+static int rmap_debug = 0;
static void
route_map_index_delete (struct route_map_index *, int);
@@ -105,45 +138,72 @@ route_map_add (const char *name)
/* Execute hook. */
if (route_map_master.add_hook)
- (*route_map_master.add_hook) (name);
-
+ {
+ (*route_map_master.add_hook) (name);
+ route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
+ }
return map;
}
-/* Route map delete from list. */
-static void
-route_map_delete (struct route_map *map)
+/* this is supposed to be called post processing by
+ * the delete hook function. Don't invoke delete_hook
+ * again in this routine.
+ */
+void
+route_map_free_map (struct route_map *map)
{
struct route_map_list *list;
struct route_map_index *index;
- char *name;
-
+
while ((index = map->head) != NULL)
route_map_index_delete (index, 0);
- name = map->name;
-
list = &route_map_master;
- if (map->next)
- map->next->prev = map->prev;
- else
- list->tail = map->prev;
+ if (map != NULL)
+ {
+ if (map->next)
+ map->next->prev = map->prev;
+ else
+ list->tail = map->prev;
- if (map->prev)
- map->prev->next = map->next;
- else
- list->head = map->next;
+ if (map->prev)
+ map->prev->next = map->next;
+ else
+ list->head = map->next;
- XFREE (MTYPE_ROUTE_MAP, map);
+ XFREE (MTYPE_ROUTE_MAP_NAME, map->name);
+ XFREE (MTYPE_ROUTE_MAP, map);
+ }
+}
+/* Route map delete from list. */
+static void
+route_map_delete (struct route_map *map)
+{
+ struct route_map_index *index;
+ char *name;
+
+ while ((index = map->head) != NULL)
+ route_map_index_delete (index, 0);
+
+ name = map->name;
+ map->head = NULL;
+
+ /* Clear all dependencies */
+ route_map_clear_all_references(name);
+ map->deleted = 1;
/* Execute deletion hook. */
if (route_map_master.delete_hook)
- (*route_map_master.delete_hook) (name);
-
- if (name)
- XFREE (MTYPE_ROUTE_MAP_NAME, name);
+ {
+ (*route_map_master.delete_hook) (name);
+ route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
+ }
+ if (!map->to_be_processed)
+ {
+ route_map_free_map (map);
+ }
}
/* Lookup route map by route map name string. */
@@ -152,12 +212,50 @@ route_map_lookup_by_name (const char *name)
{
struct route_map *map;
+ if (!name)
+ return NULL;
+
for (map = route_map_master.head; map; map = map->next)
- if (strcmp (map->name, name) == 0)
+ if ((strcmp (map->name, name) == 0) && (!map->deleted))
return map;
return NULL;
}
+int
+route_map_mark_updated (const char *name, int del_later)
+{
+ struct route_map *map;
+ int ret = -1;
+
+ /* We need to do this walk manually instead of calling lookup_by_name()
+ * because the lookup function doesn't return route maps marked as
+ * deleted.
+ */
+ for (map = route_map_master.head; map; map = map->next)
+ if (strcmp (map->name, name) == 0)
+ {
+ map->to_be_processed = 1;
+ ret = 0;
+ }
+
+ return(ret);
+}
+
+int
+route_map_clear_updated (struct route_map *map)
+{
+ int ret = -1;
+
+ if (map)
+ {
+ map->to_be_processed = 0;
+ if (map->deleted)
+ route_map_free_map(map);
+ }
+
+ return (ret);
+}
+
/* Lookup route map. If there isn't route map create one and return
it. */
static struct route_map *
@@ -168,9 +266,31 @@ route_map_get (const char *name)
map = route_map_lookup_by_name (name);
if (map == NULL)
map = route_map_add (name);
+
return map;
}
+void
+route_map_walk_update_list (void *arg,
+ int (*route_map_update_fn) (void *arg, char *name))
+{
+ struct route_map *node;
+ struct route_map *nnode = NULL;
+
+ for (node = route_map_master.head; node; node = nnode)
+ {
+ if (node->to_be_processed)
+ {
+ /* DD: Should we add any thread yield code here */
+ route_map_update_fn(arg, node->name);
+ nnode = node->next;
+ route_map_clear_updated(node);
+ }
+ else
+ nnode = node->next;
+ }
+}
+
/* Return route map's type string. */
static const char *
route_map_type_str (enum route_map_type type)
@@ -271,7 +391,8 @@ vty_show_route_map (struct vty *vty, const char *name)
else
{
for (map = route_map_master.head; map; map = map->next)
- vty_show_route_map_entry (vty, map);
+ if (!map->deleted)
+ vty_show_route_map_entry (vty, map);
}
return CMD_SUCCESS;
}
@@ -320,9 +441,11 @@ route_map_index_delete (struct route_map_index *index, int notify)
/* Execute event hook. */
if (route_map_master.event_hook && notify)
- (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
- index->map->name);
-
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
XFREE (MTYPE_ROUTE_MAP_INDEX, index);
}
@@ -386,9 +509,11 @@ route_map_index_add (struct route_map *map, enum route_map_type type,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
- map->name);
-
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
+ map->name);
+ route_map_notify_dependencies (map->name, RMAP_EVENT_CALL_ADDED);
+ }
return index;
}
@@ -521,6 +646,28 @@ rulecmp (const char *dst, const char *src)
return 1;
}
+/* Use this to return the already specified argument for this match. This is
+ * useful to get the specified argument with a route map match rule when the
+ * rule is being deleted and the argument is not provided.
+ */
+const char *
+route_map_get_match_arg(struct route_map_index *index, const char *match_name)
+{
+ struct route_map_rule *rule;
+ struct route_map_rule_cmd *cmd;
+
+ /* First lookup rule for add match statement. */
+ cmd = route_map_lookup_match (match_name);
+ if (cmd == NULL)
+ return NULL;
+
+ for (rule = index->match_list.head; rule; rule = rule->next)
+ if (rule->cmd == cmd && rule->rule_str != NULL)
+ return (rule->rule_str);
+
+ return (NULL);
+}
+
/* Add match statement to route map. */
int
route_map_add_match (struct route_map_index *index, const char *match_name,
@@ -572,10 +719,13 @@ route_map_add_match (struct route_map_index *index, const char *match_name,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (replaced ?
- RMAP_EVENT_MATCH_REPLACED:
- RMAP_EVENT_MATCH_ADDED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (replaced ?
+ RMAP_EVENT_MATCH_REPLACED:
+ RMAP_EVENT_MATCH_ADDED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
@@ -599,8 +749,11 @@ route_map_delete_match (struct route_map_index *index, const char *match_name,
route_map_rule_delete (&index->match_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
/* Can't find matched rule. */
@@ -659,10 +812,13 @@ route_map_add_set (struct route_map_index *index, const char *set_name,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (replaced ?
- RMAP_EVENT_SET_REPLACED:
- RMAP_EVENT_SET_ADDED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (replaced ?
+ RMAP_EVENT_SET_REPLACED:
+ RMAP_EVENT_SET_ADDED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
@@ -685,8 +841,11 @@ route_map_delete_set (struct route_map_index *index, const char *set_name,
route_map_rule_delete (&index->set_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
/* Can't find matched rule. */
@@ -899,6 +1058,273 @@ route_map_finish (void)
route_set_vec = NULL;
}
+/* Routines for route map dependency lists and dependency processing */
+static int
+route_map_rmap_hash_cmp (const void *p1, const void *p2)
+{
+ return (strcmp((char *)p1, (char *)p2) == 0);
+}
+
+static int
+route_map_dep_hash_cmp (const void *p1, const void *p2)
+{
+
+ return (strcmp (((struct route_map_dep *)p1)->dep_name, (char *)p2) == 0);
+}
+
+static void
+route_map_rmap_free(struct hash_backet *backet, void *arg)
+{
+ char *rmap_name = (char *)backet->data;
+
+ if (rmap_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+}
+
+static void
+route_map_dep_hash_free (struct hash_backet *backet, void *arg)
+{
+ struct route_map_dep *dep = (struct route_map_dep *)backet->data;
+
+ if (!dep)
+ return;
+
+ if (dep->dep_rmap_hash)
+ hash_iterate (dep->dep_rmap_hash, route_map_rmap_free, (void *)NULL);
+
+ hash_free(dep->dep_rmap_hash);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+}
+
+static void
+route_map_clear_reference(struct hash_backet *backet, void *arg)
+{
+ struct route_map_dep *dep = (struct route_map_dep *)backet->data;
+ char *rmap_name;
+
+ if (dep && arg)
+ {
+ rmap_name = (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
+ if (rmap_name)
+ {
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+ }
+ if (!dep->dep_rmap_hash->count)
+ {
+ dep = hash_release(dep->this_hash, (void *)dep->dep_name);
+ hash_free(dep->dep_rmap_hash);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+ }
+ }
+}
+
+static void
+route_map_clear_all_references (char *rmap_name)
+{
+ int i;
+
+ for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
+ {
+ hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
+ (void *)rmap_name);
+ }
+}
+
+static void *
+route_map_dep_hash_alloc(void *p)
+{
+ char *dep_name = (char *)p;
+ struct route_map_dep *dep_entry;
+
+ dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
+ dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
+ dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
+ route_map_rmap_hash_cmp);
+ dep_entry->this_hash = NULL;
+
+ return((void *)dep_entry);
+}
+
+static void *
+route_map_name_hash_alloc(void *p)
+{
+ return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (char *)p));
+}
+
+static unsigned int
+route_map_dep_hash_make_key (void *p)
+{
+ return (string_hash_make((char *)p));
+}
+
+static void
+route_map_print_dependency (struct hash_backet *backet, void *data)
+{
+ char *rmap_name = (char *)backet->data;
+ char *dep_name = (char *)data;
+
+ if (rmap_name)
+ zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, rmap_name);
+}
+
+static int
+route_map_dep_update (struct hash *dephash, const char *dep_name,
+ const char *rmap_name,
+ route_map_event_t type)
+{
+ struct route_map_dep *dep;
+ char *ret_map_name;
+
+ switch (type)
+ {
+ case RMAP_EVENT_PLIST_ADDED:
+ case RMAP_EVENT_CLIST_ADDED:
+ case RMAP_EVENT_ECLIST_ADDED:
+ case RMAP_EVENT_ASLIST_ADDED:
+ case RMAP_EVENT_CALL_ADDED:
+ case RMAP_EVENT_FILTER_ADDED:
+ if (rmap_debug)
+ zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__,
+ dep_name, rmap_name);
+ dep = (struct route_map_dep *) hash_get (dephash, (void *)dep_name,
+ route_map_dep_hash_alloc);
+ if (!dep)
+ return -1;
+
+ if (!dep->this_hash)
+ dep->this_hash = dephash;
+
+ hash_get(dep->dep_rmap_hash, rmap_name, route_map_name_hash_alloc);
+ break;
+ case RMAP_EVENT_PLIST_DELETED:
+ case RMAP_EVENT_CLIST_DELETED:
+ case RMAP_EVENT_ECLIST_DELETED:
+ case RMAP_EVENT_ASLIST_DELETED:
+ case RMAP_EVENT_CALL_DELETED:
+ case RMAP_EVENT_FILTER_DELETED:
+ if (rmap_debug)
+ zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__,
+ dep_name, rmap_name);
+ dep = (struct route_map_dep *) hash_get (dephash, (void *)dep_name,
+ NULL);
+ if (!dep)
+ return 0;
+ ret_map_name = (char *)hash_release(dep->dep_rmap_hash, (void *)rmap_name);
+ if (ret_map_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
+
+ if (!dep->dep_rmap_hash->count)
+ {
+ dep = hash_release(dephash, (void *)dep_name);
+ hash_free(dep->dep_rmap_hash);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+ dep = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (dep)
+ {
+ if (rmap_debug)
+ hash_iterate (dep->dep_rmap_hash, route_map_print_dependency, (void *)dep_name);
+ }
+ return 0;
+}
+
+static struct hash *
+route_map_get_dep_hash (route_map_event_t event)
+{
+ struct hash *upd8_hash = NULL;
+
+ switch (event)
+ {
+ case RMAP_EVENT_PLIST_ADDED:
+ case RMAP_EVENT_PLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
+ break;
+ case RMAP_EVENT_CLIST_ADDED:
+ case RMAP_EVENT_CLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
+ break;
+ case RMAP_EVENT_ECLIST_ADDED:
+ case RMAP_EVENT_ECLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
+ break;
+ case RMAP_EVENT_ASLIST_ADDED:
+ case RMAP_EVENT_ASLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
+ break;
+ case RMAP_EVENT_CALL_ADDED:
+ case RMAP_EVENT_CALL_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
+ break;
+ case RMAP_EVENT_FILTER_ADDED:
+ case RMAP_EVENT_FILTER_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
+ break;
+ default:
+ upd8_hash = NULL;
+ break;
+ }
+ return (upd8_hash);
+}
+
+static void
+route_map_process_dependency (struct hash_backet *backet, void *data)
+{
+ char *rmap_name;
+ route_map_event_t type = (route_map_event_t )data;
+
+ rmap_name = (char *)backet->data;
+
+ if (rmap_name)
+ {
+ if (rmap_debug)
+ zlog_debug("%s: Notifying %s of dependency", __FUNCTION__,
+ rmap_name);
+ if (route_map_master.event_hook)
+ (*route_map_master.event_hook) (type, rmap_name);
+ }
+}
+
+void
+route_map_upd8_dependency (route_map_event_t type, const char *arg,
+ const char *rmap_name)
+{
+ struct hash *upd8_hash = NULL;
+
+ if ((upd8_hash = route_map_get_dep_hash(type)))
+ route_map_dep_update (upd8_hash, arg, rmap_name, type);
+}
+
+void
+route_map_notify_dependencies (const char *affected_name, route_map_event_t event)
+{
+ struct route_map_dep *dep;
+ struct hash *upd8_hash;
+
+ if (!affected_name)
+ return;
+
+ if ((upd8_hash = route_map_get_dep_hash(event)) == NULL)
+ return;
+
+ dep = (struct route_map_dep *)hash_get (upd8_hash, (void *)affected_name,
+ NULL);
+ if (dep)
+ {
+ if (!dep->this_hash)
+ dep->this_hash = upd8_hash;
+
+ hash_iterate (dep->dep_rmap_hash, route_map_process_dependency, (void *)event);
+ }
+}
+
/* VTY related functions. */
DEFUN (route_map,
route_map_cmd,
@@ -1180,9 +1606,19 @@ DEFUN (rmap_call,
if (index)
{
if (index->nextrm)
- XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
+ {
+ route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
+ index->nextrm,
+ index->map->name);
+ XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
+ }
index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
}
+
+ /* Execute event hook. */
+ route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED,
+ index->nextrm,
+ index->map->name);
return CMD_SUCCESS;
}
@@ -1198,6 +1634,9 @@ DEFUN (no_rmap_call,
if (index->nextrm)
{
+ route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
+ index->nextrm,
+ index->map->name);
XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
index->nextrm = NULL;
}
@@ -1296,10 +1735,22 @@ static struct cmd_node rmap_node =
1
};
+static void
+route_map_init_dep_hashes (void)
+{
+ int i;
+
+ for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
+ route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
+ route_map_dep_hash_cmp);
+}
+
/* Initialization of route map vector. */
void
route_map_init_vty (void)
{
+ route_map_init_dep_hashes();
+
/* Install route map top node. */
install_node (&rmap_node, route_map_config_write);
diff --git a/lib/routemap.h b/lib/routemap.h
index ba64553f3..49191b17e 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -66,7 +66,19 @@ typedef enum
RMAP_EVENT_MATCH_DELETED,
RMAP_EVENT_MATCH_REPLACED,
RMAP_EVENT_INDEX_ADDED,
- RMAP_EVENT_INDEX_DELETED
+ RMAP_EVENT_INDEX_DELETED,
+ RMAP_EVENT_CALL_ADDED, /* call to another routemap added */
+ RMAP_EVENT_CALL_DELETED,
+ RMAP_EVENT_PLIST_ADDED,
+ RMAP_EVENT_PLIST_DELETED,
+ RMAP_EVENT_CLIST_ADDED,
+ RMAP_EVENT_CLIST_DELETED,
+ RMAP_EVENT_ECLIST_ADDED,
+ RMAP_EVENT_ECLIST_DELETED,
+ RMAP_EVENT_ASLIST_ADDED,
+ RMAP_EVENT_ASLIST_DELETED,
+ RMAP_EVENT_FILTER_ADDED,
+ RMAP_EVENT_FILTER_DELETED,
} route_map_event_t;
/* Depth limit in RMAP recursion using RMAP_CALL. */
@@ -149,6 +161,10 @@ struct route_map
/* Make linked list. */
struct route_map *next;
struct route_map *prev;
+
+ /* Maintain update info */
+ int to_be_processed; /* True if modification isn't acted on yet */
+ int deleted; /* If 1, then this node will be deleted */
};
/* Prototypes. */
@@ -166,6 +182,9 @@ extern int route_map_delete_match (struct route_map_index *index,
const char *match_name,
const char *match_arg);
+extern const char *route_map_get_match_arg (struct route_map_index *index,
+ const char *match_name);
+
/* Add route-map set statement to the route map. */
extern int route_map_add_set (struct route_map_index *index,
const char *set_name,
@@ -193,6 +212,16 @@ extern route_map_result_t route_map_apply (struct route_map *map,
extern void route_map_add_hook (void (*func) (const char *));
extern void route_map_delete_hook (void (*func) (const char *));
-extern void route_map_event_hook (void (*func) (route_map_event_t, const char *));
+extern void route_map_event_hook (void (*func) (route_map_event_t,
+ const char *));
+extern int route_map_mark_updated (const char *name, int deleted);
+extern int route_map_clear_updated (struct route_map *rmap);
+extern void route_map_walk_update_list (void *arg,
+ int (*update_fn) (void *arg,
+ char *name));
+extern void route_map_upd8_dependency (route_map_event_t type, const char *arg,
+ const char *rmap_name);
+extern void route_map_notify_dependencies (const char *affected_name,
+ route_map_event_t event);
#endif /* _ZEBRA_ROUTEMAP_H */
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 03f9cc144..470e8a1a2 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -37,7 +37,7 @@ zebra_SOURCES = \
$(othersrc) zebra_ptm.c zebra_rnh.c
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
- zebra_vty.c zebra_ptm.c \
+ zebra_vty.c zebra_ptm.c zebra_routemap.c \
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c
noinst_HEADERS = \
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index dac1166cb..af04adaa4 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -930,9 +930,8 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
rib_table_info_t *info = rn->table->info;
struct interface *ifp;
route_map_result_t ret = RMAP_MATCH;
- extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1];
- struct route_map *rmap;
int family;
+ char buf[INET6_ADDRSTRLEN+1];
family = 0;
switch (nexthop->type)
@@ -1021,18 +1020,17 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
if (!family)
family = info->afi;
- rmap = 0;
- if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX &&
- proto_rm[family][rib->type])
- rmap = route_map_lookup_by_name (proto_rm[family][rib->type]);
- if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
- rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
- if (rmap) {
- ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, nexthop);
- }
-
+ ret = zebra_route_map_check(family, rib->type, &rn->p, nexthop);
if (ret == RMAP_DENYMATCH)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf));
+ zlog_debug("%s: Filtering out %s with NH out %s due to route map",
+ __FUNCTION__, buf, nexthop->ifname);
+ }
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 7b4472488..045ee6a69 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -31,11 +31,19 @@
#include "nexthop.h"
#include "zebra/zserv.h"
+#include "zebra/debug.h"
+
+static u_int32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER;
+static struct thread *zebra_t_rmap_update = NULL;
+char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
+
+extern struct zebra_t zebrad;
/* Add zebra route map rule */
static int
zebra_route_match_add(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
@@ -52,15 +60,35 @@ zebra_route_match_add(struct vty *vty, struct route_map_index *index,
return CMD_WARNING;
}
}
+
+ if (type != RMAP_EVENT_MATCH_ADDED)
+ {
+ route_map_upd8_dependency (type, arg, index->map->name);
+ }
return CMD_SUCCESS;
}
/* Delete zebra route map rule. */
static int
zebra_route_match_delete (struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
+ char *dep_name = (char *)arg;
+ const char *tmpstr;
+ char *rmap_name = NULL;
+
+ if (type != RMAP_EVENT_MATCH_DELETED)
+ {
+ /* ignore the mundane, the types without any dependency */
+ if (arg == NULL)
+ {
+ if ((tmpstr = route_map_get_match_arg(index, command)) != NULL)
+ dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
+ }
+ rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
+ }
ret = route_map_delete_match (index, command, arg);
if (ret)
@@ -75,6 +103,15 @@ zebra_route_match_delete (struct vty *vty, struct route_map_index *index,
return CMD_WARNING;
}
}
+
+ if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
+ route_map_upd8_dependency(type, dep_name, rmap_name);
+
+ if (arg == NULL && dep_name)
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ if (rmap_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+
return CMD_SUCCESS;
}
@@ -181,7 +218,8 @@ DEFUN (match_interface,
"match first hop interface of route\n"
"Interface name\n")
{
- return zebra_route_match_add (vty, vty->index, "interface", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "interface", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_interface,
@@ -192,9 +230,9 @@ DEFUN (no_match_interface,
"Match first hop interface of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "interface", NULL);
+ return zebra_route_match_delete (vty, vty->index, "interface", NULL, RMAP_EVENT_MATCH_DELETED);
- return zebra_route_match_delete (vty, vty->index, "interface", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "interface", argv[0], RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_interface,
@@ -215,7 +253,7 @@ DEFUN (match_ip_next_hop,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0], RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_next_hop,
@@ -227,9 +265,11 @@ DEFUN (no_match_ip_next_hop,
"Match next-hop address of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+ return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_next_hop,
@@ -252,7 +292,8 @@ DEFUN (match_ip_next_hop_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_next_hop_prefix_list,
@@ -265,9 +306,13 @@ DEFUN (no_match_ip_next_hop_prefix_list,
"Match entries of prefix-lists\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-list", NULL,
+ RMAP_EVENT_PLIST_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-list", argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_next_hop_prefix_list,
@@ -291,7 +336,8 @@ DEFUN (match_ip_address,
"IP Access-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip address", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_address,
@@ -303,9 +349,11 @@ DEFUN (no_match_ip_address,
"Match address of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip address", NULL);
+ return zebra_route_match_delete (vty, vty->index, "ip address", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip address", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_address,
@@ -328,7 +376,8 @@ DEFUN (match_ip_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_address_prefix_list,
@@ -341,9 +390,13 @@ DEFUN (no_match_ip_address_prefix_list,
"Match entries of prefix-lists\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-list", NULL,
+ RMAP_EVENT_PLIST_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-list", argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_address_prefix_list,
@@ -404,6 +457,123 @@ ALIAS (no_set_src,
"src address for route\n"
"src address\n")
+DEFUN (zebra_route_map_timer,
+ zebra_route_map_timer_cmd,
+ "zebra route-map delay-timer <0-600>",
+ "Time to wait before route-map updates are\n"
+ "processed. 0 means disable event driven\n"
+ "route-map updates. Set this to a larger\n"
+ "value than protocol route-map delay timer\n"
+ "to avoid unnecessary churn in routing tables\n")
+{
+ u_int32_t rmap_delay_timer;
+
+ VTY_GET_INTEGER_RANGE ("delay-timer", rmap_delay_timer, argv[0], 0, 600);
+ zebra_route_map_set_delay_timer(rmap_delay_timer);
+
+ return (CMD_SUCCESS);
+}
+
+DEFUN (no_zebra_route_map_timer,
+ no_zebra_route_map_timer_cmd,
+ "no zebra route-map delay-timer",
+ NO_STR
+ "Reset delay-timer to default value, 30 secs\n")
+{
+ zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER);
+
+ return (CMD_SUCCESS);
+}
+
+DEFUN (ip_protocol,
+ ip_protocol_cmd,
+ "ip protocol PROTO route-map ROUTE-MAP",
+ NO_STR
+ "Apply route map to PROTO\n"
+ "Protocol name\n"
+ "Route map name\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (proto_rm[AFI_IP][i])
+ {
+ if (strcmp(proto_rm[AFI_IP][i], argv[1]) == 0)
+ return CMD_SUCCESS;
+
+ XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
+ }
+ proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
+ rib_update();
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_protocol,
+ no_ip_protocol_cmd,
+ "no ip protocol PROTO",
+ NO_STR
+ "Remove route map from PROTO\n"
+ "Protocol name\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!proto_rm[AFI_IP][i])
+ return CMD_SUCCESS;
+
+ XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
+ proto_rm[AFI_IP][i] = NULL;
+ rib_update();
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_protocol,
+ show_ip_protocol_cmd,
+ "show ip protocol",
+ SHOW_STR
+ IP_STR
+ "IP protocol filtering status\n")
+{
+ int i;
+
+ vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
+ vty_out(vty, "------------------------%s", VTY_NEWLINE);
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
+ proto_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
+ }
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", "any", proto_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
/* `match ip next-hop IP_ACCESS_LIST' */
@@ -666,12 +836,129 @@ static struct route_map_rule_cmd route_set_src_cmd =
route_set_src_free,
};
+static int
+zebra_route_map_update_timer (struct thread *thread)
+{
+ zebra_t_rmap_update = NULL;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("Event driven route-map update triggered");
+
+ rib_update();
+}
+
+void
+zebra_route_map_set_delay_timer(u_int32_t value)
+{
+ zebra_rmap_update_timer = value;
+ if (!value && zebra_t_rmap_update)
+ {
+ /* Event driven route map updates is being disabled */
+ /* But there's a pending timer. Fire it off now */
+ thread_cancel(zebra_t_rmap_update);
+ zebra_route_map_update_timer(zebra_t_rmap_update);
+ }
+}
+
+void
+zebra_route_map_write_delay_timer (struct vty *vty)
+{
+ if (vty && (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER))
+ vty_out (vty, "zebra route-map delay-timer %d%s", zebra_rmap_update_timer,
+ VTY_NEWLINE);
+ return;
+}
+
+route_map_result_t
+zebra_route_map_check (int family, int rib_type, struct prefix *p,
+ struct nexthop *nexthop)
+{
+ struct route_map *rmap = NULL;
+ route_map_result_t ret = RMAP_MATCH;
+
+ if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX)
+ rmap = route_map_lookup_by_name (proto_rm[family][rib_type]);
+ if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
+ rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
+ if (rmap) {
+ ret = route_map_apply(rmap, p, RMAP_ZEBRA, nexthop);
+ }
+
+ return (ret);
+}
+
+static void
+zebra_route_map_mark_update (char *rmap_name)
+{
+ /* rmap_update_timer of 0 means don't do route updates */
+ if (zebra_rmap_update_timer && !zebra_t_rmap_update)
+ zebra_t_rmap_update =
+ thread_add_timer(zebrad.master, zebra_route_map_update_timer, NULL,
+ zebra_rmap_update_timer);
+}
+
+static void
+zebra_route_map_add (const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
+}
+
+static void
+zebra_route_map_delete (const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
+}
+
+static void
+zebra_route_map_event (route_map_event_t event, const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
+}
+
+/* ip protocol configuration write function */
+static int config_write_protocol(struct vty *vty)
+{
+ int i;
+
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "ip protocol %s route-map %s%s", zebra_route_string(i),
+ proto_rm[AFI_IP][i], VTY_NEWLINE);
+ }
+ if (proto_rm[AFI_IP][ZEBRA_ROUTE_MAX])
+ vty_out (vty, "ip protocol %s route-map %s%s", "any",
+ proto_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
+
+ if (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
+ vty_out (vty, "zebra route-map delay-timer %d%s", zebra_rmap_update_timer,
+ VTY_NEWLINE);
+ return 1;
+}
+/* table node for protocol filtering */
+static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
+
void
zebra_route_map_init ()
{
+ install_node (&protocol_node, config_write_protocol);
+ install_element (CONFIG_NODE, &ip_protocol_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_cmd);
+ install_element (VIEW_NODE, &show_ip_protocol_cmd);
+ install_element (ENABLE_NODE, &show_ip_protocol_cmd);
+ install_element (CONFIG_NODE, &zebra_route_map_timer_cmd);
+ install_element (CONFIG_NODE, &no_zebra_route_map_timer_cmd);
+
route_map_init ();
route_map_init_vty ();
+ route_map_add_hook (zebra_route_map_add);
+ route_map_delete_hook (zebra_route_map_delete);
+ route_map_event_hook (zebra_route_map_event);
+
route_map_install_match (&route_match_interface_cmd);
route_map_install_match (&route_match_ip_next_hop_cmd);
route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 72095706e..c8e0d1f6f 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -477,59 +477,6 @@ DEFUN (no_ip_route_mask_flags_distance2,
return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]);
}
-char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
-
-DEFUN (ip_protocol,
- ip_protocol_cmd,
- "ip protocol PROTO route-map ROUTE-MAP",
- NO_STR
- "Apply route map to PROTO\n"
- "Protocol name\n"
- "Route map name\n")
-{
- int i;
-
- if (strcasecmp(argv[0], "any") == 0)
- i = ZEBRA_ROUTE_MAX;
- else
- i = proto_name2num(argv[0]);
- if (i < 0)
- {
- vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (proto_rm[AFI_IP][i])
- XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
- proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_ip_protocol,
- no_ip_protocol_cmd,
- "no ip protocol PROTO",
- NO_STR
- "Remove route map from PROTO\n"
- "Protocol name\n")
-{
- int i;
-
- if (strcasecmp(argv[0], "any") == 0)
- i = ZEBRA_ROUTE_MAX;
- else
- i = proto_name2num(argv[0]);
- if (i < 0)
- {
- vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (proto_rm[AFI_IP][i])
- XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
- proto_rm[AFI_IP][i] = NULL;
- return CMD_SUCCESS;
-}
-
/* New RIB. Detailed information for IPv4 route. */
static void
vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
@@ -1270,35 +1217,6 @@ static_config_ipv4 (struct vty *vty)
return write;
}
-DEFUN (show_ip_protocol,
- show_ip_protocol_cmd,
- "show ip protocol",
- SHOW_STR
- IP_STR
- "IP protocol filtering status\n")
-{
- int i;
-
- vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
- vty_out(vty, "------------------------%s", VTY_NEWLINE);
- for (i=0;i<ZEBRA_ROUTE_MAX;i++)
- {
- if (proto_rm[AFI_IP][i])
- vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
- proto_rm[AFI_IP][i],
- VTY_NEWLINE);
- else
- vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
- }
- if (proto_rm[AFI_IP][i])
- vty_out (vty, "%-10s : %-10s%s", "any", proto_rm[AFI_IP][i],
- VTY_NEWLINE);
- else
- vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
/*
* Show IP mroute command to dump the BGP Multicast
* routing table
@@ -2174,27 +2092,6 @@ zebra_ip_config (struct vty *vty)
return write;
}
-/* ip protocol configuration write function */
-static int config_write_protocol(struct vty *vty)
-{
- int i;
-
- for (i=0;i<ZEBRA_ROUTE_MAX;i++)
- {
- if (proto_rm[AFI_IP][i])
- vty_out (vty, "ip protocol %s route-map %s%s", zebra_route_string(i),
- proto_rm[AFI_IP][i], VTY_NEWLINE);
- }
- if (proto_rm[AFI_IP][ZEBRA_ROUTE_MAX])
- vty_out (vty, "ip protocol %s route-map %s%s", "any",
- proto_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
-
- return 1;
-}
-
-/* table node for protocol filtering */
-static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
-
/* IP node for static routes. */
static struct cmd_node ip_node = { IP_NODE, "", 1 };
@@ -2203,12 +2100,7 @@ void
zebra_vty_init (void)
{
install_node (&ip_node, zebra_ip_config);
- install_node (&protocol_node, config_write_protocol);
- install_element (CONFIG_NODE, &ip_protocol_cmd);
- install_element (CONFIG_NODE, &no_ip_protocol_cmd);
- install_element (VIEW_NODE, &show_ip_protocol_cmd);
- install_element (ENABLE_NODE, &show_ip_protocol_cmd);
install_element (CONFIG_NODE, &ip_route_cmd);
install_element (CONFIG_NODE, &ip_route_flags_cmd);
install_element (CONFIG_NODE, &ip_route_flags2_cmd);
diff --git a/zebra/zserv.h b/zebra/zserv.h
index edcfee0d4..58fcf31ad 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -25,6 +25,7 @@
#include "rib.h"
#include "if.h"
#include "workqueue.h"
+#include "routemap.h"
/* Default port information. */
#define ZEBRA_VTY_PORT 2601
@@ -32,6 +33,8 @@
/* Default configuration filename. */
#define DEFAULT_CONFIG_FILE "zebra.conf"
+#define ZEBRA_RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
+
/* Client structure. */
struct zserv
{
@@ -119,4 +122,9 @@ extern pid_t pid;
extern void zserv_create_header(struct stream *s, uint16_t cmd);
extern int zebra_server_send_message(struct zserv *client);
+extern void zebra_route_map_write_delay_timer(struct vty *);
+extern route_map_result_t zebra_route_map_check (int family, int rib_type,
+ struct prefix *p,
+ struct nexthop *nexthop);
+
#endif /* _ZEBRA_ZEBRA_H */