On adding/removing/updating NLRI entries into VRF RIB tables, a BGP
event is fired. Note that only selected entries, and entries that are
part of multipath entries, and where one of the multipath entry is
selected.

Signed-off-by: Philippe Guibert <philippe.guib...@6wind.com>
---
 bgpd/bgp_route.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 bgpd/bgp_route.h |   2 ++
 bgpd/bgpd.c      |  16 +++++++++
 bgpd/bgpd.h      |   3 ++
 4 files changed, 124 insertions(+), 2 deletions(-)

diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 5b70478870d2..e83f292162ba 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1572,6 +1572,60 @@ void bgp_vrf_clean_tables (struct bgp_vrf *vrf)
     }
 }
 
+/* messages sent to ODL to signify that an entry
+ * has been selected, or unselected
+ */
+void
+bgp_vrf_update (struct bgp_vrf *vrf, afi_t afi, struct bgp_node *rn,
+                struct bgp_info *selected, uint8_t announce)
+{
+  if(!vrf || (rn && bgp_node_table (rn)->type != BGP_TABLE_VRF))
+    return;
+  if (announce == true)
+    {
+      if(CHECK_FLAG (selected->flags, BGP_INFO_UPDATE_SENT))
+        return;
+      SET_FLAG (selected->flags, BGP_INFO_UPDATE_SENT);
+      UNSET_FLAG (selected->flags, BGP_INFO_WITHDRAW_SENT);
+    }
+  else
+    {
+      /* if not already sent, do nothing */
+      if(!CHECK_FLAG (selected->flags, BGP_INFO_UPDATE_SENT))
+        return;
+      if(CHECK_FLAG (selected->flags, BGP_INFO_WITHDRAW_SENT))
+        return;
+      SET_FLAG (selected->flags, BGP_INFO_WITHDRAW_SENT);
+      UNSET_FLAG (selected->flags, BGP_INFO_UPDATE_SENT);
+    }
+  if (BGP_DEBUG (events, EVENTS))
+    {
+      char vrf_rd_str[RD_ADDRSTRLEN], rd_str[RD_ADDRSTRLEN], 
pfx_str[INET6_BUFSIZ];
+      char label_str[BUFSIZ] = "<?>", nh_str[BUFSIZ] = "<?>";
+
+      prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str));
+      prefix_rd2str(&selected->extra->vrf_rd, rd_str, sizeof(rd_str));
+      prefix2str(&rn->p, pfx_str, sizeof(pfx_str));
+      labels2str(label_str, sizeof(label_str),
+                      selected->extra->labels, selected->extra->nlabels);
+
+      if (selected->attr && selected->attr->extra)
+        {
+          if (afi == AFI_IP)
+            strcpy (nh_str, inet_ntoa 
(selected->attr->extra->mp_nexthop_global_in));
+          else if (afi == AFI_IP6)
+            inet_ntop (AF_INET6, &selected->attr->extra->mp_nexthop_global, 
nh_str, BUFSIZ);
+        }
+
+      if (announce)
+        zlog_debug ("vrf[%s] %s: prefix updated, best RD %s labels %s nexthop 
%s",
+                   vrf_rd_str, pfx_str, rd_str, label_str, nh_str);
+      else
+        zlog_debug ("vrf[%s] %s: prefix withdrawn nh %s label %s",
+                    vrf_rd_str, pfx_str, nh_str, label_str);
+    }
+}
+
 /* 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
@@ -2098,9 +2152,13 @@ bgp_process_vrf_main (struct work_queue *wq, void *data)
   struct bgp_node *rn = pq->rn;
   afi_t afi = pq->afi;
   safi_t safi = pq->safi;
-  struct bgp_info *new_select;
+  struct bgp_info *new_select, *ri;
   struct bgp_info *old_select;
   struct bgp_info_pair old_and_new;
+  struct bgp_vrf *vrf = NULL;
+
+  if(rn)
+    vrf = bgp_vrf_lookup_per_rn(bgp, afi, rn);
 
   /* Best path selection. */
   bgp_best_selection (bgp, rn, &old_and_new, afi, safi);
@@ -2117,6 +2175,13 @@ bgp_process_vrf_main (struct work_queue *wq, void *data)
             {
               UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
               SET_FLAG (old_select->flags, BGP_INFO_MULTIPATH);
+              for(ri = rn->info; ri; ri = ri->next)
+                {
+                  if(ri == old_select)
+                    continue;
+                  if(!bgp_is_mpath_entry(ri, new_select))
+                    bgp_vrf_update(vrf, afi, rn, ri, false);
+                }
             }
           /* no zebra announce */
          UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
@@ -2138,18 +2203,53 @@ bgp_process_vrf_main (struct work_queue *wq, void *data)
     {
       if( CHECK_FLAG (old_select->flags, BGP_INFO_SELECTED))
         {
-          if(bgp_is_mpath_entry(old_select, new_select))
+          if(!bgp_is_mpath_entry(old_select, new_select))
+            {
+              bgp_vrf_update(vrf, afi, rn, old_select, false);
+            }
+          else
             {
               UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
               SET_FLAG (old_select->flags, BGP_INFO_MULTIPATH);
             }
         }
+      /* withdraw mp entries which could have been removed
+       * and that a update has previously been sent
+       */
+      for(ri = rn->info; ri; ri = ri->next)
+        {
+          if(ri == old_select || (ri == new_select) )
+            continue;
+          if(!bgp_is_mpath_entry(ri, new_select))
+            {
+              bgp_vrf_update(vrf, afi, rn, ri, false);
+            }
+        }
+      bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
     }
   if (new_select)
     {
+      if(!CHECK_FLAG (new_select->flags, BGP_INFO_SELECTED) ||
+         CHECK_FLAG (new_select->flags, BGP_INFO_MULTIPATH) ||
+         CHECK_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG))
+        {
+          bgp_vrf_update(vrf, afi, rn, new_select, true);
+        }
       bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED);
       bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED);
       UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG);
+      /* append mp entries which could have been added 
+       * and that a update has not been sent
+       */
+      for(ri = rn->info; ri; ri = ri->next)
+        {
+          if( (ri == new_select) || ( ri == old_select))
+            continue;
+          if(bgp_is_mpath_entry(ri, new_select))
+            {
+              bgp_vrf_update(vrf, afi, rn, ri, true);
+            }
+        }
     }
 
   /* Reap old select bgp_info, if it has been removed */
@@ -2374,6 +2474,7 @@ bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, 
struct peer *peer,
   bgp_process (peer->bgp, rn, afi, safi);
 }
 
+
 static void
 bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
                  afi_t afi, safi_t safi, struct prefix_rd *prd)
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 80257fdbb41e..1357dee2eabb 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -99,6 +99,8 @@ struct bgp_info
 #define BGP_INFO_COUNTED       (1 << 10)
 #define BGP_INFO_MULTIPATH      (1 << 11)
 #define BGP_INFO_MULTIPATH_CHG  (1 << 12)
+#define BGP_INFO_UPDATE_SENT    (1 << 13)
+#define BGP_INFO_WITHDRAW_SENT  (1 << 14)
 
   /* BGP route type.  This can be static, RIP, OSPF, BGP etc.  */
   u_char type;
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 44a216e9844f..a0fe4de390fb 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2091,6 +2091,22 @@ bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub)
 }
 
 struct bgp_vrf *
+bgp_vrf_lookup_per_rn (struct bgp *bgp, int afi, struct bgp_node *vrf_rn)
+{
+  struct listnode *node;
+  struct bgp_vrf *vrf;
+
+  if(bgp_node_table (vrf_rn)->type != BGP_TABLE_VRF)
+    return NULL;
+  for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
+    if(vrf->rib[afi] == bgp_node_table (vrf_rn))
+      {
+        return vrf;
+      }
+  return NULL;
+}
+
+struct bgp_vrf *
 bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd)
 {
   struct listnode *node;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 85e2647b7e16..acf59c5aaf04 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -32,6 +32,8 @@ typedef u_int32_t as_t;
 typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
 typedef u_int16_t bgp_size_t;
 
+struct bgp_node;
+
 /* BGP router distinguisher value.  */
 #define BGP_RD_SIZE                8
 
@@ -1037,6 +1039,7 @@ extern int peer_ttl_security_hops_unset (struct peer *);
 extern void bgp_scan_finish (void);
 extern struct bgp_vrf *bgp_vrf_create (struct bgp *bgp, struct prefix_rd 
*outbound_rd);
 extern struct bgp_vrf *bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd 
*outbound_rd);
+extern struct bgp_vrf *bgp_vrf_lookup_per_rn (struct bgp *bgp, int afi, struct 
bgp_node *vrf_rn);
 extern void bgp_vrf_delete (struct bgp_vrf *vrf);
 extern void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity 
*rt_export);
 extern void bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity 
*rt_import);
-- 
2.1.4


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to