]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: bgpd-table-map.patch
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 00:40:34 +0000 (17:40 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 00:40:34 +0000 (17:40 -0700)
COMMAND:

table-map <route-map-name>

DESCRIPTION:

This feature is used to apply a route-map on route updates from BGP to Zebra.
All the applicable match operations are allowed, such as match on prefix,
next-hop, communities, etc. Set operations for this attach-point are limited
to metric and next-hop only. Any operation of this feature does not affect
BGPs internal RIB.

Supported for ipv4 and ipv6 address families. It works on multi-paths as well,
however, metric setting is based on the best-path only.

IMPLEMENTATION NOTES:

The route-map application at this point is not supposed to modify any of BGP
route's attributes (anything in bgp_info for that matter). To achieve that,
creating a copy of the bgp_attr was inevitable. Implementation tries to keep
the memory footprint low, code comments do point out the rationale behind a
few choices made.

bgp_zebra_announce() was already a big routine, adding this feature would
extend it further. Patch has created a few smaller routines/macros whereever
possible to keep the size of the routine in check without compromising on the
readability of the code/flow inside this routine.

For updating a partially filtered route (with its nexthops), BGP to Zebra
replacement semantic of the next-hops serves the purpose well. However, with
this patch there could be some redundant withdraws each time BGP announces a
route thats (all the nexthops) gets denied by the route-map application.
Handling of this case could be optimized by keeping state with the prefix and
the nexthops in BGP. The patch doesn't optimizing that case, as even with the
redundant withdraws the total number of updates to zebra are still be capped
by the total number of routes in the table.

Signed-off-by: Vipin Kumar <vipin@cumulusnetworks.com>
Reviewed-by: Pradosh Mohapatra <pmohapat@cumulusnetworks.com>
12 files changed:
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_mpath.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
doc/bgpd.texi

index fcf82551cc9a97ec1d676cc3ab002810b9281837..4e38bca20090ac3877a1535d03372a727562164f 100644 (file)
@@ -150,7 +150,6 @@ cluster_free (struct cluster_list *cluster)
   XFREE (MTYPE_CLUSTER, cluster);
 }
 
-#if 0
 static struct cluster_list *
 cluster_dup (struct cluster_list *cluster)
 {
@@ -169,7 +168,6 @@ cluster_dup (struct cluster_list *cluster)
   
   return new;
 }
-#endif
 
 static struct cluster_list *
 cluster_intern (struct cluster_list *cluster)
@@ -219,6 +217,23 @@ transit_free (struct transit *transit)
   XFREE (MTYPE_TRANSIT, transit);
 }
 
+static struct transit *
+transit_dup (struct transit *transit)
+{
+  struct transit *new;
+
+  new = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
+  new->length = transit->length;
+  if (new->length)
+    {
+      new->val = XMALLOC (MTYPE_TRANSIT_VAL, transit->length);
+      memcpy (new->val, transit->val, transit->length);
+    }
+  else
+    new->val = NULL;
+
+  return new;
+}
 
 static void *
 transit_hash_alloc (void *p)
@@ -343,6 +358,46 @@ bgp_attr_dup (struct attr *new, struct attr *orig)
     }
 }
 
+void
+bgp_attr_deep_dup (struct attr *new, struct attr *orig)
+{
+  if (orig->aspath)
+    new->aspath = aspath_dup(orig->aspath);
+
+  if (orig->community)
+    new->community = community_dup(orig->community);
+
+  if (orig->extra)
+    {
+      if (orig->extra->ecommunity)
+        new->extra->ecommunity = ecommunity_dup(orig->extra->ecommunity);
+      if (orig->extra->cluster)
+        new->extra->cluster = cluster_dup(orig->extra->cluster);
+      if (orig->extra->transit)
+        new->extra->transit = transit_dup(orig->extra->transit);
+    }
+}
+
+void
+bgp_attr_deep_free (struct attr *attr)
+{
+  if (attr->aspath)
+    aspath_free(attr->aspath);
+
+  if (attr->community)
+    community_free(attr->community);
+
+  if (attr->extra)
+    {
+      if (attr->extra->ecommunity)
+        ecommunity_free(&attr->extra->ecommunity);
+      if (attr->extra->cluster)
+        cluster_free(attr->extra->cluster);
+      if (attr->extra->transit)
+        transit_free(attr->extra->transit);
+    }
+}
+
 unsigned long int
 attr_count (void)
 {
index 7edf684021245af9755602629958c19f285133f6..2d796b5b70083b571c17a28409fda577454b85eb 100644 (file)
@@ -155,6 +155,8 @@ extern int bgp_attr_check (struct peer *, struct attr *);
 extern struct attr_extra *bgp_attr_extra_get (struct attr *);
 extern void bgp_attr_extra_free (struct attr *);
 extern void bgp_attr_dup (struct attr *, struct attr *);
+extern void bgp_attr_deep_dup (struct attr *, struct attr *);
+extern void bgp_attr_deep_free (struct attr *);
 extern struct attr *bgp_attr_intern (struct attr *attr);
 extern void bgp_attr_unintern_sub (struct attr *);
 extern void bgp_attr_unintern (struct attr **);
index 0645e6c2763575ee102bbd8694c3ec89e7af8c3f..0c8137041af6d381d01c1e2f8abf08720f4a06ab 100644 (file)
@@ -24,6 +24,9 @@
 #ifndef _QUAGGA_BGP_MPATH_H
 #define _QUAGGA_BGP_MPATH_H
 
+/* Limit on number of configured maxpaths */
+#define BGP_MAXIMUM_MAXPATHS 255
+
 /* BGP default maximum-paths */
 #define BGP_DEFAULT_MAXPATHS 1
 
index b554e195e24c5364b7a34b8384587f125a95f47a..134c7c07dcc3311281bc0f143c175e378f343665 100644 (file)
@@ -1598,7 +1598,7 @@ bgp_process_main (struct work_queue *wq, void *data)
         {
           if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) ||
              CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG))
-            bgp_zebra_announce (p, old_select, bgp, safi);
+            bgp_zebra_announce (p, old_select, bgp, afi, safi);
           
          UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
           UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
@@ -1629,7 +1629,7 @@ bgp_process_main (struct work_queue *wq, void *data)
       if (new_select 
          && new_select->type == ZEBRA_ROUTE_BGP 
          && new_select->sub_type == BGP_ROUTE_NORMAL)
-       bgp_zebra_announce (p, new_select, bgp, safi);
+       bgp_zebra_announce (p, new_select, bgp, afi, safi);
       else
        {
          /* Withdraw the route from the kernel. */
@@ -4035,6 +4035,84 @@ bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str,
   return CMD_SUCCESS;
 }
 
+static int
+bgp_table_map_set (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
+                   const char *rmap_name)
+{
+  struct bgp_rmap *rmap;
+
+  rmap = &bgp->table_map[afi][safi];
+  if (rmap_name)
+    {
+      if (rmap->name)
+        free (rmap->name);
+      rmap->name = strdup (rmap_name);
+      rmap->map = route_map_lookup_by_name (rmap_name);
+    }
+  else
+    {
+      if (rmap->name)
+        free (rmap->name);
+      rmap->name = NULL;
+      rmap->map = NULL;
+    }
+
+  bgp_zebra_announce_table(bgp, afi, safi);
+
+  return CMD_SUCCESS;
+}
+
+static int
+bgp_table_map_unset (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
+                     const char *rmap_name)
+{
+  struct bgp_rmap *rmap;
+
+  rmap = &bgp->table_map[afi][safi];
+  if (rmap->name)
+    free (rmap->name);
+  rmap->name = NULL;
+  rmap->map = NULL;
+
+  bgp_zebra_announce_table(bgp, afi, safi);
+
+  return CMD_SUCCESS;
+}
+
+int
+bgp_config_write_table_map (struct vty *vty, struct bgp *bgp, afi_t afi,
+                          safi_t safi, int *write)
+{
+  if (bgp->table_map[afi][safi].name)
+    {
+      bgp_config_write_family_header (vty, afi, safi, write);
+      vty_out (vty, " table-map %s%s",
+              bgp->table_map[afi][safi].name, VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+
+DEFUN (bgp_table_map,
+       bgp_table_map_cmd,
+       "table-map WORD",
+       "BGP table to RIB route download filter\n"
+       "Name of the route map\n")
+{
+  return bgp_table_map_set (vty, vty->index,
+             bgp_node_afi (vty), bgp_node_safi (vty), argv[0]);
+}
+DEFUN (no_bgp_table_map,
+       no_bgp_table_map_cmd,
+       "no table-map WORD",
+       "BGP table to RIB route download filter\n"
+       "Name of the route map\n")
+{
+  return bgp_table_map_unset (vty, vty->index,
+             bgp_node_afi (vty), bgp_node_safi (vty), argv[0]);
+}
+
 DEFUN (bgp_network,
        bgp_network_cmd,
        "network A.B.C.D/M",
@@ -12671,6 +12749,7 @@ bgp_route_init (void)
   bgp_distance_table = bgp_table_init (AFI_IP, SAFI_UNICAST);
 
   /* IPv4 BGP commands. */
+  install_element (BGP_NODE, &bgp_table_map_cmd);
   install_element (BGP_NODE, &bgp_network_cmd);
   install_element (BGP_NODE, &bgp_network_mask_cmd);
   install_element (BGP_NODE, &bgp_network_mask_natural_cmd);
@@ -12680,6 +12759,7 @@ bgp_route_init (void)
   install_element (BGP_NODE, &bgp_network_backdoor_cmd);
   install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd);
   install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd);
+  install_element (BGP_NODE, &no_bgp_table_map_cmd);
   install_element (BGP_NODE, &no_bgp_network_cmd);
   install_element (BGP_NODE, &no_bgp_network_mask_cmd);
   install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd);
@@ -12712,12 +12792,14 @@ bgp_route_init (void)
   install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd);
 
   /* IPv4 unicast configuration.  */
+  install_element (BGP_IPV4_NODE, &bgp_table_map_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_table_map_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd);
@@ -12747,12 +12829,14 @@ bgp_route_init (void)
   install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd);
 
   /* IPv4 multicast configuration.  */
+  install_element (BGP_IPV4M_NODE, &bgp_table_map_cmd);
   install_element (BGP_IPV4M_NODE, &bgp_network_cmd);
   install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd);
   install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd);
   install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd);
   install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd);
   install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_table_map_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd);
@@ -13026,8 +13110,10 @@ bgp_route_init (void)
   install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd);
 
   /* New config IPv6 BGP commands.  */
+  install_element (BGP_IPV6_NODE, &bgp_table_map_cmd);
   install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
   install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
+  install_element (BGP_IPV6_NODE, &no_bgp_table_map_cmd);
   install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
   install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd);
 
index b50a0bab3ad883b3e0ed6cd1f68b662b0b039fcb..7f31a38204d9c61036ec81aa25c3ef519984f85f 100644 (file)
@@ -237,6 +237,8 @@ extern int bgp_withdraw (struct peer *, struct prefix *, struct attr *,
 
 /* for bgp_nexthop and bgp_damp */
 extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t);
+extern int bgp_config_write_table_map (struct vty *, struct bgp *, afi_t, safi_t,
+                                       int *);
 extern int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *);
 extern int bgp_config_write_distance (struct vty *, struct bgp *);
 
index 24f3af767a98a3096990c069280230a5e48a0587..a2c740078c6ca9ae32214a3a3cfd944ce415565d 100644 (file)
@@ -45,6 +45,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_attr.h"
 #include "bgpd/bgp_aspath.h"
 #include "bgpd/bgp_route.h"
+#include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_regex.h"
 #include "bgpd/bgp_community.h"
 #include "bgpd/bgp_clist.h"
@@ -52,6 +53,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_ecommunity.h"
 #include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_debug.h"
 
 /* Memo of route-map commands.
 
@@ -2409,6 +2411,23 @@ bgp_route_map_update (const char *unused)
        }
     }
 
+  /* For table route-map updates. */
+  for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+    {
+      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;
+          }
+    }
+
   /* For network route-map updates. */
   for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
     {
@@ -2443,6 +2462,32 @@ bgp_route_map_update (const char *unused)
     }
 }
 
+static void
+bgp_route_map_add (const char *unused)
+{
+  if (BGP_DEBUG (events, EVENTS))
+        zlog_debug ("received route-map add");
+
+  bgp_route_map_update(unused);
+}
+static void
+bgp_route_map_delete (const char *unused)
+{
+  if (BGP_DEBUG (events, EVENTS))
+        zlog_debug ("received route-map delete");
+
+  bgp_route_map_update(unused);
+}
+static void
+bgp_route_map_event (route_map_event_t event, const char *unused)
+{
+  if (BGP_DEBUG (events, EVENTS))
+        zlog_debug ("received route-map event");
+
+  bgp_route_map_update(unused);
+}
+
+
 DEFUN (match_peer,
        match_peer_cmd,
        "match peer (A.B.C.D|X:X::X:X)",
@@ -3897,8 +3942,9 @@ bgp_route_map_init (void)
 {
   route_map_init ();
   route_map_init_vty ();
-  route_map_add_hook (bgp_route_map_update);
-  route_map_delete_hook (bgp_route_map_update);
+  route_map_add_hook (bgp_route_map_add);
+  route_map_delete_hook (bgp_route_map_delete);
+  route_map_event_hook (bgp_route_map_event);
 
   route_map_install_match (&route_match_peer_cmd);
   route_map_install_match (&route_match_ip_address_cmd);
index 93797aa089ee95a3c2e72477194d18480a5d9849..fc93c812129e306734de41ea32bf93b1f04f6966 100644 (file)
@@ -672,7 +672,8 @@ bgp_maxpaths_config_vty (struct vty *vty, int peer_type, char *mpaths,
 
   if (set)
     {
-      VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, mpaths, 1, 255);
+      VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, mpaths, 1,
+                             BGP_MAXIMUM_MAXPATHS);
       ret = bgp_maximum_paths_set (bgp, afi, safi, peer_type, maxpaths,
                                   options);
     }
index 6ba4f4bf2b40c31f42baa261a2eb378e3cc2b987..bea28bee55123340efd6c4234c6b6d48318c0280 100644 (file)
@@ -48,6 +48,43 @@ struct in_addr router_id_zebra;
 struct stream *bgp_nexthop_buf = NULL;
 struct stream *bgp_ifindices_buf = NULL;
 
+/* These array buffers are used in making a copy of the attributes for
+   route-map apply. Arrays are being used here to minimize mallocs and
+   frees for the temporary copy of the attributes.
+   Given the zapi api expects the nexthop buffer to contain pointer to
+   pointers for nexthops, we couldnt have used a single nexthop variable
+   on the stack, hence we had two options:
+     1. maintain a linked-list and free it after zapi_*_route call
+     2. use an array to avoid number of mallocs.
+   Number of supported next-hops are finite, use of arrays should be ok. */
+struct attr attr_cp[BGP_MAXIMUM_MAXPATHS];
+struct attr_extra attr_extra_cp[BGP_MAXIMUM_MAXPATHS];
+int    attr_index = 0;
+
+/* Once per address-family initialization of the attribute array */
+#define BGP_INFO_ATTR_BUF_INIT()\
+do {\
+  memset(attr_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr));\
+  memset(attr_extra_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr_extra));\
+  attr_index = 0;\
+} while (0)
+
+#define BGP_INFO_ATTR_BUF_COPY(info_src, info_dst)\
+do { \
+  *info_dst = *info_src; \
+  assert(attr_index != BGP_MAXIMUM_MAXPATHS);\
+  attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \
+  bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \
+  bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \
+  info_dst->attr = &attr_cp[attr_index]; \
+  attr_index++;\
+} while (0)
+
+#define BGP_INFO_ATTR_BUF_FREE(info) \
+do { \
+  bgp_attr_deep_free(info->attr); \
+} while (0)
+
 /* Router-id update message from zebra. */
 static int
 bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length)
@@ -671,15 +708,72 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
   return ret;
 }
 
+static struct in6_addr *
+bgp_info_to_ipv6_nexthop (struct bgp_info *info)
+{
+  struct in6_addr *nexthop = NULL;
+
+  /* Only global address nexthop exists. */
+  if (info->attr->extra->mp_nexthop_len == 16)
+    nexthop = &info->attr->extra->mp_nexthop_global;
+
+  /* If both global and link-local address present. */
+  if (info->attr->extra->mp_nexthop_len == 32)
+    {
+      /* Workaround for Cisco's nexthop bug.  */
+      if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
+          && info->peer->su_remote->sa.sa_family == AF_INET6)
+        nexthop = &info->peer->su_remote->sin6.sin6_addr;
+      else
+        nexthop = &info->attr->extra->mp_nexthop_local;
+    }
+
+  return nexthop;
+}
+
+static int
+bgp_table_map_apply (struct route_map *map, struct prefix *p,
+                     struct bgp_info *info)
+{
+  if (route_map_apply(map, p, RMAP_BGP, info) != RMAP_DENYMATCH)
+    return 1;
+
+  if (BGP_DEBUG(zebra, ZEBRA))
+    {
+      if (p->family == AF_INET)
+        {
+          char buf[2][INET_ADDRSTRLEN];
+          zlog_debug("Zebra rmap deny: IPv4 route %s/%d nexthop %s",
+                     inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
+                     p->prefixlen,
+                     inet_ntop(AF_INET, &info->attr->nexthop, buf[1],
+                               sizeof(buf[1])));
+        }
+      if (p->family == AF_INET6)
+        {
+          char buf[2][INET6_ADDRSTRLEN];
+          zlog_debug("Zebra rmap deny: IPv6 route %s/%d nexthop %s",
+                     inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
+                     p->prefixlen,
+                     inet_ntop(AF_INET6, bgp_info_to_ipv6_nexthop(info), buf[1],
+                               sizeof(buf[1])));
+        }
+    }
+  return 0;
+}
+
 void
-bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
+bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
+                    afi_t afi, safi_t safi)
 {
   int flags;
   u_char distance;
   struct peer *peer;
   struct bgp_info *mpinfo;
   size_t oldsize, newsize;
-  u_int32_t nhcount;
+  u_int32_t nhcount, metric;
+  struct bgp_info local_info;
+  struct bgp_info *info_cp = &local_info;
 
   if (zclient->sock < 0)
     return;
@@ -706,6 +800,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
     {
       struct zapi_ipv4 api;
       struct in_addr *nexthop;
+      char buf[2][INET_ADDRSTRLEN];
+      int valid_nh_count = 0;
 
       /* resize nexthop buffer size if necessary */
       if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
@@ -720,26 +816,72 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
             }
         }
       stream_reset (bgp_nexthop_buf);
+      nexthop = NULL;
+
+      /* Metric is currently based on the best-path only. */
+      metric = info->attr->med;
+
+      if (bgp->table_map[afi][safi].name)
+        {
+          BGP_INFO_ATTR_BUF_INIT();
+
+          /* Copy info and attributes, so the route-map apply doesn't modify the
+             BGP route info. */
+          BGP_INFO_ATTR_BUF_COPY(info, info_cp);
+          if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+            {
+              metric = info_cp->attr->med;
+              nexthop = &info_cp->attr->nexthop;
+            }
+          BGP_INFO_ATTR_BUF_FREE(info_cp);
+        }
+      else
+        {
+          nexthop = &info->attr->nexthop;
+        }
+
+      if (nexthop)
+        {
+          stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+          valid_nh_count++;
+        }
 
-      api.flags = flags;
-      nexthop = &info->attr->nexthop;
-      stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
       for (mpinfo = bgp_info_mpath_first (info); mpinfo;
-          mpinfo = bgp_info_mpath_next (mpinfo))
-       {
-         nexthop = &mpinfo->attr->nexthop;
-         stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
-       }
+           mpinfo = bgp_info_mpath_next (mpinfo))
+        {
+          nexthop = NULL;
 
+          if (bgp->table_map[afi][safi].name)
+            {
+              /* Copy info and attributes, so the route-map apply doesn't modify the
+                 BGP route info. */
+              BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
+              if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+                nexthop = &info_cp->attr->nexthop;
+              BGP_INFO_ATTR_BUF_FREE(info_cp);
+            }
+          else
+            {
+              nexthop = &mpinfo->attr->nexthop;
+            }
+
+          if (nexthop == NULL)
+            continue;
+
+          stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+          valid_nh_count++;
+        }
+
+      api.flags = flags;
       api.type = ZEBRA_ROUTE_BGP;
       api.message = 0;
       api.safi = safi;
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
-      api.nexthop_num = nhcount;
+      api.nexthop_num = valid_nh_count;
       api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
       api.ifindex_num = 0;
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
-      api.metric = info->attr->med;
+      api.metric = metric;
 
       distance = bgp_distance_apply (p, info, bgp);
 
@@ -750,23 +892,19 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
        }
 
       if (BGP_DEBUG(zebra, ZEBRA))
-       {
-         int i;
-         char buf[2][INET_ADDRSTRLEN];
-         zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u"
-                    " count %d",
-                    inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
-                    p->prefixlen,
-                    inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])),
-                    api.metric, api.nexthop_num);
-         for (i = 1; i < api.nexthop_num; i++)
-           zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s",
-                      i, inet_ntop(AF_INET, api.nexthop[i], buf[1],
-                                   sizeof(buf[1])));
-       }
+        {
+          int i;
+          zlog_debug("Zebra send: IPv4 route %s %s/%d  metric %u"
+                     " count %d", (valid_nh_count ? "add":"delete"),
+                     inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
+                     p->prefixlen, api.metric, api.nexthop_num);
+          for (i = 0; i < api.nexthop_num; i++)
+            zlog_debug("  IPv4 [nexthop %d] %s", i+1,
+                       inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])));
+        }
 
-      zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, 
-                       (struct prefix_ipv4 *) p, &api);
+      zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE,
+                       zclient, (struct prefix_ipv4 *) p, &api);
     }
 #ifdef HAVE_IPV6
 
@@ -777,6 +915,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
       struct in6_addr *nexthop;
       struct zapi_ipv6 api;
       int valid_nh_count = 0;
+           char buf[2][INET6_ADDRSTRLEN];
 
       /* resize nexthop buffer size if necessary */
       if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
@@ -810,94 +949,86 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
       nexthop = NULL;
 
       assert (info->attr->extra);
-      
-      /* Only global address nexthop exists. */
-      if (info->attr->extra->mp_nexthop_len == 16)
-       nexthop = &info->attr->extra->mp_nexthop_global;
-      
-      /* If both global and link-local address present. */
-      if (info->attr->extra->mp_nexthop_len == 32)
-       {
-         /* Workaround for Cisco's nexthop bug.  */
-         if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
-             && peer->su_remote->sa.sa_family == AF_INET6)
-           nexthop = &peer->su_remote->sin6.sin6_addr;
-         else
-           nexthop = &info->attr->extra->mp_nexthop_local;
 
-         if (info->peer->nexthop.ifp)
-           ifindex = info->peer->nexthop.ifp->ifindex;
-       }
+      /* Metric is currently based on the best-path only. */
+      metric = info->attr->med;
 
-      if (nexthop == NULL)
-       return;
+      if (bgp->table_map[afi][safi].name)
+        {
+          BGP_INFO_ATTR_BUF_INIT();
 
-      if (!ifindex)
-       {
-         if (info->peer->ifname)
-           ifindex = if_nametoindex (info->peer->ifname);
-         else if (info->peer->nexthop.ifp)
-           ifindex = info->peer->nexthop.ifp->ifindex;
-       }
-      stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
-      stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
-      valid_nh_count++;
+          /* Copy info and attributes, so the route-map apply doesn't modify the
+             BGP route info. */
+          BGP_INFO_ATTR_BUF_COPY(info, info_cp);
+          if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+            {
+              metric = info_cp->attr->med;
+              nexthop = bgp_info_to_ipv6_nexthop(info_cp);
+            }
+          BGP_INFO_ATTR_BUF_FREE(info_cp);
+        }
+      else
+        {
+           nexthop = bgp_info_to_ipv6_nexthop(info);
+        }
+
+      if (nexthop)
+        {
+          if (info->attr->extra->mp_nexthop_len == 32)
+            if (info->peer->nexthop.ifp)
+              ifindex = info->peer->nexthop.ifp->ifindex;
+
+          if (!ifindex)
+            if (info->peer->ifname)
+              ifindex = if_nametoindex (info->peer->ifname);
+            else if (info->peer->nexthop.ifp)
+              ifindex = info->peer->nexthop.ifp->ifindex;
+
+          stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
+          stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+          valid_nh_count++;
+        }
 
       for (mpinfo = bgp_info_mpath_first (info); mpinfo;
            mpinfo = bgp_info_mpath_next (mpinfo))
-       {
-         ifindex = 0;
-
-          /* Only global address nexthop exists. */
-          if (mpinfo->attr->extra->mp_nexthop_len == 16)
-              nexthop = &mpinfo->attr->extra->mp_nexthop_global;
+        {
+          ifindex = 0;
+          nexthop = NULL;
 
-          /* If both global and link-local address present. */
-         if (mpinfo->attr->extra->mp_nexthop_len == 32)
+          if (bgp->table_map[afi][safi].name)
             {
-              /* Workaround for Cisco's nexthop bug.  */
-              if (IN6_IS_ADDR_UNSPECIFIED (&mpinfo->attr->extra->mp_nexthop_global)
-                  && mpinfo->peer->su_remote->sa.sa_family == AF_INET6)
-                {
-                   nexthop = &mpinfo->peer->su_remote->sin6.sin6_addr;
-                }
-              else
-                {
-                  nexthop = &mpinfo->attr->extra->mp_nexthop_local;
-               }
-
-              if (mpinfo->peer->nexthop.ifp)
-                {
-                  ifindex = mpinfo->peer->nexthop.ifp->ifindex;
-                }
+              /* Copy info and attributes, so the route-map apply doesn't modify the
+                 BGP route info. */
+              BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
+              if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+                nexthop = bgp_info_to_ipv6_nexthop(info_cp);
+              BGP_INFO_ATTR_BUF_FREE(info_cp);
+            }
+          else
+            {
+              nexthop = bgp_info_to_ipv6_nexthop(mpinfo);
             }
 
-         if (nexthop == NULL)
-           {
-             continue;
-           }
+          if (nexthop == NULL)
+            continue;
+
+          if (mpinfo->attr->extra->mp_nexthop_len == 32)
+            if (mpinfo->peer->nexthop.ifp)
+              ifindex = mpinfo->peer->nexthop.ifp->ifindex;
 
           if (!ifindex)
-           {
-             if (mpinfo->peer->ifname)
-               {
-                 ifindex = if_nametoindex (mpinfo->peer->ifname);
-               }
-             else if (mpinfo->peer->nexthop.ifp)
-               {
-                 ifindex = mpinfo->peer->nexthop.ifp->ifindex;
-               }
-           }
-
-         if (ifindex == 0)
-           {
-             continue;
-           }
+            if (mpinfo->peer->ifname)
+              ifindex = if_nametoindex (mpinfo->peer->ifname);
+            else if (mpinfo->peer->nexthop.ifp)
+              ifindex = mpinfo->peer->nexthop.ifp->ifindex;
+
+          if (ifindex == 0)
+            continue;
 
           stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
           stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
           valid_nh_count++;
-       }
+        }
 
       /* Make Zebra API structure. */
       api.flags = flags;
@@ -911,24 +1042,44 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
       api.ifindex_num = valid_nh_count;
       api.ifindex = (unsigned int *)STREAM_DATA (bgp_ifindices_buf);
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
-      api.metric = info->attr->med;
+      api.metric = metric;
 
       if (BGP_DEBUG(zebra, ZEBRA))
-       {
-         char buf[2][INET6_ADDRSTRLEN];
-         zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u",
-                    inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
-                    p->prefixlen,
-                    inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
-                    api.metric);
-       }
+        {
+          int i;
+          zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u",
+                   valid_nh_count ? "add" : "delete",
+                   inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
+                   p->prefixlen, api.metric);
+          for (i = 0; i < api.nexthop_num; i++)
+            zlog_debug("  IPv6 [nexthop %d] %s", i+1,
+                       inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
+        }
 
-      zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, 
-                       (struct prefix_ipv6 *) p, &api);
+      zapi_ipv6_route (valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
+                       zclient, (struct prefix_ipv6 *) p, &api);
     }
 #endif /* HAVE_IPV6 */
 }
 
+/* Announce all routes of a table to zebra */
+void
+bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
+{
+  struct bgp_node *rn;
+  struct bgp_table *table;
+  struct bgp_info *ri;
+
+  table = bgp->rib[afi][safi];
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    for (ri = rn->info; ri; ri = ri->next)
+      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
+          && ri->type == ZEBRA_ROUTE_BGP
+          && ri->sub_type == BGP_ROUTE_NORMAL)
+        bgp_zebra_announce (&rn->p, ri, bgp, afi, safi);
+}
+
 void
 bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
 {
index 466758ec3dbd95c3750eb9d3e116aa1d1a76074b..34e121670698a68949c42a7c6f8b3d82a6e52acf 100644 (file)
@@ -33,7 +33,9 @@ extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t,
                                      safi_t, int *);
 extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,
                                   int *);
-extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t);
+extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *,
+                                afi_t, safi_t);
+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);
index 3c2f82c6bed2aadae6cfab4844a88a75ba32090f..2635b729b9ab28162eb45da8f7dd0f449a3a3674 100644 (file)
@@ -5196,6 +5196,7 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
     }
 
   bgp_config_write_maxpaths (vty, bgp, afi, safi, &write);
+  bgp_config_write_table_map (vty, bgp, afi, safi, &write);
 
   if (write)
     vty_out (vty, " exit-address-family%s", VTY_NEWLINE);
@@ -5378,6 +5379,7 @@ bgp_config_write (struct vty *vty)
 
       /* maximum-paths */
       bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
+      bgp_config_write_table_map (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
 
       /* Distance configuration. */
       bgp_config_write_distance (vty, bgp);
index 4fb6afefc0cb0f49f944bb05c8429b1e80be4f76..b2d421ed1f8a77635c6d02f32e68fda9c7ce3df5 100644 (file)
@@ -62,6 +62,13 @@ struct bgp_master
 #define BGP_OPT_NO_LISTEN                (1 << 3)
 };
 
+/* BGP route-map structure.  */
+struct bgp_rmap
+{
+  char *name;
+  struct route_map *map;
+};
+
 /* BGP instance structure.  */
 struct bgp 
 {
@@ -153,6 +160,9 @@ struct bgp
   /* BGP routing information base.  */
   struct bgp_table *rib[AFI_MAX][SAFI_MAX];
 
+  /* BGP table route-map.  */
+  struct bgp_rmap table_map[AFI_MAX][SAFI_MAX];
+
   /* BGP redistribute configuration. */
   u_char redist[AFI_MAX][ZEBRA_ROUTE_MAX];
 
@@ -161,11 +171,7 @@ struct bgp
   u_int32_t redist_metric[AFI_MAX][ZEBRA_ROUTE_MAX];
 
   /* BGP redistribute route-map.  */
-  struct
-  {
-    char *name;
-    struct route_map *map;
-  } rmap[AFI_MAX][ZEBRA_ROUTE_MAX];
+  struct bgp_rmap rmap[AFI_MAX][ZEBRA_ROUTE_MAX];
 
   /* BGP distance configuration.  */
   u_char distance_ebgp;
index 10fe13ca22ebf837af341d4ca9b1bc9c470df8b3..5dd4ed616d40b140487cd1f497e134f27f34c163 100644 (file)
@@ -247,6 +247,17 @@ and generates updates to its peers.
 Default max-delay is 0, i.e. the feature is off by default.
 @end deffn
 
+@deffn {BGP} {table-map @var{route-map-name}} {}
+This feature is used to apply a route-map on route updates from BGP to Zebra.
+All the applicable match operations are allowed, such as match on prefix,
+next-hop, communities, etc. Set operations for this attach-point are limited
+to metric and next-hop only. Any operation of this feature does not affect
+BGPs internal RIB.
+
+Supported for ipv4 and ipv6 address families. It works on multi-paths as well,
+however, metric setting is based on the best-path only.
+@end deffn
+
 @node BGP Peer
 @section BGP Peer