#include "stream.h"
#include "memory.h"
#include "plist.h"
+#include "workqueue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
#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 */
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
/* 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,
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;
}
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++)
static int
bgp_fsm_keepalive (struct peer *peer)
{
+ bgp_update_implicit_eors(peer);
+
/* peer count update */
peer->keepalive_in++;
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 */
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
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
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)
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])
&& 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])
&& 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])
&& 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])
&& 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",
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 */
XFREE (MTYPE_BGP_PROCESS_QUEUE, pq);
}
-static void
+void
bgp_process_queue_init (void)
{
bm->process_main_queue
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;
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);
};
/* 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);
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,
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;
}
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,
else
vty_out (vty, "No %s neighbor is configured%s",
afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
+
return CMD_SUCCESS;
}
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);
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 */
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;
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",
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)
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;
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);
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