mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 10:54:47 +00:00
bgpd: bgpd-update-delay.patch
COMMAND: 'update-delay <max-delay in seconds> [<establish-wait in seconds>]' DESCRIPTION: This feature is used to enable read-only mode on BGP process restart or when BGP process is cleared using 'clear ip bgp *'. When applicable, read-only mode would begin as soon as the first peer reaches Established state and a timer for <max-delay> seconds is started. During this mode BGP doesn't run any best-path or generate any updates to its peers. This mode continues until: 1. All the configured peers, except the shutdown peers, have sent explicit EOR (End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached Established is considered an implicit-EOR. If the <establish-wait> optional value is given, then BGP will wait for peers to reach establish from the begining of the update-delay till the establish-wait period is over, i.e. the minimum set of established peers for which EOR is expected would be peers established during the establish-wait window, not necessarily all the configured neighbors. 2. max-delay period is over. On hitting any of the above two conditions, BGP resumes the decision process and generates updates to its peers. Default <max-delay> is 0, i.e. the feature is off by default. This feature can be useful in reducing CPU/network used as BGP restarts/clears. Particularly useful in the topologies where BGP learns a prefix from many peers. Intermediate bestpaths are possible for the same prefix as peers get established and start receiving updates at different times. This feature should offer a value-add if the network has a high number of such prefixes. IMPLEMENTATION OBJECTIVES: Given this is an optional feature, minimized the code-churn. Used existing constructs wherever possible (existing queue-plug/unplug were used to achieve delay and resume of best-paths/update-generation). As a result, no new data-structure(s) had to be defined and allocated. When the feature is disabled, the new node is not exercised for the most part. Signed-off-by: Vipin Kumar <vipin@cumulusnetworks.com> Reviewed-by: Pradosh Mohapatra <pmohapat@cumulusnetworks.com> Dinesh Dutt <ddutt@cumulusnetworks.com>
This commit is contained in:
parent
fe7d2a4834
commit
f188f2c424
176
bgpd/bgp_fsm.c
176
bgpd/bgp_fsm.c
@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "stream.h"
|
||||
#include "memory.h"
|
||||
#include "plist.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
@ -40,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_dump.h"
|
||||
#include "bgpd/bgp_open.h"
|
||||
#include "bgpd/bgp_advertise.h"
|
||||
#ifdef HAVE_SNMP
|
||||
#include "bgpd/bgp_snmp.h"
|
||||
#endif /* HAVE_SNMP */
|
||||
@ -395,6 +397,157 @@ bgp_graceful_stale_timer_expire (struct thread *thread)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bgp_update_delay_applicable (struct bgp *bgp)
|
||||
{
|
||||
/* update_delay_over flag should be reset (set to 0) for any new
|
||||
applicability of the update-delay during BGP process lifetime.
|
||||
And it should be set after an occurence of the update-delay is over)*/
|
||||
if (!bgp->update_delay_over)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bgp_update_delay_active (struct bgp *bgp)
|
||||
{
|
||||
if (bgp->t_update_delay)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bgp_update_delay_configured (struct bgp *bgp)
|
||||
{
|
||||
if (bgp->v_update_delay)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do the post-processing needed when bgp comes out of the read-only mode
|
||||
on ending the update delay. */
|
||||
void
|
||||
bgp_update_delay_end (struct bgp *bgp)
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct peer *peer;
|
||||
|
||||
THREAD_TIMER_OFF (bgp->t_update_delay);
|
||||
THREAD_TIMER_OFF (bgp->t_establish_wait);
|
||||
|
||||
/* Reset update-delay related state */
|
||||
bgp->update_delay_over = 1;
|
||||
bgp->established = 0;
|
||||
bgp->restarted_peers = 0;
|
||||
bgp->implicit_eors = 0;
|
||||
bgp->explicit_eors = 0;
|
||||
|
||||
quagga_timestamp(3, bgp->update_delay_end_time,
|
||||
sizeof(bgp->update_delay_end_time));
|
||||
|
||||
/* Route announcements were postponed for all the peers during read-only mode,
|
||||
send those now. */
|
||||
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
|
||||
bgp_announce_route_all (peer);
|
||||
|
||||
/* Resume the queue processing. This should trigger the event that would take
|
||||
care of processing any work that was queued during the read-only mode. */
|
||||
work_queue_unplug(bm->process_main_queue);
|
||||
work_queue_unplug(bm->process_rsclient_queue);
|
||||
}
|
||||
|
||||
/* The update delay timer expiry callback. */
|
||||
static int
|
||||
bgp_update_delay_timer (struct thread *thread)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
|
||||
zlog_info ("Update delay ended - timer expired.");
|
||||
|
||||
bgp = THREAD_ARG (thread);
|
||||
THREAD_TIMER_OFF (bgp->t_update_delay);
|
||||
bgp_update_delay_end(bgp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The establish wait timer expiry callback. */
|
||||
static int
|
||||
bgp_establish_wait_timer (struct thread *thread)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
|
||||
zlog_info ("Establish wait - timer expired.");
|
||||
|
||||
bgp = THREAD_ARG (thread);
|
||||
THREAD_TIMER_OFF (bgp->t_establish_wait);
|
||||
bgp_check_update_delay(bgp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Steps to begin the update delay:
|
||||
- initialize queues if needed
|
||||
- stop the queue processing
|
||||
- start the timer */
|
||||
static void
|
||||
bgp_update_delay_begin (struct bgp *bgp)
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct peer *peer;
|
||||
|
||||
if ((bm->process_main_queue == NULL) ||
|
||||
(bm->process_rsclient_queue == NULL))
|
||||
bgp_process_queue_init();
|
||||
|
||||
/* Stop the processing of queued work. Enqueue shall continue */
|
||||
work_queue_plug(bm->process_main_queue);
|
||||
work_queue_plug(bm->process_rsclient_queue);
|
||||
|
||||
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
|
||||
peer->update_delay_over = 0;
|
||||
|
||||
/* Start the update-delay timer */
|
||||
THREAD_TIMER_ON (master, bgp->t_update_delay, bgp_update_delay_timer,
|
||||
bgp, bgp->v_update_delay);
|
||||
|
||||
if (bgp->v_establish_wait != bgp->v_update_delay)
|
||||
THREAD_TIMER_ON (master, bgp->t_establish_wait, bgp_establish_wait_timer,
|
||||
bgp, bgp->v_establish_wait);
|
||||
|
||||
quagga_timestamp(3, bgp->update_delay_begin_time,
|
||||
sizeof(bgp->update_delay_begin_time));
|
||||
}
|
||||
|
||||
static void
|
||||
bgp_update_delay_process_status_change(struct peer *peer)
|
||||
{
|
||||
if (peer->status == Established)
|
||||
{
|
||||
if (!peer->bgp->established++)
|
||||
{
|
||||
bgp_update_delay_begin(peer->bgp);
|
||||
zlog_info ("Begin read-only mode - update-delay timer %d seconds",
|
||||
peer->bgp->v_update_delay);
|
||||
}
|
||||
if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV))
|
||||
bgp_update_restarted_peers(peer);
|
||||
}
|
||||
if (peer->ostatus == Established && bgp_update_delay_active(peer->bgp))
|
||||
{
|
||||
/* Adjust the update-delay state to account for this flap.
|
||||
NOTE: Intentionally skipping adjusting implicit_eors or explicit_eors
|
||||
counters. Extra sanity check in bgp_check_update_delay() should
|
||||
be enough to take care of any additive discrepancy in bgp eor
|
||||
counters */
|
||||
peer->bgp->established--;
|
||||
peer->update_delay_over = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Called after event occured, this function change status and reset
|
||||
read/write and timer thread. */
|
||||
void
|
||||
@ -411,7 +564,12 @@ bgp_fsm_change_status (struct peer *peer, int status)
|
||||
/* Preserve old status and change into new status. */
|
||||
peer->ostatus = peer->status;
|
||||
peer->status = status;
|
||||
|
||||
|
||||
/* If update-delay processing is applicable, do the necessary. */
|
||||
if (bgp_update_delay_configured(peer->bgp) &&
|
||||
bgp_update_delay_applicable(peer->bgp))
|
||||
bgp_update_delay_process_status_change(peer);
|
||||
|
||||
if (BGP_DEBUG (normal, NORMAL))
|
||||
zlog_debug ("%s went from %s to %s",
|
||||
peer->host,
|
||||
@ -762,6 +920,17 @@ bgp_fsm_open (struct peer *peer)
|
||||
static int
|
||||
bgp_fsm_keepalive_expire (struct peer *peer)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
|
||||
{
|
||||
if (!FIFO_EMPTY(&peer->sync[afi][safi]->withdraw) ||
|
||||
!FIFO_EMPTY(&peer->sync[afi][safi]->update))
|
||||
return 0;
|
||||
}
|
||||
|
||||
bgp_keepalive_send (peer);
|
||||
return 0;
|
||||
}
|
||||
@ -883,9 +1052,6 @@ bgp_establish (struct peer *peer)
|
||||
REFRESH_IMMEDIATE, 0);
|
||||
}
|
||||
|
||||
if (peer->v_keepalive)
|
||||
bgp_keepalive_send (peer);
|
||||
|
||||
/* First update is deferred until ORF or ROUTE-REFRESH is received */
|
||||
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
|
||||
for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
|
||||
@ -905,6 +1071,8 @@ bgp_establish (struct peer *peer)
|
||||
static int
|
||||
bgp_fsm_keepalive (struct peer *peer)
|
||||
{
|
||||
bgp_update_implicit_eors(peer);
|
||||
|
||||
/* peer count update */
|
||||
peer->keepalive_in++;
|
||||
|
||||
|
@ -77,5 +77,6 @@ extern int bgp_stop (struct peer *peer);
|
||||
extern void bgp_timer_set (struct peer *);
|
||||
extern void bgp_fsm_change_status (struct peer *peer, int status);
|
||||
extern const char *peer_down_str[];
|
||||
extern void bgp_update_delay_end (struct bgp *);
|
||||
|
||||
#endif /* _QUAGGA_BGP_FSM_H */
|
||||
|
@ -439,6 +439,9 @@ bgp_default_update_send (struct peer *peer, struct attr *attr,
|
||||
if (DISABLE_BGP_ANNOUNCE)
|
||||
return;
|
||||
|
||||
if (bgp_update_delay_active(peer->bgp))
|
||||
return;
|
||||
|
||||
if (afi == AFI_IP)
|
||||
str2prefix ("0.0.0.0/0", &p);
|
||||
#ifdef HAVE_IPV6
|
||||
@ -512,6 +515,9 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi)
|
||||
if (DISABLE_BGP_ANNOUNCE)
|
||||
return;
|
||||
|
||||
if (bgp_update_delay_active(peer->bgp))
|
||||
return;
|
||||
|
||||
if (afi == AFI_IP)
|
||||
str2prefix ("0.0.0.0/0", &p);
|
||||
#ifdef HAVE_IPV6
|
||||
@ -1597,6 +1603,116 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called when there is a change in the EOR(implicit or explicit) status of a peer.
|
||||
Ends the update-delay if all expected peers are done with EORs. */
|
||||
void
|
||||
bgp_check_update_delay(struct bgp *bgp)
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct peer *peer;
|
||||
|
||||
if (BGP_DEBUG (normal, NORMAL))
|
||||
zlog_debug ("Checking update delay, T: %d R: %d I:%d E: %d", bgp->established,
|
||||
bgp->restarted_peers, bgp->implicit_eors, bgp->explicit_eors);
|
||||
|
||||
if (bgp->established <=
|
||||
bgp->restarted_peers + bgp->implicit_eors + bgp->explicit_eors)
|
||||
{
|
||||
/* This is an extra sanity check to make sure we wait for all the
|
||||
eligible configured peers. This check is performed if establish wait
|
||||
timer is on, or establish wait option is not given with the
|
||||
update-delay command */
|
||||
if (bgp->t_establish_wait ||
|
||||
(bgp->v_establish_wait == bgp->v_update_delay))
|
||||
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
|
||||
{
|
||||
if (!CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)
|
||||
&& !peer->update_delay_over)
|
||||
{
|
||||
if (BGP_DEBUG (normal, NORMAL))
|
||||
zlog_debug (" Peer %s pending, continuing read-only mode",
|
||||
peer->host);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
zlog_info ("Update delay ended, restarted: %d, EORs implicit: %d, explicit: %d",
|
||||
bgp->restarted_peers, bgp->implicit_eors, bgp->explicit_eors);
|
||||
bgp_update_delay_end(bgp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called if peer is known to have restarted. The restart-state bit in
|
||||
Graceful-Restart capability is used for that */
|
||||
void
|
||||
bgp_update_restarted_peers (struct peer *peer)
|
||||
{
|
||||
if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */
|
||||
if (peer->update_delay_over) return; /* This peer has already been considered */
|
||||
|
||||
if (BGP_DEBUG (normal, NORMAL))
|
||||
zlog_debug ("Peer %s: Checking restarted", peer->host);
|
||||
|
||||
if (peer->status == Established)
|
||||
{
|
||||
peer->update_delay_over = 1;
|
||||
peer->bgp->restarted_peers++;
|
||||
bgp_check_update_delay(peer->bgp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called as peer receives a keep-alive. Determines if this occurence can be
|
||||
taken as an implicit EOR for this peer.
|
||||
NOTE: The very first keep-alive after the Established state of a peer is
|
||||
considered implicit EOR for the update-delay purposes */
|
||||
void
|
||||
bgp_update_implicit_eors (struct peer *peer)
|
||||
{
|
||||
if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */
|
||||
if (peer->update_delay_over) return; /* This peer has already been considered */
|
||||
|
||||
if (BGP_DEBUG (normal, NORMAL))
|
||||
zlog_debug ("Peer %s: Checking implicit EORs", peer->host);
|
||||
|
||||
if (peer->status == Established)
|
||||
{
|
||||
peer->update_delay_over = 1;
|
||||
peer->bgp->implicit_eors++;
|
||||
bgp_check_update_delay(peer->bgp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Should be called only when there is a change in the EOR_RECEIVED status
|
||||
for any afi/safi on a peer */
|
||||
static void
|
||||
bgp_update_explicit_eors (struct peer *peer)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */
|
||||
if (peer->update_delay_over) return; /* This peer has already been considered */
|
||||
|
||||
if (BGP_DEBUG (normal, NORMAL))
|
||||
zlog_debug ("Peer %s: Checking explicit EORs", peer->host);
|
||||
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
|
||||
{
|
||||
if (peer->afc_nego[afi][safi] &&
|
||||
!CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED))
|
||||
{
|
||||
if (BGP_DEBUG (normal, NORMAL))
|
||||
zlog_debug (" afi %d safi %d didnt receive EOR", afi, safi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
peer->update_delay_over = 1;
|
||||
peer->bgp->explicit_eors++;
|
||||
bgp_check_update_delay(peer->bgp);
|
||||
}
|
||||
|
||||
/* Parse BGP Update packet and make attribute object. */
|
||||
static int
|
||||
bgp_update_receive (struct peer *peer, bgp_size_t size)
|
||||
@ -1806,8 +1922,13 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
|
||||
if (! attribute_len && ! withdraw_len)
|
||||
{
|
||||
/* End-of-RIB received */
|
||||
SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST],
|
||||
PEER_STATUS_EOR_RECEIVED);
|
||||
if (!CHECK_FLAG(peer->af_sflags[AFI_IP][SAFI_UNICAST],
|
||||
PEER_STATUS_EOR_RECEIVED))
|
||||
{
|
||||
SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST],
|
||||
PEER_STATUS_EOR_RECEIVED);
|
||||
bgp_update_explicit_eors(peer);
|
||||
}
|
||||
|
||||
/* NSF delete stale route */
|
||||
if (peer->nsf[AFI_IP][SAFI_UNICAST])
|
||||
@ -1836,8 +1957,13 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
|
||||
&& mp_withdraw.length == 0)
|
||||
{
|
||||
/* End-of-RIB received */
|
||||
SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST],
|
||||
PEER_STATUS_EOR_RECEIVED);
|
||||
if (!CHECK_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST],
|
||||
PEER_STATUS_EOR_RECEIVED))
|
||||
{
|
||||
SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST],
|
||||
PEER_STATUS_EOR_RECEIVED);
|
||||
bgp_update_explicit_eors(peer);
|
||||
}
|
||||
|
||||
/* NSF delete stale route */
|
||||
if (peer->nsf[AFI_IP][SAFI_MULTICAST])
|
||||
@ -1866,7 +1992,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
|
||||
&& mp_withdraw.length == 0)
|
||||
{
|
||||
/* End-of-RIB received */
|
||||
SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED);
|
||||
if (!CHECK_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST],
|
||||
PEER_STATUS_EOR_RECEIVED))
|
||||
{
|
||||
SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED);
|
||||
bgp_update_explicit_eors(peer);
|
||||
}
|
||||
|
||||
/* NSF delete stale route */
|
||||
if (peer->nsf[AFI_IP6][SAFI_UNICAST])
|
||||
@ -1895,6 +2026,13 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
|
||||
&& mp_withdraw.length == 0)
|
||||
{
|
||||
/* End-of-RIB received */
|
||||
if (!CHECK_FLAG (peer->af_sflags[AFI_IP6][SAFI_MULTICAST],
|
||||
PEER_STATUS_EOR_RECEIVED))
|
||||
{
|
||||
SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_MULTICAST], PEER_STATUS_EOR_RECEIVED);
|
||||
bgp_update_explicit_eors(peer);
|
||||
}
|
||||
|
||||
|
||||
/* NSF delete stale route */
|
||||
if (peer->nsf[AFI_IP6][SAFI_MULTICAST])
|
||||
@ -1923,6 +2061,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
|
||||
&& mp_withdraw.length == 0)
|
||||
{
|
||||
/* End-of-RIB received */
|
||||
if (!CHECK_FLAG (peer->af_sflags[AFI_IP][SAFI_MPLS_VPN],
|
||||
PEER_STATUS_EOR_RECEIVED))
|
||||
{
|
||||
SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MPLS_VPN], PEER_STATUS_EOR_RECEIVED);
|
||||
bgp_update_explicit_eors(peer);
|
||||
}
|
||||
|
||||
if (BGP_DEBUG (update, UPDATE_IN))
|
||||
zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s",
|
||||
|
@ -53,5 +53,7 @@ extern void bgp_default_update_send (struct peer *, struct attr *,
|
||||
extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t);
|
||||
|
||||
extern int bgp_capability_receive (struct peer *, bgp_size_t);
|
||||
|
||||
extern void bgp_update_restarted_peers (struct peer *);
|
||||
extern void bgp_update_implicit_eors (struct peer *);
|
||||
extern void bgp_check_update_delay (struct bgp *);
|
||||
#endif /* _QUAGGA_BGP_PACKET_H */
|
||||
|
@ -1664,7 +1664,7 @@ bgp_processq_del (struct work_queue *wq, void *data)
|
||||
XFREE (MTYPE_BGP_PROCESS_QUEUE, pq);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
bgp_process_queue_init (void)
|
||||
{
|
||||
bm->process_main_queue
|
||||
@ -2605,9 +2605,19 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
|
||||
if (! table)
|
||||
table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi];
|
||||
|
||||
if (safi != SAFI_MPLS_VPN
|
||||
&& CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
|
||||
bgp_default_originate (peer, afi, safi, 0);
|
||||
if (safi != SAFI_MPLS_VPN)
|
||||
{
|
||||
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
|
||||
{
|
||||
bgp_default_originate (peer, afi, safi, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Send the withdraw if it was postponed during read-only mode. */
|
||||
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE))
|
||||
bgp_default_originate (peer, afi, safi, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* It's initialized in bgp_announce_[check|check_rsclient]() */
|
||||
attr.extra = &extra;
|
||||
@ -2659,6 +2669,9 @@ bgp_announce_route_all (struct peer *peer)
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
if (bgp_update_delay_active(peer->bgp))
|
||||
return;
|
||||
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
|
||||
bgp_announce_route (peer, afi, safi);
|
||||
|
@ -170,6 +170,7 @@ enum bgp_clear_route_type
|
||||
};
|
||||
|
||||
/* Prototypes. */
|
||||
extern void bgp_process_queue_init (void);
|
||||
extern void bgp_route_init (void);
|
||||
extern void bgp_route_finish (void);
|
||||
extern void bgp_cleanup_routes (void);
|
||||
|
138
bgpd/bgp_vty.c
138
bgpd/bgp_vty.c
@ -692,6 +692,108 @@ bgp_maxpaths_config_vty (struct vty *vty, int peer_type, char *mpaths,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
bgp_update_delay_config_vty (struct vty *vty, const char *delay,
|
||||
const char *wait)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
u_int16_t update_delay;
|
||||
u_int16_t establish_wait;
|
||||
|
||||
|
||||
bgp = vty->index;
|
||||
|
||||
VTY_GET_INTEGER_RANGE ("update-delay", update_delay, delay,
|
||||
BGP_UPDATE_DELAY_MIN, BGP_UPDATE_DELAY_MAX);
|
||||
|
||||
if (!wait) /* update-delay <delay> */
|
||||
{
|
||||
bgp->v_update_delay = update_delay;
|
||||
bgp->v_establish_wait = bgp->v_update_delay;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* update-delay <delay> <establish-wait> */
|
||||
establish_wait = atoi (wait);
|
||||
if (update_delay < establish_wait)
|
||||
{
|
||||
vty_out (vty, "%%Failed: update-delay less than the establish-wait!%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
bgp->v_update_delay = update_delay;
|
||||
bgp->v_establish_wait = establish_wait;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
bgp_update_delay_deconfig_vty (struct vty *vty)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
|
||||
bgp = vty->index;
|
||||
|
||||
bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
|
||||
bgp->v_establish_wait = bgp->v_update_delay;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
bgp_config_write_update_delay (struct vty *vty, struct bgp *bgp)
|
||||
{
|
||||
if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF)
|
||||
{
|
||||
vty_out (vty, " update-delay %d", bgp->v_update_delay);
|
||||
if (bgp->v_update_delay != bgp->v_establish_wait)
|
||||
vty_out (vty, " %d", bgp->v_establish_wait);
|
||||
vty_out (vty, "%s", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Update-delay configuration */
|
||||
DEFUN (bgp_update_delay,
|
||||
bgp_update_delay_cmd,
|
||||
"update-delay <0-3600>",
|
||||
"Force initial delay for best-path and updates\n"
|
||||
"Seconds\n")
|
||||
{
|
||||
return bgp_update_delay_config_vty(vty, argv[0], NULL);
|
||||
}
|
||||
|
||||
DEFUN (bgp_update_delay_establish_wait,
|
||||
bgp_update_delay_establish_wait_cmd,
|
||||
"update-delay <0-3600> <1-3600>",
|
||||
"Force initial delay for best-path and updates\n"
|
||||
"Seconds\n"
|
||||
"Wait for peers to be established\n"
|
||||
"Seconds\n")
|
||||
{
|
||||
return bgp_update_delay_config_vty(vty, argv[0], argv[1]);
|
||||
}
|
||||
|
||||
/* Update-delay deconfiguration */
|
||||
DEFUN (no_bgp_update_delay,
|
||||
no_bgp_update_delay_cmd,
|
||||
"no update-delay <0-3600>",
|
||||
"Force initial delay for best-path and updates\n"
|
||||
"Seconds\n")
|
||||
{
|
||||
return bgp_update_delay_deconfig_vty(vty);
|
||||
}
|
||||
|
||||
ALIAS (no_bgp_update_delay,
|
||||
no_bgp_update_delay_establish_wait_cmd,
|
||||
"no update-delay <0-3600> <1-3600>",
|
||||
"Force initial delay for best-path and updates\n"
|
||||
"Seconds\n"
|
||||
"Wait for peers to be established\n"
|
||||
"Seconds\n")
|
||||
|
||||
/* Maximum-paths configuration */
|
||||
DEFUN (bgp_maxpaths,
|
||||
@ -4353,6 +4455,11 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
|
||||
if (ret < 0)
|
||||
bgp_clear_vty_error (vty, peer, afi, safi, ret);
|
||||
}
|
||||
|
||||
/* This is to apply read-only mode on this clear. */
|
||||
if (stype == BGP_CLEAR_SOFT_NONE)
|
||||
bgp->update_delay_over = 0;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -6964,6 +7071,30 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
|
||||
vty_out (vty,
|
||||
"BGP router identifier %s, local AS number %u%s",
|
||||
inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE);
|
||||
if (bgp_update_delay_configured(bgp))
|
||||
{
|
||||
vty_out (vty, "Read-only mode update-delay limit: %d seconds%s",
|
||||
bgp->v_update_delay, VTY_NEWLINE);
|
||||
if (bgp->v_update_delay != bgp->v_establish_wait)
|
||||
vty_out (vty, " Establish wait: %d seconds%s",
|
||||
bgp->v_establish_wait, VTY_NEWLINE);
|
||||
if (bgp_update_delay_active(bgp))
|
||||
{
|
||||
vty_out (vty, " First neighbor established: %s%s",
|
||||
bgp->update_delay_begin_time, VTY_NEWLINE);
|
||||
vty_out (vty, " Delay in progress%s", VTY_NEWLINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bgp->update_delay_over)
|
||||
{
|
||||
vty_out (vty, " First neighbor established: %s%s",
|
||||
bgp->update_delay_begin_time, VTY_NEWLINE);
|
||||
vty_out (vty, " Best-paths/updates resumed: %s%s",
|
||||
bgp->update_delay_end_time, VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ents = bgp_table_count (bgp->rib[afi][safi]);
|
||||
vty_out (vty, "RIB entries %ld, using %s of memory%s", ents,
|
||||
@ -7045,6 +7176,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
|
||||
else
|
||||
vty_out (vty, "No %s neighbor is configured%s",
|
||||
afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -9169,6 +9301,12 @@ bgp_vty_init (void)
|
||||
install_element (BGP_NODE, &bgp_confederation_peers_cmd);
|
||||
install_element (BGP_NODE, &no_bgp_confederation_peers_cmd);
|
||||
|
||||
/* bgp update-delay command */
|
||||
install_element (BGP_NODE, &bgp_update_delay_cmd);
|
||||
install_element (BGP_NODE, &no_bgp_update_delay_cmd);
|
||||
install_element (BGP_NODE, &bgp_update_delay_establish_wait_cmd);
|
||||
install_element (BGP_NODE, &no_bgp_update_delay_establish_wait_cmd);
|
||||
|
||||
/* "maximum-paths" commands. */
|
||||
install_element (BGP_NODE, &bgp_maxpaths_cmd);
|
||||
install_element (BGP_NODE, &no_bgp_maxpaths_cmd);
|
||||
|
@ -25,5 +25,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
|
||||
extern void bgp_vty_init (void);
|
||||
extern const char *afi_safi_print (afi_t, safi_t);
|
||||
extern int bgp_config_write_update_delay (struct vty *, struct bgp *);
|
||||
|
||||
#endif /* _QUAGGA_BGP_VTY_H */
|
||||
|
@ -1973,6 +1973,7 @@ bgp_create (as_t *as, const char *name)
|
||||
bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS;
|
||||
}
|
||||
|
||||
bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
|
||||
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
|
||||
bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
|
||||
bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
|
||||
@ -5307,6 +5308,9 @@ bgp_config_write (struct vty *vty)
|
||||
if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
|
||||
vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE);
|
||||
|
||||
/* BGP update-delay. */
|
||||
bgp_config_write_update_delay (vty, bgp);
|
||||
|
||||
/* BGP graceful-restart. */
|
||||
if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
|
||||
vty_out (vty, " bgp graceful-restart stalepath-time %d%s",
|
||||
|
21
bgpd/bgpd.h
21
bgpd/bgpd.h
@ -106,6 +106,22 @@ struct bgp
|
||||
|
||||
struct thread *t_startup;
|
||||
|
||||
/* BGP update delay on startup */
|
||||
struct thread *t_update_delay;
|
||||
struct thread *t_establish_wait;
|
||||
u_char update_delay_over;
|
||||
u_int16_t v_update_delay;
|
||||
u_int16_t v_establish_wait;
|
||||
char update_delay_begin_time[64];
|
||||
char update_delay_end_time[64];
|
||||
u_int32_t established;
|
||||
u_int32_t restarted_peers;
|
||||
u_int32_t implicit_eors;
|
||||
u_int32_t explicit_eors;
|
||||
#define BGP_UPDATE_DELAY_DEF 0
|
||||
#define BGP_UPDATE_DELAY_MIN 0
|
||||
#define BGP_UPDATE_DELAY_MAX 3600
|
||||
|
||||
/* BGP flags. */
|
||||
u_int16_t flags;
|
||||
#define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0)
|
||||
@ -507,6 +523,9 @@ struct peer
|
||||
u_int32_t established; /* Established */
|
||||
u_int32_t dropped; /* Dropped */
|
||||
|
||||
/* Update delay related fields */
|
||||
u_char update_delay_over; /* When this is set, BGP is no more waiting for EOR */
|
||||
|
||||
/* Syncronization list and time. */
|
||||
struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX];
|
||||
time_t synctime;
|
||||
@ -899,6 +918,8 @@ extern int bgp_timers_unset (struct bgp *);
|
||||
extern int bgp_default_local_preference_set (struct bgp *, u_int32_t);
|
||||
extern int bgp_default_local_preference_unset (struct bgp *);
|
||||
|
||||
extern int bgp_update_delay_active (struct bgp *);
|
||||
extern int bgp_update_delay_configured (struct bgp *);
|
||||
extern int peer_rsclient_active (struct peer *);
|
||||
|
||||
extern int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t);
|
||||
|
@ -223,6 +223,30 @@ Redistribute RIP route to BGP process.
|
||||
Redistribute OSPF route to BGP process.
|
||||
@end deffn
|
||||
|
||||
@deffn {BGP} {update-delay @var{max-delay}} {}
|
||||
@deffnx {BGP} {update-delay @var{max-delay} @var{establish-wait}} {}
|
||||
This feature is used to enable read-only mode on BGP process restart or when
|
||||
BGP process is cleared using 'clear ip bgp *'. When applicable, read-only mode
|
||||
would begin as soon as the first peer reaches Established status and a timer
|
||||
for max-delay seconds is started.
|
||||
|
||||
During this mode BGP doesn't run any best-path or generate any updates to its
|
||||
peers. This mode continues until:
|
||||
1. All the configured peers, except the shutdown peers, have sent explicit EOR
|
||||
(End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached
|
||||
Established is considered an implicit-EOR.
|
||||
If the establish-wait optional value is given, then BGP will wait for
|
||||
peers to reach established from the begining of the update-delay till the
|
||||
establish-wait period is over, i.e. the minimum set of established peers for
|
||||
which EOR is expected would be peers established during the establish-wait
|
||||
window, not necessarily all the configured neighbors.
|
||||
2. max-delay period is over.
|
||||
On hitting any of the above two conditions, BGP resumes the decision process
|
||||
and generates updates to its peers.
|
||||
|
||||
Default max-delay is 0, i.e. the feature is off by default.
|
||||
@end deffn
|
||||
|
||||
@node BGP Peer
|
||||
@section BGP Peer
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user