summaryrefslogtreecommitdiff
path: root/bgpd/bgp_packet.c
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2021-04-22 11:04:52 +0200
committerDavid Lamparter <equinox@opensourcerouting.org>2022-05-19 12:14:40 +0200
commitbd9fb6f368049bd5f1f6a2b7bc97fbd51c9300cc (patch)
treef172dc19ee071f21387bc212197d4913b99a881a /bgpd/bgp_packet.c
parent18028bdb9b5d0e5cd6081d8df387551c206ce7ab (diff)
bgpd: implement SendHoldTimer
As described by https://www.ietf.org/archive/id/draft-spaghetti-idr-bgp-sendholdtimer-04.html Since this replicates the HoldTime check on the receiver that is already part of the protocol, I do not believe it necessary to wait for IETF progress on this draft. It's just replicating an existing element of the protocol at the other side of the session. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'bgpd/bgp_packet.c')
-rw-r--r--bgpd/bgp_packet.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index cacc4995fc..e4697fdb2b 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -122,8 +122,45 @@ void bgp_packet_set_size(struct stream *s)
*/
static void bgp_packet_add(struct peer *peer, struct stream *s)
{
+ intmax_t delta;
+ uint32_t holdtime;
+
frr_with_mutex(&peer->io_mtx) {
+ /* if the queue is empty, reset the "last OK" timestamp to
+ * now, otherwise if we write another packet immediately
+ * after it'll get confused
+ */
+ if (!stream_fifo_count_safe(peer->obuf))
+ peer->last_sendq_ok = bgp_clock();
+
stream_fifo_push(peer->obuf, s);
+
+ delta = bgp_clock() - peer->last_sendq_ok;
+ holdtime = atomic_load_explicit(&peer->holdtime,
+ memory_order_relaxed);
+
+ /* Note that when we're here, we're adding some packet to the
+ * OutQ. That includes keepalives when there is nothing to
+ * do, so there's a guarantee we pass by here once in a while.
+ *
+ * That implies there is no need to go set up another separate
+ * timer that ticks down SendHoldTime, as we'll be here sooner
+ * or later anyway and will see the checks below failing.
+ */
+ if (delta > 2 * (intmax_t)holdtime) {
+ flog_err(
+ EC_BGP_SENDQ_STUCK_PROPER,
+ "%s has not made any SendQ progress for 2 holdtimes, terminating session",
+ peer->host);
+ BGP_EVENT_ADD(peer, TCP_fatal_error);
+ } else if (delta > (intmax_t)holdtime &&
+ bgp_clock() - peer->last_sendq_warn > 5) {
+ flog_warn(
+ EC_BGP_SENDQ_STUCK_WARN,
+ "%s has not made any SendQ progress for 1 holdtime, peer overloaded?",
+ peer->host);
+ peer->last_sendq_warn = bgp_clock();
+ }
}
}