summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2015-04-13 09:50:00 +0200
committerDonald Sharp <sharpd@cumulusnetworks.com>2016-06-08 14:58:21 -0400
commit6b87f736187d1a40a6b4f8d4fe42716bac09e857 (patch)
tree2f8032eee91b59957713c5d8cbc7ae32678a7720
parent801e0e14920b7ad91080fb65b07c9283179eaf31 (diff)
bgpd: speed up "no-hit" withdraws for routeservers
This accelerates handling of incoming Withdraw messages for routes that don't exist in the table to begin with. Cisco IOS 12.4(24)T4 has a bug in this regard - it sends withdraws instead of doing nothing for prefixes that are filtered. Pulling up the adj_in removal in Quagga should have no ill effect, but we can avoid the costly iteration over all rsclients if there was no adj_in entry. Performance impact of this change on routeserver with 3 buggy peers, startup/sync time: before patch: 143.12 seconds (user cpu) after patch: 7.01 seconds (user cpu) Many thanks to Nick Hilliard & INEX for providing real-world test data! Signed-off-by: David Lamparter <equinox@opensourcerouting.org> Acked-by: Paul Jakma <paul@jakma.org>
-rw-r--r--bgpd/bgp_advertise.c8
-rw-r--r--bgpd/bgp_advertise.h2
-rw-r--r--bgpd/bgp_route.c20
3 files changed, 26 insertions, 4 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 73b2619c26..de27513a42 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -222,7 +222,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,
u_int32_t addpath_id)
{
@@ -230,6 +230,10 @@ bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer,
struct bgp_adj_in *adj_next;
adj = rn->adj_in;
+
+ if (!adj)
+ return 0;
+
while (adj)
{
adj_next = adj->next;
@@ -242,6 +246,8 @@ bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer,
adj = adj_next;
}
+
+ return 1;
}
void
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h
index ae6e6bd147..86c959478d 100644
--- a/bgpd/bgp_advertise.h
+++ b/bgpd/bgp_advertise.h
@@ -172,7 +172,7 @@ struct bgp_synchronize
/* Prototypes. */
extern int bgp_adj_out_lookup (struct peer *, struct bgp_node *, u_int32_t);
extern void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *, u_int32_t);
-extern void bgp_adj_in_unset (struct bgp_node *, struct peer *, u_int32_t);
+extern int bgp_adj_in_unset (struct bgp_node *, struct peer *, u_int32_t);
extern void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *);
extern void bgp_sync_init (struct peer *);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 1b17dc36b5..d9dec8772b 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2561,10 +2561,26 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
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. */
+ * further calculation.
+ *
+ * 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)
- bgp_adj_in_unset (rn, peer, addpath_id);
+ if (!bgp_adj_in_unset (rn, peer, addpath_id))
+ {
+ if (bgp_debug_update (peer, p, NULL, 1))
+ zlog_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;
+ }
/* Lookup withdrawn route. */
for (ri = rn->info; ri; ri = ri->next)