diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 112c34a198..653dd7b1be 100644 --- a/bgpd/bgp_fsm.c +++ b/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++; diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index a749f8ea31..bef5e0a596 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -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 */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 62ef86166f..674892515b 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -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", diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 8f0ebe318c..79390ec8a1 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -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 */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 6397c55090..15c3b6eab2 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -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); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 3d2eea51b5..fea18dd299 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -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); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 6ca595c294..5e854d6fb5 100644 --- a/bgpd/bgp_vty.c +++ b/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 */ + { + bgp->v_update_delay = update_delay; + bgp->v_establish_wait = bgp->v_update_delay; + return CMD_SUCCESS; + } + + /* update-delay */ + 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); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 2df8aaa5de..e9dc09a061 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -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 */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 140cb189cc..3c2f82c6be 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -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", diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 73f2849ef5..4fb6afefc0 100644 --- a/bgpd/bgpd.h +++ b/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); diff --git a/doc/bgpd.texi b/doc/bgpd.texi index de709707a7..10fe13ca22 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -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