diff options
-rw-r--r-- | bgpd/bgp_advertise.c | 5 | ||||
-rw-r--r-- | bgpd/bgp_advertise.h | 2 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 30 |
3 files changed, 25 insertions, 12 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index e0fa58d4..be9b4801 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -361,7 +361,7 @@ bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) XFREE (MTYPE_BGP_ADJ_IN, bai); } -void +int bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) { struct bgp_adj_in *adj; @@ -371,10 +371,11 @@ bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) break; if (! adj) - return; + return 0; bgp_adj_in_remove (rn, adj); bgp_unlock_node (rn); + return 1; } void diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 2cf2a29b..adbbe307 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -133,7 +133,7 @@ extern int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t, struct bgp_node *); extern void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *); -extern void bgp_adj_in_unset (struct bgp_node *, struct peer *); +extern int bgp_adj_in_unset (struct bgp_node *, struct peer *); extern void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *); extern struct bgp_advertise * diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 34cb7c0c..34ba1abe 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2431,6 +2431,27 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, bgp = peer->bgp; + /* Lookup node. */ + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); + + /* Cisco IOS 12.4(24)T4 on session establishment sends withdraws for all + * routes that are filtered. This tanks out Quagga RS pretty badly due to + * the iteration over all RS clients. + * Since we need to remove the entry from adj_in anyway, do that first and + * if there was no entry, we don't need to do anything more. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) + && peer != bgp->peer_self) + if (!bgp_adj_in_unset (rn, peer)) + { + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_DEBUG, "%s withdrawing route %s/%d " + "not in adj-in", peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + bgp_unlock_node (rn); + return 0; + } + /* Process the withdraw for each RS-client. */ for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) { @@ -2445,15 +2466,6 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); - /* Lookup node. */ - rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); - - /* If peer is soft reconfiguration enabled. Record input packet for - further calculation. */ - if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) - && peer != bgp->peer_self) - bgp_adj_in_unset (rn, peer); - /* Lookup withdrawn route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) |