summaryrefslogtreecommitdiff
path: root/bgpd/bgp_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_packet.c')
-rw-r--r--bgpd/bgp_packet.c233
1 files changed, 223 insertions, 10 deletions
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index dfc64c043b..c2e2de1c73 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -444,6 +444,45 @@ int bgp_generate_updgrp_packets(struct thread *thread)
* yet.
*/
if (!next_pkt || !next_pkt->buffer) {
+ if (!paf->t_announce_route) {
+ /* Make sure we supress BGP UPDATES
+ * for normal processing later again.
+ */
+ UNSET_FLAG(paf->subgroup->sflags,
+ SUBGRP_STATUS_FORCE_UPDATES);
+
+ /* If route-refresh BoRR message was
+ * already sent and we are done with
+ * re-announcing tables for a decent
+ * afi/safi, we ready to send
+ * EoRR request.
+ */
+ if (CHECK_FLAG(
+ peer->af_sflags[afi][safi],
+ PEER_STATUS_BORR_SEND)) {
+ bgp_route_refresh_send(
+ peer, afi, safi, 0, 0,
+ 0,
+ BGP_ROUTE_REFRESH_EORR);
+
+ SET_FLAG(peer->af_sflags[afi]
+ [safi],
+ PEER_STATUS_EORR_SEND);
+ UNSET_FLAG(
+ peer->af_sflags[afi]
+ [safi],
+ PEER_STATUS_BORR_SEND);
+
+ if (bgp_debug_neighbor_events(
+ peer))
+ zlog_debug(
+ "%s sending route-refresh (EoRR) for %s/%s",
+ peer->host,
+ afi2str(afi),
+ safi2str(safi));
+ }
+ }
+
if (CHECK_FLAG(peer->cap,
PEER_CAP_RESTART_RCV)) {
if (!(PAF_SUBGRP(paf))->t_coalesce
@@ -809,7 +848,7 @@ void bgp_notify_send(struct peer *peer, uint8_t code, uint8_t sub_code)
*/
void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
uint8_t orf_type, uint8_t when_to_refresh,
- int remove)
+ int remove, uint8_t subtype)
{
struct stream *s;
struct bgp_filter *filter;
@@ -835,7 +874,10 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
/* Encode Route Refresh message. */
stream_putw(s, pkt_afi);
- stream_putc(s, 0);
+ if (subtype)
+ stream_putc(s, subtype);
+ else
+ stream_putc(s, 0);
stream_putc(s, pkt_safi);
if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD)
@@ -1453,6 +1495,29 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size)
return Receive_KEEPALIVE_message;
}
+static int bgp_refresh_stalepath_timer_expire(struct thread *thread)
+{
+ struct peer_af *paf;
+
+ paf = THREAD_ARG(thread);
+
+ afi_t afi = paf->afi;
+ safi_t safi = paf->safi;
+ struct peer *peer = paf->peer;
+
+ peer->t_refresh_stalepath = NULL;
+
+ if (peer->nsf[afi][safi])
+ bgp_clear_stale_route(peer, afi, safi);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s: route-refresh (BoRR) timer for %s/%s expired",
+ peer->host, afi2str(afi), safi2str(safi));
+
+ bgp_timer_set(peer);
+
+ return 0;
+}
/**
* Process BGP UPDATE message for peer.
@@ -1798,6 +1863,7 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
bgp_notify.subcode = stream_getc(peer->curr);
bgp_notify.length = size - 2;
bgp_notify.data = NULL;
+ bgp_notify.raw_data = NULL;
/* Preserv notify code and sub code. */
peer->notify.code = bgp_notify.code;
@@ -1881,6 +1947,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
struct peer_af *paf;
struct update_group *updgrp;
struct peer *updgrp_peer;
+ uint8_t subtype;
+ bgp_size_t msg_length =
+ size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE);
/* If peer does not have the capability, send notification. */
if (!CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_ADV)) {
@@ -1908,14 +1977,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
/* Parse packet. */
pkt_afi = stream_getw(s);
- (void)stream_getc(s);
+ subtype = stream_getc(s);
pkt_safi = stream_getc(s);
- if (bgp_debug_update(peer, NULL, NULL, 0))
- zlog_debug("%s rcvd REFRESH_REQ for afi/safi: %s/%s",
- peer->host, iana_afi2str(pkt_afi),
- iana_safi2str(pkt_safi));
-
/* Convert AFI, SAFI to internal values and check. */
if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
zlog_info(
@@ -1931,8 +1995,34 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
uint8_t orf_type;
uint16_t orf_len;
- if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE)
- < 5) {
+ if (subtype) {
+ /* If the length, excluding the fixed-size message
+ * header, of the received ROUTE-REFRESH message with
+ * Message Subtype 1 and 2 is not 4, then the BGP
+ * speaker MUST send a NOTIFICATION message with the
+ * Error Code of "ROUTE-REFRESH Message Error" and the
+ * subcode of "Invalid Message Length".
+ */
+ if (msg_length != 4) {
+ zlog_err(
+ "%s Enhanced Route Refresh message length error",
+ peer->host);
+ bgp_notify_send(
+ peer, BGP_NOTIFY_ROUTE_REFRESH_ERR,
+ BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN);
+ }
+
+ /* When the BGP speaker receives a ROUTE-REFRESH message
+ * with a "Message Subtype" field other than 0, 1, or 2,
+ * it MUST ignore the received ROUTE-REFRESH message.
+ */
+ if (subtype > 2)
+ zlog_err(
+ "%s Enhanced Route Refresh invalid subtype",
+ peer->host);
+ }
+
+ if (msg_length < 5) {
zlog_info("%s ORF route refresh length error",
peer->host);
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
@@ -2116,6 +2206,11 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
peer->orf_plist[afi][safi];
}
+ /* Avoid supressing duplicate routes later
+ * when processing in subgroup_announce_table().
+ */
+ SET_FLAG(paf->subgroup->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+
/* If the peer is configured for default-originate clear the
* SUBGRP_STATUS_DEFAULT_ORIGINATE flag so that we will
* re-advertise the
@@ -2127,6 +2222,124 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
SUBGRP_STATUS_DEFAULT_ORIGINATE);
}
+ if (subtype == BGP_ROUTE_REFRESH_BORR) {
+ /* A BGP speaker that has received the Graceful Restart
+ * Capability from its neighbor MUST ignore any BoRRs for
+ * an <AFI, SAFI> from the neighbor before the speaker
+ * receives the EoR for the given <AFI, SAFI> from the
+ * neighbor.
+ */
+ if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)
+ && !CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s rcvd route-refresh (BoRR) for %s/%s before EoR",
+ peer->host, afi2str(afi),
+ safi2str(safi));
+ return BGP_PACKET_NOOP;
+ }
+
+ if (peer->t_refresh_stalepath) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s rcvd route-refresh (BoRR) for %s/%s, whereas BoRR already received",
+ peer->host, afi2str(afi),
+ safi2str(safi));
+ return BGP_PACKET_NOOP;
+ }
+
+ SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_BORR_RECEIVED);
+ UNSET_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EORR_RECEIVED);
+
+ /* When a BGP speaker receives a BoRR message from
+ * a peer, it MUST mark all the routes with the given
+ * Address Family Identifier and Subsequent Address
+ * Family Identifier, <AFI, SAFI> [RFC2918], from
+ * that peer as stale.
+ */
+ if (peer_active_nego(peer)) {
+ SET_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_ENHANCED_REFRESH);
+ bgp_set_stale_route(peer, afi, safi);
+ }
+
+ if (peer->status == Established)
+ thread_add_timer(bm->master,
+ bgp_refresh_stalepath_timer_expire,
+ paf, peer->bgp->stalepath_time,
+ &peer->t_refresh_stalepath);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s rcvd route-refresh (BoRR) for %s/%s, triggering timer for %u seconds",
+ peer->host, afi2str(afi), safi2str(safi),
+ peer->bgp->stalepath_time);
+ } else if (subtype == BGP_ROUTE_REFRESH_EORR) {
+ if (!peer->t_refresh_stalepath) {
+ zlog_err(
+ "%s rcvd route-refresh (EoRR) for %s/%s, whereas no BoRR received",
+ peer->host, afi2str(afi), safi2str(safi));
+ return BGP_PACKET_NOOP;
+ }
+
+ BGP_TIMER_OFF(peer->t_refresh_stalepath);
+
+ SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EORR_RECEIVED);
+ UNSET_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_BORR_RECEIVED);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s rcvd route-refresh (EoRR) for %s/%s, stopping BoRR timer",
+ peer->host, afi2str(afi), safi2str(safi));
+
+ if (peer->nsf[afi][safi])
+ bgp_clear_stale_route(peer, afi, safi);
+ } else {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s rcvd route-refresh (REQUEST) for %s/%s",
+ peer->host, afi2str(afi), safi2str(safi));
+
+ /* In response to a "normal route refresh request" from the
+ * peer, the speaker MUST send a BoRR message.
+ */
+ if (CHECK_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_RCV)) {
+ /* For a BGP speaker that supports the BGP Graceful
+ * Restart, it MUST NOT send a BoRR for an <AFI, SAFI>
+ * to a neighbor before it sends the EoR for the
+ * <AFI, SAFI> to the neighbor.
+ */
+ if (!CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s rcvd route-refresh (REQUEST) for %s/%s before EoR",
+ peer->host, afi2str(afi),
+ safi2str(safi));
+ return BGP_PACKET_NOOP;
+ }
+
+ bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
+ BGP_ROUTE_REFRESH_BORR);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s sending route-refresh (BoRR) for %s/%s",
+ peer->host, afi2str(afi),
+ safi2str(safi));
+
+ /* Set flag Ready-To-Send to know when we can send EoRR
+ * message.
+ */
+ SET_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_BORR_SEND);
+ UNSET_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EORR_SEND);
+ }
+ }
+
/* Perform route refreshment to the peer */
bgp_announce_route(peer, afi, safi);