diff options
-rw-r--r-- | bgpd/bgp_clist.c | 14 | ||||
-rw-r--r-- | bgpd/bgp_filter.c | 29 | ||||
-rw-r--r-- | bgpd/bgp_filter.h | 4 | ||||
-rw-r--r-- | bgpd/bgp_main.c | 4 | ||||
-rw-r--r-- | bgpd/bgp_routemap.c | 639 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 53 | ||||
-rw-r--r-- | bgpd/bgp_zebra.c | 19 | ||||
-rw-r--r-- | bgpd/bgp_zebra.h | 1 | ||||
-rw-r--r-- | bgpd/bgpd.c | 76 | ||||
-rw-r--r-- | bgpd/bgpd.h | 8 | ||||
-rw-r--r-- | lib/filter.c | 5 | ||||
-rw-r--r-- | lib/memtypes.c | 1 | ||||
-rw-r--r-- | lib/plist.c | 14 | ||||
-rw-r--r-- | lib/routemap.c | 547 | ||||
-rw-r--r-- | lib/routemap.h | 33 | ||||
-rw-r--r-- | zebra/Makefile.am | 2 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 24 | ||||
-rw-r--r-- | zebra/zebra_routemap.c | 321 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 108 | ||||
-rw-r--r-- | zebra/zserv.h | 8 |
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 */ |