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