diff options
| author | David Lamparter <equinox@opensourcerouting.org> | 2021-04-22 11:04:52 +0200 |
|---|---|---|
| committer | David Lamparter <equinox@opensourcerouting.org> | 2022-05-19 12:14:40 +0200 |
| commit | bd9fb6f368049bd5f1f6a2b7bc97fbd51c9300cc (patch) | |
| tree | f172dc19ee071f21387bc212197d4913b99a881a /bgpd/bgp_packet.c | |
| parent | 18028bdb9b5d0e5cd6081d8df387551c206ce7ab (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.c | 37 |
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(); + } } } |
