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:
Donald Sharp 2015-05-19 17:40:33 -07:00
parent fe7d2a4834
commit f188f2c424
11 changed files with 531 additions and 14 deletions

View File

@ -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++;

View File

@ -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 */

View File

@ -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",

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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",

View File

@ -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);

View File

@ -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