]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: bgpd-event-driven-route-map-updates.patch
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 00:40:45 +0000 (17:40 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 00:40:45 +0000 (17:40 -0700)
BGP: Reprocess the trigger points when an attached route map changes

Currently, modifications to route maps do not affect already processed
routes; they only affect new route updates. This patch addresses this
limitation.

Signed-off-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
20 files changed:
bgpd/bgp_clist.c
bgpd/bgp_filter.c
bgpd/bgp_filter.h
bgpd/bgp_main.c
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
lib/filter.c
lib/memtypes.c
lib/plist.c
lib/routemap.c
lib/routemap.h
zebra/Makefile.am
zebra/zebra_rib.c
zebra/zebra_routemap.c
zebra/zebra_vty.c
zebra/zserv.h

index b91ab81fafde63814aa8e43f54f5135ea1c7bff5..80564df4b7d7d632fda2e35ed35cffb30d72ba96 100644 (file)
@@ -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;
 }
index fd8ece6591cbcb500956b32a811fcf48b37b8069..fa0889cdbe60759cc7c56561df885794b3dab03d 100644 (file)
@@ -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;
 }
index c1da90412c77270f73bb6360b03dd3ae9d46e98d..80feb1ccb9aee6cc6247f986766d881d3b88235e 100644 (file)
@@ -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 */
index 584bfa761df94cc1efb3d367b277027d77dbd084..ae73afc0a2da2dabfb3c4c7459bd8d6b29cd066a 100644 (file)
@@ -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 ();
index ab543f910436b1f97414ef9a36f7a311a6fe9110..3204daba517ec5b3be0afa51076730c2b58111fe 100644 (file)
@@ -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();
+
+}
index d3b21124a797c3e2136986ffe652211418daaf81..10bdc150705533bbf90a1c6b5c725a8990ac4064 100644 (file)
@@ -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);
index 58990c50304f25a4f5e7899d4bf07ae2e4712f8a..b3d1109114cb1e00634b85d62e9b64f6268829e0 100644 (file)
@@ -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, 
index 34e121670698a68949c42a7c6f8b3d82a6e52acf..eb049a47edb093898ed38e02679220ffa0d1fb92 100644 (file)
@@ -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);
index 347c4bc5f5707b3fbe490b8f7a80b5bb969f05d3..4332722efef3d5d74554204e9f4c0f6fb7458cc2 100644 (file)
@@ -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 ();
index 7cd43cf5a9b7b22f5e9f9718d91552ac00e6c981..4faf452b2bd6b0c879cce40837451c56e6dc1ff9 100644 (file)
@@ -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 */
index 96605c7d5c6ff505ea823b53154e9a5017d0b379..ae50e6cbe0ed2f9858e38864fa0d06e9c911c4b1 100644 (file)
@@ -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);
index f418b3d0ade2071e574b8f71eac2b64b423a9fc2..00ed0a48ee58524a443c556a3bc3a10b4e71ea2e 100644 (file)
@@ -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"                     },
index 7416ebd2f9d895dd36a57329c185c4e15bb6664a..f5950c331f1d3c323717add12dfc3710bd8fa05d 100644 (file)
@@ -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;
 }
 
index 1e1510ebd497b019cbc7000aeb0acf3623445229..b884fed2a9930e988dad5dbc5fda360d8b6ff2fd 100644 (file)
@@ -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);
 
index ba64553f3cf8028f1307f82b3535ae1297c56741..49191b17e62cbe9833190c3574cfbd642bcc36ec 100644 (file)
@@ -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 */
index 03f9cc144f14c77a811800c3d985adccac131d50..470e8a1a282b275ac5a657dfad458353d1643a26 100644 (file)
@@ -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 = \
index dac1166cbc7e344ac65acc601efef1921ce1420a..af04adaa49fc8cf9970f4180c40c0785d4cc1465 100644 (file)
@@ -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);
 }
 
index 7b4472488d3f7f030ed38aa3b3c23def150a6fce..045ee6a697dc39f64f09faeda04257cb89c5df84 100644 (file)
 #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);
index 72095706eeb15e3724a211bde27d77bb426c45f3..c8e0d1f6f4eb3a8f433e7328cff1a2f6793f3b3f 100644 (file)
@@ -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);
index edcfee0d4fa2ee15194c5226aec1c4d3b7eb72cd..58fcf31ad279953fc3ee62be179afe55d2ed5122 100644 (file)
@@ -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 */