[frr] [PATCH 03/11] bgpd: VRF import processing

Philippe Guibert philippe.guibert at 6wind.com
Wed Dec 21 09:13:48 EST 2016


From: Christian Franke <chris at opensourcerouting.org>

This enhancement permits to export received or locally set route
entries for MPLS VPN, to the appropriate VRF. By introducing the
RFC4360 and BGP extended communities, some export route target are
received on BGP update, or some import route target are set on a
local route entry. It results from exporting the current route
information to the appropriate VRF RIB entry.
This commit is relying on BGP VRF processing, and supports VRF
RIB election as for standard RIBs. This makes it reusable, even
for multipath feature.
Moreover, some debug traces have been enhanced to inform VRF RIB
changes. Those logs are reflected in new debug command:

[no] debug bgp vrf

Signed-off-by: Christian Franke <chris at opensourcerouting.org>
Signed-off-by: Philippe Guibert <philippe.guibert at 6wind.com>
---
 bgpd/bgp_debug.c |   5 +
 bgpd/bgp_route.c |  30 ++++-
 bgpd/bgp_route.h |   7 +
 bgpd/bgp_vrf.c   | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 bgpd/bgp_vrf.h   |  20 +++
 5 files changed, 445 insertions(+), 12 deletions(-)

diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index de175de5a056..9c8c572f4ad6 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -38,6 +38,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_community.h"
 #include "bgpd/bgp_updgrp.h"
+#include "bgpd/bgp_vrf.h"
 
 unsigned long conf_bgp_debug_as4;
 unsigned long conf_bgp_debug_neighbor_events;
@@ -1695,6 +1696,10 @@ DEFUN (show_debugging_bgp,
 
   if (BGP_DEBUG (allow_martians, ALLOW_MARTIANS))
     vty_out (vty, "  BGP allow martian next hop debugging is on%s", VTY_NEWLINE);
+
+  if (BGP_DEBUG (bgp_vrf, BGPVRF))
+    vty_out (vty, "  BGP VRF debugging is on%s", VTY_NEWLINE);
+
   vty_out (vty, "%s", VTY_NEWLINE);
   return CMD_SUCCESS;
 }
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 1a9845392bb4..81d33df024fa 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -115,7 +115,7 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
 }
 
 /* Allocate bgp_info_extra */
-static struct bgp_info_extra *
+struct bgp_info_extra *
 bgp_info_extra_new (void)
 {
   struct bgp_info_extra *new;
@@ -2047,6 +2047,12 @@ bgp_process_vrf_main (struct work_queue *wq, void *data)
     {
       if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
         {
+          /* case mpath number of entries changed */
+          if (CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG))
+            {
+              UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
+              SET_FLAG (old_select->flags, BGP_INFO_MULTIPATH);
+            }
           /* no zebra announce */
 	  UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
           UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
@@ -2065,7 +2071,14 @@ bgp_process_vrf_main (struct work_queue *wq, void *data)
 
   if (old_select)
     {
-      bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
+      if( CHECK_FLAG (old_select->flags, BGP_INFO_SELECTED))
+        {
+          if(bgp_is_mpath_entry(old_select, new_select))
+            {
+              UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
+              SET_FLAG (old_select->flags, BGP_INFO_MULTIPATH);
+            }
+        }
     }
   if (new_select)
     {
@@ -2304,6 +2317,7 @@ bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
   if (!CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
     bgp_info_delete (rn, ri); /* keep historical info */
 
+  bgp_vrf_process_imports (peer->bgp, afi, safi, rn, ri, NULL);
   bgp_process (peer->bgp, rn, afi, safi);
 }
 
@@ -2354,7 +2368,7 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
   bgp_rib_remove (rn, ri, peer, afi, safi);
 }
 
-static struct bgp_info *
+struct bgp_info *
 info_make (int type, int sub_type, u_short instance, struct peer *peer, struct attr *attr,
 	   struct bgp_node *rn)
 {
@@ -2780,6 +2794,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
       bgp_aggregate_increment (bgp, p, ri, afi, safi);
 
       bgp_process (bgp, rn, afi, safi);
+      bgp_vrf_process_imports(bgp, afi, safi, rn, (struct bgp_info *)0xffffffff, ri);                           
       bgp_unlock_node (rn);
 
       return 0;
@@ -2875,6 +2890,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
   /* Process change. */
   bgp_process (bgp, rn, afi, safi);
+  bgp_vrf_process_imports(peer->bgp, afi, safi, rn, NULL, new);
 
   return 0;
 
@@ -3811,7 +3827,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
 	  /* Process change. */
 	  bgp_aggregate_increment (bgp, p, ri, afi, safi);
 	  bgp_process (bgp, rn, afi, safi);
-	  bgp_unlock_node (rn);
+	  bgp_vrf_process_imports(bgp, afi, safi, rn, (struct bgp_info *)0xffffffff, ri);
+          bgp_unlock_node (rn);
 	  aspath_unintern (&attr.aspath);
 	  bgp_attr_extra_free (&attr);
 	  return;
@@ -3861,6 +3878,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
   
   /* Process change. */
   bgp_process (bgp, rn, afi, safi);
+  bgp_vrf_process_imports(bgp, afi, safi, rn, NULL, new);
 
   /* Unintern original. */
   aspath_unintern (&attr.aspath);
@@ -3896,6 +3914,7 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
       bgp_aggregate_decrement (bgp, p, ri, afi, safi);
       bgp_unlink_nexthop(ri);
       bgp_info_delete (rn, ri);
+      bgp_vrf_process_imports(bgp, afi, safi, rn, ri, NULL);
       bgp_process (bgp, rn, afi, safi);
     }
 
@@ -3939,6 +3958,7 @@ bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi,
 #endif
       bgp_aggregate_decrement (bgp, p, ri, afi, safi);
       bgp_info_delete (rn, ri);
+      bgp_vrf_process_imports(bgp, afi, safi, rn, ri, NULL);
       bgp_process (bgp, rn, afi, safi);
     }
 
@@ -4081,6 +4101,8 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
 
   /* Process change. */
   bgp_process (bgp, rn, afi, safi);
+  
+  bgp_vrf_process_imports(bgp, afi, safi, rn, NULL, new);
 
 #if ENABLE_BGP_VNC
   rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd,
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index df1e8d8e056a..1bbd9cc99745 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -382,4 +382,11 @@ extern int
 bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table,
                 enum bgp_show_type type, void *output_arg, u_char use_json);
 
+extern struct bgp_info *
+info_make (int type, int sub_type, u_short instance, struct peer *peer, struct attr *attr,
+	   struct bgp_node *rn);
+
+extern struct bgp_info_extra *
+bgp_info_extra_new (void);
+
 #endif /* _QUAGGA_BGP_ROUTE_H */
diff --git a/bgpd/bgp_vrf.c b/bgpd/bgp_vrf.c
index a6354de700e1..d1883a5c95bd 100644
--- a/bgpd/bgp_vrf.c
+++ b/bgpd/bgp_vrf.c
@@ -29,6 +29,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_vrf.h"
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_mpath.h"
 
 static int
 bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi,
@@ -38,6 +40,13 @@ static int
 bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str,
                     afi_t afi, int prefix_check,u_char use_json);
 
+static void
+bgp_vrf_apply_new_imports_internal (struct bgp_vrf *vrf, afi_t afi, safi_t safi);
+
+static void
+bgp_vrf_process_one (struct bgp_vrf *vrf, afi_t afi, safi_t safi, struct bgp_node *rn,
+                     struct bgp_info *select, int action);
+
 /* for vty access to bgp vrf node */
 DEFINE_QOBJ_TYPE(bgp_vrf)
 
@@ -49,6 +58,11 @@ static struct cmd_node bgp_vrf_node =
   1
 };
 
+/* for debugging */
+unsigned long conf_bgp_debug_bgp_vrf;
+unsigned long term_bgp_debug_bgp_vrf;
+
+
 static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom)
 {
   assert (ecom->refcnt > 0);
@@ -242,20 +256,17 @@ bgp_vrf_context_delete (struct bgp_vrf *vrf)
   bgp_vrf_delete_int(vrf);
 }
 
-void
-bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
+static void
+bgp_vrf_apply_new_imports_internal (struct bgp_vrf *vrf, afi_t afi, safi_t safi)
 {
   struct bgp_node *rd_rn, *rn;
-  struct bgp_info *sel;
+  struct bgp_info *sel, *mp;
   struct bgp_table *table;
   struct ecommunity *ecom;
   size_t i, j;
   bool found;
 
-  if (!vrf->rt_import || vrf->rt_import->size == 0)
-    return;
-
-  for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][SAFI_MPLS_VPN]); rd_rn;
+  for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][safi]); rd_rn;
                   rd_rn = bgp_route_next (rd_rn))
     if (rd_rn->info != NULL)
       {
@@ -266,7 +277,27 @@ bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
             for (sel = rn->info; sel; sel = sel->next)
               if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED))
                 break;
-            if (!sel || !sel->attr || !sel->attr->extra)
+            if (!sel)
+              continue;
+            for (mp = rn->info; mp; mp = mp->next)
+              if(mp != sel &&  bgp_is_mpath_entry(mp, sel))
+                {
+                  /* call bgp_vrf_process_two */
+                  if (!mp->attr || !mp->attr->extra)
+                    continue;
+                  ecom = mp->attr->extra->ecommunity;
+                  if (!ecom)
+                    continue;
+                  found = false;
+                  for (i = 0; i < (size_t)ecom->size && !found; i++)
+                    for (j = 0; j < (size_t)vrf->rt_import->size && !found; j++)
+                      if (!memcmp(ecom->val + i * 8, vrf->rt_import->val + j * 8, 8))
+                        found = true;
+                  if (!found)
+                    continue;
+                  bgp_vrf_process_one(vrf, afi, safi, rn, mp, 0);
+                }
+            if (!sel->attr || !sel->attr->extra)
               continue;
             ecom = sel->attr->extra->ecommunity;
             if (!ecom)
@@ -279,10 +310,21 @@ bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
                   found = true;
             if (!found)
               continue;
+            bgp_vrf_process_one(vrf, afi, safi, rn, sel, 0);
           }
       }
 }
 
+void
+bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
+{
+  if (!vrf->rt_import || vrf->rt_import->size == 0)
+    return;
+  bgp_vrf_apply_new_imports_internal (vrf, afi, SAFI_MPLS_VPN);
+  bgp_vrf_apply_new_imports_internal (vrf, afi, SAFI_ENCAP);
+  return;
+}
+
 struct bgp_vrf *
 bgp_vrf_lookup_per_name (struct bgp *bgp, const char *name, int create)
 {
@@ -322,6 +364,304 @@ bgp_vrf_lookup_per_name (struct bgp *bgp, const char *name, int create)
   return vrf;
 }
 
+static bool rd_same (const struct prefix_rd *a, const struct prefix_rd *b)
+{
+  return !memcmp(&a->val, &b->val, sizeof(a->val));
+}
+
+/* VRF import processing */
+/* updates selected bgp_info structure to bgp vrf rib table
+ * most of the cases, processing consists in adding or removing entries in RIB tables
+ * on some cases, there is an update request. then it is necessary to have both old and new ri
+ */
+static void
+bgp_vrf_process_one (struct bgp_vrf *vrf, afi_t afi, safi_t safi, struct bgp_node *rn,
+                     struct bgp_info *select, int action)
+{
+  struct bgp_node *vrf_rn;
+  struct bgp_info *iter = NULL;
+  struct prefix_rd *prd;
+  char pfx_str[INET6_BUFSIZ];
+
+  prd = &bgp_node_table (rn)->prd;
+  if (BGP_DEBUG(bgp_vrf, BGPVRF))
+    {
+      char vrf_rd_str[RD_ADDRSTRLEN], rd_str[RD_ADDRSTRLEN];
+      char nh_str[BUFSIZ] = "<?>";
+
+      prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str));
+      prefix_rd2str(prd, rd_str, sizeof(rd_str));
+      prefix2str(&rn->p, pfx_str, sizeof(pfx_str));
+      if(select && select->attr && select->attr->extra)
+        {
+          if (afi == AFI_IP)
+            strcpy (nh_str, inet_ntoa (select->attr->extra->mp_nexthop_global_in));
+          else if (afi == AFI_IP6)
+            inet_ntop (AF_INET6, &select->attr->extra->mp_nexthop_global, nh_str, BUFSIZ);
+        }
+      else if(select)
+        {
+          inet_ntop (AF_INET, &select->attr->nexthop,
+                     nh_str, sizeof (nh_str));
+        }
+      zlog_debug ("vrf[%s] %s: [%s] [nh %s] %s ", vrf_rd_str, pfx_str, rd_str, nh_str,
+                action == BGP_VRF_IMPORT_ROUTE_INFO_TO_REMOVE? "withdrawing" : "updating");
+    }  
+  /* add a new entry if necessary
+   * if already present, do nothing. 
+   * use the loop to parse old entry also */
+
+  /* check if global RIB plans for destroying initial entry
+   * if yes, then suppress it
+   */
+  if(!vrf || !vrf->rib[afi] || !select)
+    {
+      return;
+    }
+  vrf_rn = bgp_node_get (vrf->rib[afi], &rn->p);
+  if(!vrf_rn)
+    {
+      return;
+    }
+  if ( (action == BGP_VRF_IMPORT_ROUTE_INFO_TO_REMOVE) &&
+       (CHECK_FLAG (select->flags, BGP_INFO_REMOVED)))
+    {
+      /* check entry not already present */
+      for (iter = vrf_rn->info; iter; iter = iter->next)
+        {
+          /* coming from same peer */
+          if(iter->peer->remote_id.s_addr == select->peer->remote_id.s_addr)
+            {
+              bgp_info_delete(vrf_rn, iter);
+              prefix2str(&vrf_rn->p, pfx_str, sizeof(pfx_str));
+              if (BGP_DEBUG(bgp_vrf, BGPVRF))
+                {
+                  char nh_str[BUFSIZ] = "<?>";
+                  if(iter->attr && iter->attr->extra)
+                    {
+                      if (afi == AFI_IP)
+                        strcpy (nh_str, inet_ntoa (iter->attr->extra->mp_nexthop_global_in));
+                      else if (afi == AFI_IP6)
+                        inet_ntop (AF_INET6, &iter->attr->extra->mp_nexthop_global, nh_str, BUFSIZ);
+                    }
+                  else
+                    {
+                      inet_ntop (AF_INET, &iter->attr->nexthop,
+                                 nh_str, sizeof (nh_str));
+                    }
+                  zlog_debug ("%s: processing entry (for removal) from %s [ nh %s]", 
+                              pfx_str, iter->peer->host, nh_str);
+                }
+              bgp_process (iter->peer->bgp, vrf_rn, afi, SAFI_UNICAST);
+              break;
+            }
+        }
+    }
+  if(action == BGP_VRF_IMPORT_ROUTE_INFO_TO_ADD || action == BGP_VRF_IMPORT_ROUTE_INFO_TO_UPDATE)
+    {
+      /* check entry not already present */
+      for (iter = vrf_rn->info; iter; iter = iter->next)
+        {
+          if (!rd_same (&iter->extra->vrf_rd, prd))
+            continue;
+          /* search associated old entry.
+           * assume with same nexthop and same peer */
+          if(iter->peer->remote_id.s_addr == select->peer->remote_id.s_addr)
+            {
+              /* update */
+              if(action == BGP_VRF_IMPORT_ROUTE_INFO_TO_UPDATE)
+                {
+                  /* update label */
+                  /* update attr part / containing next hop */
+                  if(select->extra)
+                    memcpy (iter->extra->tag, select->extra->tag, 3);
+                  if(select->attr)
+                    {
+                      if(iter->attr)
+                        bgp_attr_unintern(&iter->attr);
+                      iter->attr = bgp_attr_intern (select->attr);
+                      if(select->attr->extra && select->attr->extra->ecommunity)
+                        {
+                          bgp_attr_extra_get(iter->attr);
+                          iter->attr->extra->ecommunity = 
+                            ecommunity_dup(select->attr->extra->ecommunity);
+                        }
+                    }
+                  /* if changes, update, and permit resending
+                     information */
+                  bgp_info_set_flag (rn, iter, BGP_INFO_ATTR_CHANGED);
+                }
+              break;
+            }
+        }
+      /* silently add new entry to rn */
+      if(!iter)
+        {
+          iter = info_make (select->type, select->sub_type, 0, select->peer, 
+                            select->attr?bgp_attr_intern (select->attr):NULL,
+                            vrf_rn);
+          iter->extra = bgp_info_extra_new();
+          iter->extra->vrf_rd = *prd;
+          if (select->extra)
+            memcpy (iter->extra->tag, select->extra->tag, 3);
+          SET_FLAG (iter->flags, BGP_INFO_VALID);
+          bgp_info_add (vrf_rn, iter);
+          bgp_unlock_node (vrf_rn);
+        }
+      if (BGP_DEBUG(bgp_vrf, BGPVRF))
+        {
+          char nh_str[BUFSIZ] = "<?>";
+
+          prefix2str(&rn->p, pfx_str, sizeof(pfx_str));
+          if(iter->attr && iter->attr->extra)
+            {
+              if (afi == AFI_IP)
+                strcpy (nh_str, inet_ntoa (iter->attr->extra->mp_nexthop_global_in));
+              else if (afi == AFI_IP6)
+                inet_ntop (AF_INET6, &iter->attr->extra->mp_nexthop_global, nh_str, BUFSIZ);
+            }
+          else
+            {
+              inet_ntop (AF_INET, &iter->attr->nexthop,
+                         nh_str, sizeof (nh_str));
+            }
+          zlog_debug ("%s: processing entry (for %s) from %s [ nh %s]",
+                      pfx_str, action == BGP_VRF_IMPORT_ROUTE_INFO_TO_UPDATE?"upgrading":"adding",
+                      iter->peer->host, nh_str);
+
+        }
+      bgp_process (iter->peer->bgp, vrf_rn, afi, SAFI_UNICAST);
+    }
+}
+
+/* propagates a change in the BGP per VRF tables,
+ * according to import export rules contained:
+ * - in bgp vrf configuration
+ * - in Route Target extended communities
+ * result stands for a new ri to add, an old ri to suppress,
+ * or an change in the ri itself. for latter case, old ri is
+ * not attached
+ */
+void
+bgp_vrf_process_imports (struct bgp *bgp, afi_t afi, safi_t safi,
+                         struct bgp_node *rn,
+                         struct bgp_info *old_select,
+                         struct bgp_info *new_select)
+{
+  struct ecommunity *old_ecom = NULL, *new_ecom = NULL;
+  struct bgp_vrf *vrf;
+  struct listnode *node;
+  size_t i, j;
+  struct prefix_rd *prd;
+  int action;
+  struct bgp_info *ri;
+
+  if (safi != SAFI_MPLS_VPN)
+    return;
+
+  prd = &bgp_node_table (rn)->prd;
+  if(new_select && !old_select)
+    {
+      ri = new_select;
+      action = BGP_VRF_IMPORT_ROUTE_INFO_TO_ADD;
+    }
+  else if(!new_select && old_select)
+    {
+      ri = old_select;
+      action = BGP_VRF_IMPORT_ROUTE_INFO_TO_REMOVE;
+    }
+  else
+    {
+      /* old_select set to null */
+      old_select = NULL;
+      ri = new_select;
+      action = BGP_VRF_IMPORT_ROUTE_INFO_TO_UPDATE;
+    }
+
+  if (old_select && old_select->attr && old_select->attr->extra)
+    old_ecom = old_select->attr->extra->ecommunity;
+  if (new_select && new_select->attr && new_select->attr->extra)
+    new_ecom = new_select->attr->extra->ecommunity;
+
+  if (old_select
+      && old_select->type == ZEBRA_ROUTE_BGP
+      && old_select->sub_type == BGP_ROUTE_STATIC
+      && (!new_select
+          || !new_select->type == ZEBRA_ROUTE_BGP
+          || !new_select->sub_type == BGP_ROUTE_STATIC))
+    for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
+      if (!prefix_cmp((struct prefix*)&vrf->outbound_rd,
+                      (struct prefix*)prd))
+        bgp_vrf_process_one(vrf, afi, safi, rn, ri, action);
+
+  if (old_ecom)
+    for (i = 0; i < (size_t)old_ecom->size; i++)
+      {
+        struct bgp_rt_sub dummy, *rt_sub;
+        uint8_t *val = old_ecom->val + 8 * i;
+        uint8_t type = val[1];
+        bool withdraw = true;
+
+        if (type != ECOMMUNITY_ROUTE_TARGET)
+          continue;
+
+        memcpy(&dummy.rt, val, 8);
+        rt_sub = hash_lookup (bgp->rt_subscribers, &dummy);
+        if (!rt_sub)
+          continue;
+
+        if (new_ecom)
+          for (j = 0; j < (size_t)new_ecom->size; j++)
+            if (!memcmp(new_ecom->val + j * 8, val, 8))
+              {
+                withdraw = false;
+                break;
+              }
+
+        for (ALL_LIST_ELEMENTS_RO(rt_sub->vrfs, node, vrf))
+          bgp_vrf_process_one (vrf, afi, safi, rn, ri, withdraw == false?
+                               BGP_VRF_IMPORT_ROUTE_INFO_TO_UPDATE:
+                               BGP_VRF_IMPORT_ROUTE_INFO_TO_REMOVE);
+      }
+
+  if (new_ecom)
+    for (i = 0; i < (size_t)new_ecom->size; i++)
+      {
+        struct bgp_rt_sub dummy, *rt_sub;
+        uint8_t *val = new_ecom->val + 8 * i;
+        uint8_t type = val[1];
+        bool found = false;
+
+        if (type != ECOMMUNITY_ROUTE_TARGET)
+          continue;
+
+        memcpy(&dummy.rt, val, 8);
+        rt_sub = hash_lookup (bgp->rt_subscribers, &dummy);
+        if (!rt_sub)
+          continue;
+
+        if (old_ecom)
+          for (j = 0; j < (size_t)old_ecom->size; j++)
+            if (!memcmp(old_ecom->val + j * 8, val, 8))
+              {
+                found = true;
+                break;
+              }
+
+        if (!found)
+          for (ALL_LIST_ELEMENTS_RO(rt_sub->vrfs, node, vrf))
+            bgp_vrf_process_one (vrf, afi, safi, rn, ri, action);
+      }
+
+  if (new_select
+      && new_select->type == ZEBRA_ROUTE_BGP
+      && new_select->sub_type == BGP_ROUTE_STATIC)
+    for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
+      if (!prefix_cmp((struct prefix*)&vrf->outbound_rd,
+                      (struct prefix*)prd))
+        bgp_vrf_process_one(vrf, afi, safi, rn, ri, action);
+}
+
 /* VTY configuration and exploitation */
 
 DEFUN (bgp_vrf,
@@ -652,6 +992,41 @@ DEFUN (show_ipv6_bgp_vrf_route,
   return bgp_show_vrf_route (vty, argv[4]->arg, argv[5]->arg, AFI_IP6, 0, use_json (argc,argv));
 }
 
+DEFUN (debug_bgp_vrf,
+       debug_bgp_vrf_cmd,
+       "debug bgp vrf",
+       DEBUG_STR
+       BGP_STR
+       "BGP VRF Changes\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_ON (bgp_vrf, BGPVRF);
+  else
+    {
+      TERM_DEBUG_ON (bgp_vrf, BGPVRF);
+      vty_out (vty, "BGP VRF debugging is on%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_vrf,
+       no_debug_bgp_vrf_cmd,
+       "no debug bgp vrf",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "BGP VRF changes\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_OFF (bgp_vrf, BGPVRF);
+  else
+    {
+      TERM_DEBUG_OFF (bgp_vrf, BGPVRF);
+      vty_out (vty, "BGP vrf debugging is off%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
 /* BGP VRF init/delete/ show running */
 void
 bgp_bgpvrf_init (struct bgp *bgp)
@@ -683,6 +1058,10 @@ void bgp_bgpvrf_vty (void)
   install_element (VIEW_NODE, &show_ip_bgp_vrf_route_cmd);
   install_element (VIEW_NODE, &show_ipv6_bgp_vrf_cmd);
   install_element (VIEW_NODE, &show_ipv6_bgp_vrf_route_cmd);
+
+  install_element (ENABLE_NODE, &debug_bgp_vrf_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_vrf_cmd);
+
 }
 
 void
diff --git a/bgpd/bgp_vrf.h b/bgpd/bgp_vrf.h
index 81d491331d36..40f885b46a00 100644
--- a/bgpd/bgp_vrf.h
+++ b/bgpd/bgp_vrf.h
@@ -30,6 +30,15 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgp_table.h"
 #include "bgp_ecommunity.h"
 
+/* for vrf importation */
+#define BGP_VRF_IMPORT_ROUTE_INFO_TO_UPDATE 2
+#define BGP_VRF_IMPORT_ROUTE_INFO_TO_REMOVE 1
+#define BGP_VRF_IMPORT_ROUTE_INFO_TO_ADD    0
+
+/* for debugging */
+#define BGP_DEBUG_BGPVRF                 0x01
+
+
 struct bgp_rt_sub
 {
   struct ecommunity_val rt;
@@ -64,6 +73,11 @@ struct bgp_vrf
 };
 DECLARE_QOBJ_TYPE(bgp_vrf)
 
+
+/* for debugging */
+extern unsigned long conf_bgp_debug_bgp_vrf;
+extern unsigned long term_bgp_debug_bgp_vrf;
+
 extern void bgp_bgpvrf_vty (void);
 extern void bgp_bgpvrf_init (struct bgp *bgp);
 extern void bgp_bgpvrf_delete (struct bgp *bgp);
@@ -81,5 +95,11 @@ extern void bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi);
 extern void bgp_vrf_rt_import_unset (struct bgp_vrf *vrf);
 extern void bgp_vrf_rt_export_unset (struct bgp_vrf *vrf);
 
+extern void
+bgp_vrf_process_imports (struct bgp *bgp, afi_t afi, safi_t safi,
+                         struct bgp_node *rn,
+                         struct bgp_info *old_select,
+                         struct bgp_info *new_select);
+
 #endif /* _QUAGGA_BGP_VRF */
 
-- 
2.1.4





More information about the dev mailing list