summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Hall <GMCH@hestia.halldom.com>2010-07-19 21:12:58 +0100
committerChris Hall <GMCH@hestia.halldom.com>2010-07-19 21:12:58 +0100
commit378deb2ebf5b34c053f212e14aa0c9d62c4bc85d (patch)
tree529ac933446e4541cca11882df1fdd418a155b61
parentdb0632a8aeb717cb715c444ae203f38ec42a92e6 (diff)
downloadquagga-378deb2ebf5b34c053f212e14aa0c9d62c4bc85d.tar.bz2
quagga-378deb2ebf5b34c053f212e14aa0c9d62c4bc85d.tar.xz
Reworking of peer state handling.
This fixes a reported assert() in 'no neighbor xxx'. It also fixes other issues found when reviewing and testing that. Also fixed is a reported segfault caused by prefix lists without explicit sequence numbers. Peer State ========== Tightened up the peer state handling, including: * shades of pIdle -- depending on some peer flags and the session, if any * state transitions -- particularly pEstablished -> pIdle or pClearing * handling if deleting peer and associated session * handling of PEER_DOWN_XXX -- why peer was last downed * handling of last NOTIFICATION sent/received RS Client RIBs ============== Cleared up places where RS Client RIBs were not disposed of properly when a peer's afi/safi state changed, in particular: -- when deactivating an afi/safi -- when unsetting the rs client state for an afi/safi -- when binding a peer to a group for an afi/safi In the past these issues were probably invisible, except for a slight leak of memory. With the newer code these issues triggered some asserts when closing down a peer or the entire program. Program Termination =================== Now terminates by deleting all peers -- essentially 'no neighbor' for all peers. Each time a peer is set to be deleted bm->peer_linger_count is incremented, when the peer finally is deleted, the count is decremented. So while in program_terminating state, all nexuses continue to run until the Routing Engine spots that there are no peers left to delete. Then all nexuses are shut down and the program finally terminates. To do this, when termination starts a new Routing Engine foreground task is added, which calls program_terminate_if_all_peers_deleted(). Accept() Status for Session =========================== The accept() code needs to find the session associated with the incoming IP address. Then it needs to see if can accept the incoming connection. It looks up the IP address in the Peer Index (under its Mutex). Previously: the Peer Index entry contained a pointer to the accepting connection (if any), and the session had a pointer to the Peer Index entry so that it could set/clear the accept field in that entry. Now: have removed the accept field in the Peer Index entry, and the pointer from the session to that entry. There is now an "accept" flag in the session structure -- so setting/clearing accept does not have to fiddle with any state to do with the peer. Which seems cleaner. To find the session, the accept() code goes via the Peer Index and then via the peer to find the session. This is done under the Peer Index Mutex. To support that, the Routing Engine only changes the peer->session pointer under the same Mutex. General Changes =============== 1. name changes: peer_lock -> bgp_peer_lock etc. 2. bgp_notify_send -> bgp_peer_down_error bgp_notify_send_with_data -> bgp_peer_down_error_with_data 3. name changes: bgp_peer_sIdle -> bgp_peer_pIdle etc. 4. changing int to bool 5. added "received" flag to bgp_notify structure Files Affected ============== configure.ac -- set version to 0.99.15ex02 bgpd/bgp.h -- format changes only bgpd/bgp_advertise.c -- (1) bgpd/bgp_attr.c -- (2) bgpd/bgp_common.h -- (3) bgpd/bgp_connection.c -- (4) for session->active - adding session->accept flag - removing peer index accept entry - adding bgp_connection_query_accept() bgpd/bgp_connection.h -- adding bgp_connection_query_accept() bgpd/bgp_debug.c -- (3) (5) - changed bgp_notify_print() to remove "sending" parameter and use (5) bgpd/bgp_debug.h -- changed bgp_notify_print() bgpd/bgp_fsm.c -- added TODO for NSF and for CollisionDetectEstablishedState bgpd/bgp_main.c -- (4) for various flags - added static bool program_terminating - used "mqb_priority" name instead of "1" - ignore SIGHUP and SIGTERM messages once is "program_terminating" - added program_terminate_if_all_peers_deleted() - in SIGTERM: set program_terminating and add the foreground hook. bgpd/bgp_mplsvpn.c -- (3) bgpd/bgp_msg_read.c -- (5) set the "received" flag on incoming notifications - update call of bgp_notify_print() bgpd/bgp_msg_write.c -- update call of bgp_notify_print() bgpd/bgp_network.c -- (4) bgpd/bgp_nexthop.c -- (3) bgpd/bgp_notification.c -- add "received" flag to notification structure, which is false by default. bgpd/bgp_notification.h -- add "received" flag to notification structure - add bgp_notify_set_received() - add bgp_notify_get_received() bgpd/bgp_open.c -- (2) bgpd/bgp_open_state.c -- in bgp_peer_open_state_receive(): - copy the session->hold_timer_interval and session->keepalive_timer_interval values (as negotiated by the BGP Engine) into the peer - set PEER_CAP_RESTART_RCV if have - fix typo, use: open_recv->can_preserve not: open_recv->can_g_restart bgpd/bgp_packet.c -- delete bgp_notify_send() and bgp_notify_send_with_data() - (1) (2) (3) - bgp_clear_route_normal() -> bgp_clear_routes() and now returns "completed" state. bgpd/bgp_packet.h -- delete: bgp_keepalive_send() bgp_open_send() bgp_notify_send() bgp_notify_send_with_data() bgpd/bgp_peer.c -- changed: bgp_session_has_established() bgp_session session() bgp_session_has_disabled() to void and to take session, not peer. - removed lock of session structure in bgp_session_do_event() -- was holding the lock for far longer than necessary, particularly when clearing routes ! - in bgp_session_has_established(): - lock session structure where and only where required - tidied up timer handling - in bgp_session_has_stopped(): - extend IdleHoldTime - examine notification etc to see why session came down. - invoke bgp_peer_down_notify(), which will start the process of downing the peer. - in bgp_session_has_disabled(): - removed defer_enable - removed calls to bgp_peer_stop() etc. That is done in bgp_peer_down() et all. - now if session is marked delete_me, then do that; otherwise, can enable again. - removed program_terminate_if_all_disabled(), replaced by new mechanism - in bgp_peer_stop(): - changed to void function and added nsf parameter. - sets pClearing state. - MUST now only be called when pEstablished. - removed some code to bgp_peer_reset_idle(). So... bgp_peer_stop() brings pEstablished peer to halt, while bgp_peer_reset_idle() prepares it for new session. - now passes nsf to bgp_clear_all_routes(), which returns flag to say whether task is complete or whether it continues in background. - clearing of NSF_MODE and flags moved to bgp_peer_reset_idle(). - sets pIdle state if route clearing completed - renamed peer_nsf_stop() -> bgp_peer_nsf_stop() - if is pIdle or pClearing and have NSF routes, then stops timers and clears out all the NSF routes. - added bgp_peer_clear_all_stale_routes() - added bgp_peer_shutdown() -- used when peer is downed for PEER_DOWN_USER_SHUTDOWN ! - added bgp_peer_reset_idle() -- used when peer goes pIdle or is about to enable session. - deleted bgp_peer_timers_stop() -- see bgp_peer_change_status(). - replaced bgp_peer_clearing_completed() - if pClearing, sets pIdle and enables if can - if pDeleting, unlocks peer - replaced bgp_timer_set() by bgp_peer_timers_set() -- deals in new peer states only. - renamed peer_new() -> bgp_peer_new() - renamed peer_create() -> bgp_peer_create() - added setting of PEER_STATUS_REAL_PEER - changed auto activation to reflect what actually happens. - changed bgp_session_init_new() call because it now sets peer->session. - sets timers suitable for pIdle. before any auto enable. - renamed peer_delete() -> bgp_peer_delete() - removed call of peer_nsf_stop() - added bgp_peer_down() with PEER_DOWN_NEIGHBOR_DELETE -- which does all the work of flattening an active peer, and returns it pIdle or pClearing. - if pClearing, lock the peer so that when clearing completes, it can unlock it. - sets pDeleting state, and increments bm->peer_linger_count. - tightened procedure for dealing with various references to peer -- including use of the PEER_STATUS_REAL_PEER flag. - tidied up dealing with rsclient RIBs and shared pointers to group versions of same. - removed call of bgp_timer_set(), now done in bgp_peer_change_status(). - now unregisters the peer immediately, so can register a new one before this one is completely deleted. - deletes session if it can. - moved peer_lock() & peer_unlock() from bgpd.c and renamed bgp_peer_lock() & bgp_peer_unlock() - renamed peer_free() bgp_peer_free() and made static. - peer must be pDeleting -- so have been through bgp_peer_delete() - peer->session must be NULL - decrements bm->peer_linger_count - deleted peer->clear_node_queue handling - deleted bgp_session_free() -- that's done in bgp_peer_delete() or elsewhere. - unlocked bgp at end - assert peer->session == NULL, to be sure - set peer->lock == -54321 - in bgp_peer_enable(): - recast as switch() on peer state - added bgp_peer_reset)idle() before enabling the session. - renamed bgp_peer_disable() -> bgp_peer_down() - takes PEER_DOWN_XXX argument, which drives what notification is sent, and sets the peer->last_reset status. A small number of PEER_DOWN_XXX are special. - removed the IdleHoldTimer stuff. - copies outbound notification to session. - for PEER_DOWN_NSF_CLOSE_SESSION, keep non- stale routes. - for PEER_DOWN_USER_SHUTDOWN, do bgp_peer_shutdown() - after disabling any session and doing any shutdown, proceed as per peer->status: pIdle -- flush stale routes bgp_peer_enable() pEstablished -- bgp_peer_stop() pClearing -- flush stale routes - added bgp_peer_down_notify(). - added bgp_peer_down_error(), which replaces bgp_notify_send(). - added bgp_peer_down_error_with_data(), which replaces bgp_notify_send_with_data() The "down_error" functions calculate the appropriate PEER_DOWN_XXX value, and call bgp_peer_down_notify(). - added bgp_peer_map_peer_down(), to map PEER_DOWN_XXX to a notification message. - added bgp_peer_map_notification, to map notification message to a PEER_DOWN_XXX. - renamed peer_change_status() -> bgp_peer_change_status() - do most things only if state changes. - add call to bgp_peer_reset_idle() as enter pIdle state. - at all times do bgp_peer_timer_set() - renamed peer_timers_set() -> bgp_peer_timers_set() - commoned up code for Graceful Restart and Graceful Restart Stale timers and stale routes. - changed Graceful Restart Stale time to cope if it should expire before Graceful Restart ! bgpd/bgp_peer.h -- added PEER_DOWN_XXX values and tidied up + PEER_DOWN_NULL + PEER_DOWN_UNSPECIFIED + PEER_DOWN_CONFIG_CHANGE + PEER_DOWN_AF_DEACTIVATE + PEER_DOWN_PASSWORD_CHANGE + PEER_DOWN_ALLOWAS_IN_CHANGE + PEER_DOWN_INTERFACE_DOWN + PEER_DOWN_MAX_PREFIX + PEER_DOWN_HEADER_ERROR + PEER_DOWN_OPEN_ERROR + PEER_DOWN_UPDATE_ERROR + PEER_DOWN_HOLD_TIMER + PEER_DOWN_FSM_ERROR + PEER_DOWN_DYN_CAP_ERROR - PEER_DOWN_NOTIFY_SEND (deleted) - added typedef peer_down_t - struct peer: - deleted redundant clear_node_queue - removed PEER_STATUS_ACCEPT_PEER flag - added PEER_STATUS_REAL_PEER flag - (3) - deleted bgp_peer_reenable() -- redundant - deleted bgp_peer_stop() -- now static - replaced bgp_peer_disable() by bgp_peer_down() - added bgp_peer_down_error() - added bgp_peer_down_error_with_data() - deleted peer_change_status() -- now static - renamed peer_new() -> bgp_peer_new() - renamed peer_create() -> bgp_peer_create() - renamed peer_delete() -> bgp_peer_delete() - added bgp_peer_lock() - added bgp_peer_unlock() - deleted peer_free() - deleted peer_nsf_stop() bgpd/bgp_peer_index.c -- removed accept entry from bgp_peer_index_entry structure - added explicit next_free entry to the structure - sets next_free to point at self in entries which are in use -- and checks this. - change bgp_peer_index_seek_accept() to link to session via the peer data structure, and to call bgp_connection_query_accept() under the Peer Index Mutex. - (4) for bgp_peer_index_seek_accept() bgpd/bgp_peer_index.h -- removed accept entry from bgp_peer_index_entry structure - added explicit next_free entry to the structure - (4) for bgp_peer_index_seek_accept() bgpd/bgp_route.c -- (1) (2) (3) - in bgp_process_rsclient(), bgp_process_main(), and bgp_processq_del(): - extra dasserts() - clear rn->wq_next - unlock table *after* unlock node (bug fix) - in bgp_process(), lock bgp before table. - in bgp_maximum_prefix_restart_timer(), replace call of peer_clear() by unset of flag and bgp_peer_enable() -- peer is already down. - added bgp_maximum_prefix_cancel_timer() - deleted bgp_clear_this_route() -- code now inline in only caller. - renamed bgp_clear_route_normal() -> bgp_clear_routes() - takes an "nsf" argument to invoke NSF "clearing", iff nsf set for afi/safi. Sets PEER_STATUS_NSF_WAIT if so. - returns bool "completed" if clearing has completed immediately -- ie no background work left to be done. - renamed bgp_clear_route_all() -> bgp_clear_all_routes() - takes "nsf" argument and returns "completed" as for bgp_clear_routes(). - removed call: bgp_peer_clearing_completed() - renamed bgp_clear_route_rsclient() -> bgp_clear_rsclient_rib() - deleted bgp_cleanup_routes() -- was used during termination, no longer required because termination deletes all peers. bgpd/bgp_route.h -- deleted bgp_cleanup_routes() -- program termination now deletes all peers, which implicitly cleans up all routes. - renamed: bgp_clear_route_normal() -> bgp_clear_routes() - renamed: bgp_clear_route_rsclient() -> bgp_clear_rsclient_rib() - renamed: bgp_clear_route_all() -> bgp_clear_all_routes() - added: bgp_maximum_prefix_cancel_timer() bgpd/bgp_session.c -- (3) - deleted bgp_session_defer_if_limping() - in bgp_session_init_new() - changed to void and removed session argument -- always creates a new session - peer MUST not have a session - removed Peer Index pointer stuff as Peer Index no longer has accept field - sets session->peer and locks peer - sets peer->session under Peer Index Mutex - sets session->delete_me false - sets session->accept flag false - replaced bgp_session_free() by bgp_session_delete() - changed to void function - if session is active, set the delete_me flag so session will be deleted when goes sDisabled. - make sure that session Mutex has been released by the BGP Engine before destroying it... otherwise: tears. - unhook session from peer under Peer Index mutex -- for accept() stuff. - unhook peer from session. - unlock peer. - in bgp_session_enable() - assert that peer is pIdle. - clear delete_me for completeness - clear additional fields - in bgp_session_disable() - clear session->accept - in bgp_session_is_active() - no longer interested in Peer Index stuff - deleted bgp_session_defer_if_limping() bgpd/bgp_session.h -- in bgp_session structure: - removed index_entry pointer to Peer Index - added delete_me flag - removed defer_enable flag - added accept flag - removed session parameter from bgp_session_init_new() - deleted bgp_session_free() - added bgp_session_delete() - bgp_session_is_active() now returns bool bgpd/bgp_table.c -- bgp_node_free() sets lock count = -54321 - in bgp_table_free(): - assert that route node is empty - set lock count = -54321 - bgp_node_delete() asserts that is not on_wq - (1) bgpd/bgp_vty.c -- (1) (3) (4) - change peer_af_flag_modify_vty() to call peer_af_flag_modify() not set or unset. - change name: bgp_clear_route_rsclient() -> bgp_clear_rsclient_rib() - in peer_rsclient_set_vty(): - add peer to bgp->rsclient list after all validation is complete - in peer_rsclient_unset_vty(): - removed code for deleting the rsclient RIB etc to peer_rsclient_unset(). - added peer_rsclient_unset() bgpd/bgp_zebra.c -- bgp_peer_disable() -> bgp_peer_down() and now takes PEER_DOWN_INTERFACE_DOWN argument. bgpd/bgpd.c -- (1) (3) - replaced setting peer->last_reset and call of bgp_notify_send() by call of the new bgp_peer_down(). - bgp_router_id_set() ... PEER_DOWN_RID_CHANGE - bgp_cluster_id_set() ... PEER_DOWN_CLID_CHANGE - bgp_cluster_id_unset() ... PEER_DOWN_CLID_CHANGE - bgp_confederation_id_set() ... PEER_DOWN_CONFED_ID_CHANGE ... PEER_DOWN_CONFED_ID_CHANGE - bgp_confederation_id_unset() ... PEER_DOWN_CONFED_ID_CHANGE - bgp_confederation_peers_add() ... PEER_DOWN_CONFED_PEER_CHANGE - bgp_confederation_peers_remove() ... PEER_DOWN_CONFED_PEER_CHANGE - peer_as_change() ... PEER_DOWN_REMOTE_AS_CHANGE - peer_activate() ... PEER_DOWN_AF_ACTIVATE - peer_deactivate() ... PEER_DOWN_AF_DEACTIVATE - peer_group_bind() ... PEER_DOWN_RMAP_BIND - peer_group_unbind() ... PEER_DOWN_RMAP_UNBIND - peer_change_action() ... why_changed ... why_changed - peer_flag_modify_action() ... action->peer_down - peer_update_source_if_set() ... PEER_DOWN_UPDATE_SOURCE_CHANGE ... PEER_DOWN_UPDATE_SOURCE_CHANGE - peer_update_source_addr_set() ... PEER_DOWN_UPDATE_SOURCE_CHANGE ... PEER_DOWN_UPDATE_SOURCE_CHANGE - peer_update_source_unset() ... PEER_DOWN_UPDATE_SOURCE_CHANGE ... PEER_DOWN_UPDATE_SOURCE_CHANGE - peer_local_as_set() ... PEER_DOWN_LOCAL_AS_CHANGE ... PEER_DOWN_LOCAL_AS_CHANGE - peer_local_as_unset() ... PEER_DOWN_LOCAL_AS_CHANGE ... PEER_DOWN_LOCAL_AS_CHANGE - peer_password_set() ... PEER_DOWN_PASSWORD_CHANGE ... PEER_DOWN_PASSWORD_CHANGE - peer_password_unset() ... PEER_DOWN_PASSWORD_CHANGE ... PEER_DOWN_PASSWORD_CHANGE - peer_clear() ... PEER_DOWN_USER_RESET - bgp_terminate() ... PEER_DOWN_USER_RESET - deleted peer_lock() & peer_unlock(). See bgp_peer_lock() & bgp_peer_unlock() in bgp_peer - in peer_as_change(), move downing of peer to after all config changes have been made. - in peer_remote_as() implicitly activate iff !BGP_FLAG_NO_DEFAULT and is IPv4/Unicast. (but only ever called with IPv4/Unicast or nothing at all.) - in peer_deactivate() - if cannot dynamically reconfigure, then will down the peer PEER_DOWN_AF_DEACTIVATE. - uses new peer_rsclient_unset() to tidy away any rsclient RIB etc. - in peer_change_action(): - added 'why_down' argument - replace if's by switch() - in struct peer_flag_action, updated entry types - in peer_flag_action_list[], added the appropriate PEER_DOWN_XXX values. - in peer_af_flag_action_list[] - added the appropriate PEER_DOWN_XXX values - added multiple flag entries - in peer_flag_action_set(): - changed to return const address of peer_flag_action structure -- or NULL. - table may now contain entries which the given flag must be a subset of. - in peer_flag_modify_action(): - now takes peer_flag_action* and whether flag has been set or not. - allow *only* peer_change_none or peer_change_reset - deal with clearing PEER_FLAG_SHUTDOWN, otherwise bgp_peer_down(). - in peer_group_bind(): - uses new peer_rsclient_unset() to tidy away any rsclient RIB etc. - in peer_flag_modify(): - takes bool set flag - changed to suit peer_flag_action_set() and peer_flag_modify_action() - in peer_flag_set() and peer_flag_unset() changed to bool flag - added peer_af_flag_modify_action(), common code for use in peer_af_flag_modify(). - in peer_af_flag_modify(): - takes bool set flag - changed to suit peer_flag_action_set() and peer_flag_modify_action() - use peer_af_flag_modify_action() - in peer_af_flag_set() and peer_af_flag_unset() changed to bool flag - in peer_clear(): adjust for new bgp_peer_down() mechanics. - in bgp_master_init(): account for peer_linger_count (starting at 0) - in bgp_terminate(): - removed program_terminating -- see flag now in bgp_main.c - implement "retain_mode" by using BGP_OPT_NO_FIB flag to turn off changing the FIB as routes are deleted. - either bgp_peer_delete() if terminating or bgp_peer_down() all peers. - flush process queues. - deleted program_terminate_if_all_disabled() - in peer_lookup(), removed handling of PEER_STATUS_ACCEPT_PEER(). - deleted peer_lookup_with_open(). - in bgp_config_write_family(), removed handling of PEER_STATUS_ACCEPT_PEER(). - in bgp_config_write(), removed handling of PEER_STATUS_ACCEPT_PEER(). bgpd/bgpd.h -- add peer_linger_count entry to the bgp_master structure. - remove: peer_lock(), peer_unlock() and peer_delete() - (4) for peer_af_flag_modify() - added peer_rsclient_unset() lib/plist.c -- fixed handling of prefix lists with no explicit sequence numbers. lib/qpnexus.c -- (4) for main_thread & terminate flags - change qpn_terminate() so does nothing if terminate flag is already set. lib/qpnexus.h -- (4) for main_thread & terminate flags tests/bgp_capability_test.c -- (3)
-rw-r--r--bgpd/bgp.h10
-rw-r--r--bgpd/bgp_advertise.c8
-rw-r--r--bgpd/bgp_attr.c160
-rw-r--r--bgpd/bgp_common.h8
-rw-r--r--bgpd/bgp_connection.c53
-rw-r--r--bgpd/bgp_connection.h3
-rw-r--r--bgpd/bgp_debug.c26
-rw-r--r--bgpd/bgp_debug.h3
-rw-r--r--bgpd/bgp_fsm.c16
-rw-r--r--bgpd/bgp_main.c84
-rw-r--r--bgpd/bgp_mplsvpn.c2
-rw-r--r--bgpd/bgp_msg_read.c3
-rw-r--r--bgpd/bgp_msg_write.c5
-rw-r--r--bgpd/bgp_network.c2
-rw-r--r--bgpd/bgp_nexthop.c2
-rw-r--r--bgpd/bgp_notification.c15
-rw-r--r--bgpd/bgp_notification.h17
-rw-r--r--bgpd/bgp_open.c59
-rw-r--r--bgpd/bgp_open_state.c36
-rw-r--r--bgpd/bgp_packet.c93
-rw-r--r--bgpd/bgp_packet.h5
-rw-r--r--bgpd/bgp_peer.c1932
-rw-r--r--bgpd/bgp_peer.h226
-rw-r--r--bgpd/bgp_peer_index.c87
-rw-r--r--bgpd/bgp_peer_index.h21
-rw-r--r--bgpd/bgp_route.c614
-rw-r--r--bgpd/bgp_route.h10
-rw-r--r--bgpd/bgp_session.c229
-rw-r--r--bgpd/bgp_session.h29
-rw-r--r--bgpd/bgp_table.c11
-rw-r--r--bgpd/bgp_vty.c110
-rw-r--r--bgpd/bgp_zebra.c2
-rw-r--r--bgpd/bgpd.c1106
-rw-r--r--bgpd/bgpd.h25
-rwxr-xr-xconfigure.ac2
-rw-r--r--lib/plist.c45
-rw-r--r--lib/qpnexus.c18
-rw-r--r--lib/qpnexus.h6
-rw-r--r--tests/bgp_capability_test.c2
39 files changed, 3082 insertions, 2003 deletions
diff --git a/bgpd/bgp.h b/bgpd/bgp.h
index 55cf0d2d..1016fe93 100644
--- a/bgpd/bgp.h
+++ b/bgpd/bgp.h
@@ -461,19 +461,19 @@ enum BGP_NOMC
enum BGP_NOMS
{
- BGP_NOMS_UNSPECIFIC = 0 /* If nothing else applies */
+ BGP_NOMS_UNSPECIFIC = 0 /* If nothing else applies */
};
enum BGP_NOMS_HEADER /* BGP_NOMC_HEADER subcodes */
{
- BGP_NOMS_H_NOT_SYNC = 1, /* Connection Not Synchronised */
+ BGP_NOMS_H_NOT_SYNC = 1, /* Connection Not Synchronised */
/* (Marker field not all = 1,'s !) */
- BGP_NOMS_H_BAD_LEN = 2, /* Bad Message Length */
+ BGP_NOMS_H_BAD_LEN = 2, /* Bad Message Length */
/* DATA: the length that failed */
- BGP_NOMS_H_BAD_TYPE = 3, /* Bad Message Type */
+ BGP_NOMS_H_BAD_TYPE = 3, /* Bad Message Type */
/* DATA: the message type objected to */
- BGP_NOMS_H_MAX = 3, /* max known subcode */
+ BGP_NOMS_H_MAX = 3, /* max known subcode */
} ;
enum BGP_NOMS_OPEN /* BGP_NOMC_OPEN subcodes */
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 552b2291..495d0fdc 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -231,7 +231,7 @@ bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p,
adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out));
/* Add to list of adj_out stuff for the peer */
- adj->peer = peer_lock (peer);
+ adj->peer = bgp_peer_lock (peer);
adj_out_head = &(peer->adj_out_head[afi][safi]) ;
@@ -336,7 +336,7 @@ bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,
else
peer->adj_out_head[afi][safi] = adj->route_next ;
- peer_unlock (peer);
+ bgp_peer_unlock (peer);
/* Unhook from bgp_node */
if (adj->adj_next)
@@ -379,7 +379,7 @@ bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)
adj->attr = bgp_attr_intern (attr);
/* Add to list of adj in stuff for the peer */
- adj->peer = peer_lock (peer);
+ adj->peer = bgp_peer_lock (peer);
adj_in_head = &(peer->adj_in_head[rn->table->afi][rn->table->safi]) ;
@@ -420,7 +420,7 @@ bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai)
else
*adj_in_head = bai->route_next ;
- peer_unlock (peer);
+ bgp_peer_unlock (peer);
/* Unhook from bgp_node */
if (bai->adj_next)
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index d79f25f2..7fc9749e 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -718,10 +718,10 @@ bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"AS-Pathlimit attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -729,10 +729,10 @@ bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"AS-Pathlimit length, %u, is not 5", length);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -760,10 +760,10 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"Origin attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -776,9 +776,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
length);
- bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ startp, total);
return -1;
}
@@ -795,10 +795,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
attr->origin);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
- startp, total);
+ bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
+ startp, total);
return -1;
}
@@ -824,10 +823,10 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"As-Path attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -841,9 +840,8 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
if (! attr->aspath)
{
zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return -1;
}
@@ -876,9 +874,8 @@ static int bgp_attr_aspath_check( struct peer *peer,
(peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
{
zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return -1;
}
@@ -890,9 +887,8 @@ static int bgp_attr_aspath_check( struct peer *peer,
{
zlog (peer->log, LOG_ERR,
"%s incorrect first AS (must be %u)", peer->host, peer->as);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return -1;
}
}
@@ -941,10 +937,10 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"Origin attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -954,7 +950,7 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
length);
- bgp_notify_send_with_data (peer,
+ bgp_peer_down_error_with_data (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
startp, total);
@@ -982,10 +978,10 @@ bgp_attr_med (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR,
"MED attribute length isn't four [%d]", length);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ startp, total);
return -1;
}
@@ -1030,9 +1026,9 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1059,9 +1055,8 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen,
length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1087,9 +1082,8 @@ bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
*as4_aggregator_as = stream_getl (peer->ibuf);
@@ -1145,9 +1139,8 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
zlog (peer->log, LOG_ERR,
"%s BGP not AS4 capable peer sent AS4_PATH but"
" no AS_PATH, cant do anything here", peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1247,9 +1240,8 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1271,9 +1263,8 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1511,10 +1502,10 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
{
/* Adjust startp to do not include flag value. */
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_UNREC_ATTR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_UNREC_ATTR,
+ startp, total);
return -1;
}
@@ -1584,9 +1575,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
peer->host,
(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1604,9 +1594,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
peer->host,
(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1626,9 +1615,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
"%s error BGP attribute type %d appears twice in a message",
peer->host, type);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1644,9 +1632,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
{
zlog (peer->log, LOG_WARNING,
"%s BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1713,9 +1700,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
"%s: Attribute %s, parse error",
peer->host,
LOOKUP (attr_str, type));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return ret;
}
@@ -1734,9 +1720,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
PEER_CAP_AS4_USE(peer) ? "" : "NOT ") ;
} ;
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
}
@@ -1747,9 +1732,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
zlog (peer->log, LOG_WARNING,
"%s BGP attribute %s, length mismatch",
peer->host, LOOKUP (attr_str, type));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1829,10 +1813,10 @@ bgp_attr_check (struct peer *peer, struct attr *attr)
zlog (peer->log, LOG_WARNING,
"%s Missing well-known attribute %d.",
peer->host, type);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MISS_ATTR,
- &type, 1);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MISS_ATTR,
+ &type, 1);
return -1;
}
return 0;
diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h
index d35d6da6..67d1afb0 100644
--- a/bgpd/bgp_common.h
+++ b/bgpd/bgp_common.h
@@ -134,10 +134,10 @@ enum bgp_peer_states
{
bgp_peer_min_state = 0,
- bgp_peer_sIdle = 1, /* session not yet established */
- bgp_peer_sEstablished = 2, /* session established */
- bgp_peer_sClearing = 3, /* Clearing routes */
- bgp_peer_sDeleted = 4, /* Deleted, linger until lock count == 0 */
+ bgp_peer_pIdle = 1, /* session not yet established */
+ bgp_peer_pEstablished = 2, /* session established */
+ bgp_peer_pClearing = 3, /* Clearing routes */
+ bgp_peer_pDeleting = 4, /* Deleting, lingers until lock count == 0 */
bgp_peer_max_state = 4
} ;
diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c
index 41cde9a3..cdcfc10e 100644
--- a/bgpd/bgp_connection.c
+++ b/bgpd/bgp_connection.c
@@ -690,28 +690,65 @@ bgp_connection_stop(bgp_connection connection, int stop_writer)
} ;
/*------------------------------------------------------------------------------
- * Enable connection for accept()
+ * Enable connection/session for accept()
*
- * NB: requires the session to be LOCKED.
+ * NB: requires the session to be LOCKED
*/
extern void
bgp_connection_enable_accept(bgp_connection connection)
{
+ bgp_session session = connection->session ;
+
assert(connection->ordinal == bgp_connection_secondary) ;
- connection->session->index_entry->accept = connection ;
+ assert((session != NULL) && (session->active)) ;
+
+ session->accept = true ;
} ;
/*------------------------------------------------------------------------------
* Disable connection for accept() -- assuming still have session !
*
- * NB: requires the session to be LOCKED.
+ * NB: requires the session to be LOCKED
*/
extern void
bgp_connection_disable_accept(bgp_connection connection)
{
- bgp_session session = connection->session ;
- if (session != NULL)
- session->index_entry->accept = NULL ;
+ if (connection->session != NULL)
+ connection->session->accept = false ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * See if there is a connection which is ready to accept()
+ *
+ * Note that if there *is* a connection, then the session is active, and is not
+ * subject to the whim of the Routing Engine -- in particular it cannot be
+ * deleted !
+ *
+ * NB: this is *only* used in the BGP Engine. The session->active and
+ * session->accept flags are private variables, only set by the BGP Engine.
+ *
+ * NB: this is called under the Peer Index Mutex. The Routing Engine never
+ * deletes sessions while it holds the Peer Index Mutex, nor when the
+ * session->active is true.
+ *
+ * Only returns a connection if session->active -- so safe.
+ */
+extern bgp_connection
+bgp_connection_query_accept(bgp_session session)
+{
+ bgp_connection connection ;
+
+ if ((session != NULL) && session->active && session->accept)
+ {
+ connection = session->connections[bgp_connection_secondary] ;
+ assert(connection != NULL) ;
+ }
+ else
+ {
+ connection = NULL ;
+ } ;
+
+ return connection ;
} ;
/*------------------------------------------------------------------------------
@@ -830,7 +867,7 @@ bgp_connection_part_close(bgp_connection connection)
/* Turn off session->active (if still attached). */
if (session != NULL)
- session->active = 0 ;
+ session->active = false ;
/* Purge wbuff of all but current partly written message (if any) */
if (wb->p_in != wb->p_out) /* will be equal if buffer is empty */
diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h
index 3d63edb7..58afc2ae 100644
--- a/bgpd/bgp_connection.h
+++ b/bgpd/bgp_connection.h
@@ -219,6 +219,9 @@ extern void
bgp_connection_disable_accept(bgp_connection connection) ;
extern bgp_connection
+bgp_connection_query_accept(bgp_session session) ;
+
+extern bgp_connection
bgp_connection_get_sibling(bgp_connection connection) ;
extern void
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 607bf824..684e9651 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -81,10 +81,10 @@ const int bgp_status_msg_max = bgp_fsm_last_state + 1 ;
const struct message bgp_peer_status_msg[] =
{
- { bgp_peer_sIdle, "Idle" },
- { bgp_peer_sEstablished, "Established" },
- { bgp_peer_sClearing, "Clearing" },
- { bgp_peer_sDeleted, "Deleted" },
+ { bgp_peer_pIdle, "Idle" },
+ { bgp_peer_pEstablished, "Established" },
+ { bgp_peer_pClearing, "Clearing" },
+ { bgp_peer_pDeleting, "Deleting" },
};
const int bgp_peer_status_msg_max = bgp_peer_max_state + 1 ;
@@ -254,7 +254,7 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
/* dump notify packet */
void
-bgp_notify_print(struct peer *peer, bgp_notify notification, bool sending)
+bgp_notify_print(struct peer *peer, bgp_notify notification)
{
const char* subcode_str ;
const char* code_str ;
@@ -328,15 +328,15 @@ bgp_notify_print(struct peer *peer, bgp_notify notification, bool sending)
/* Output the required logging */
if (log_neighbor_changes)
- zlog_info ("%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s",
- sending ? "sent to" : "received from", peer->host,
- notification->code, notification->subcode,
- code_str, subcode_str, length, hex_form) ;
+ zlog_info("%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s",
+ notification->received ? "received from" : "sent to", peer->host,
+ notification->code, notification->subcode,
+ code_str, subcode_str, length, hex_form) ;
else
- plog_debug (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s",
- peer->host, sending ? "sending" : "received",
- notification->code, notification->subcode,
- code_str, subcode_str, length, hex_form) ;
+ plog_debug(peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s",
+ peer->host, notification->received ? "received" : "sending",
+ notification->code, notification->subcode,
+ code_str, subcode_str, length, hex_form) ;
/* Release the */
if (alloc != NULL)
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index 1d05cefb..2b9ca268 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -121,8 +121,7 @@ extern unsigned long term_bgp_debug_zebra;
extern const char *bgp_type_str[];
extern int bgp_dump_attr (struct peer *, struct attr *, char *, size_t);
-extern void bgp_notify_print (struct peer* peer, bgp_notify notification,
- bool sending);
+extern void bgp_notify_print (struct peer* peer, bgp_notify notification);
extern const struct message bgp_status_msg[];
extern const int bgp_status_msg_max;
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 9c323ffd..9df8a955 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -66,6 +66,20 @@
*
* The fsm action functions are called with the session locked.
*
+ * TODO: restore NSF
+ * TODO: track incoming connections while established
+ *
+ * To do this need to accept connection while established, then wait for
+ * OPEN. While waiting, the established connection may drop, and
+ * so the session restart, but with an incoming connection already
+ * in place.
+ *
+ * When OPEN arrives, for NSF should close any established connection
+ * and restart with the new one.
+ *
+ * Otherwise, if CollisionDetectEstablishedState option is set, should
+ * go through collision detection !
+ *
*------------------------------------------------------------------------------
* FSM "events" and Session "exceptions".
*
@@ -1932,6 +1946,8 @@ static bgp_fsm_action(bgp_fsm_error)
* Next state will be sIdle, except if is sEstablished, when will be sStopping.
*
* NB: requires the session LOCKED
+ *
+ * TODO: deal with: BGP_NOMC_OPEN/BGP_NOMS_O_OPTION & squash capabilities.
*/
static bgp_fsm_action(bgp_fsm_recv_nom)
{
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 0de28b9b..60b66533 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -75,20 +75,23 @@ static const struct option longopts[] =
{ "ignore_warnings", no_argument, NULL, 'I'},
{ 0 }
};
-/* Configuration file and directory. */
+/* Configuration file and directory. */
char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG;
-/* Route retain mode flag. */
-static int retain_mode = 0;
+/* Route retain mode flag. */
+static bool retain_mode = false;
+
+/* Have started terminating the program */
+static bool program_terminating = false ;
/* whether to ignore warnings in configuration file */
static bool config_ignore_warnings = false;
/* whether configured to run with qpthreads */
-static bool config_threaded = 0;
+static bool config_threaded = false ;
/* whether configured to run as an AS2 speaker */
-static bool config_as2_speaker = 0;
+static bool config_as2_speaker = false ;
/* Master of threads. */
struct thread_master *master;
@@ -483,11 +486,11 @@ int
main (int argc, char **argv)
{
char *p;
- int opt;
- int daemon_mode = 0;
- int dryrun = 0;
+ int opt;
+ bool daemon_mode = false ;
+ bool dryrun = false ;
char *progname;
- int tmp_port;
+ int tmp_port;
/* Set umask before anything for security */
umask (0027);
@@ -520,7 +523,7 @@ main (int argc, char **argv)
case 0:
break;
case 'd':
- daemon_mode = 1;
+ daemon_mode = true ;
break;
case 'f':
config_file = optarg;
@@ -551,7 +554,7 @@ main (int argc, char **argv)
vty_port = BGP_VTY_PORT;
break;
case 'r':
- retain_mode = 1;
+ retain_mode = true ;
break;
case 'l':
bm->address = optarg;
@@ -570,19 +573,19 @@ main (int argc, char **argv)
exit (0);
break;
case 'C':
- dryrun = 1;
+ dryrun = true ;
break;
case 'h':
usage (progname, 0);
break;
case 't':
- config_threaded = 1;
+ config_threaded = true ;
break;
case 'I':
- config_ignore_warnings = 1;
+ config_ignore_warnings = true ;
break ;
case '2':
- config_as2_speaker = 1;
+ config_as2_speaker = true ;
break ;
default:
usage (progname, 1);
@@ -716,6 +719,10 @@ routing_background(void)
return thread_dispatch_background(master) ;
}
+/*==============================================================================
+ * SIGHUP and SIGTERM
+ */
+
/*------------------------------------------------------------------------------
* SIGHUP: message sent to Routeing engine and the action it then takes.
*
@@ -726,14 +733,14 @@ sighup_enqueue(void)
{
mqueue_block mqb = mqb_init_new(NULL, sighup_action, NULL) ;
- mqueue_enqueue(routing_nexus->queue, mqb, 1) ;
+ mqueue_enqueue(routing_nexus->queue, mqb, mqb_priority) ;
}
/* dispatch a command from the message queue block */
static void
sighup_action(mqueue_block mqb, mqb_flag_t flag)
{
- if (flag == mqb_action)
+ if ((flag == mqb_action) && !program_terminating)
{
zlog_info ("bgpd restarting!");
@@ -753,6 +760,32 @@ sighup_action(mqueue_block mqb, mqb_flag_t flag)
}
/*------------------------------------------------------------------------------
+ * Foreground task to see if all peers have been deleted yet.
+ */
+static int
+program_terminate_if_all_peers_deleted(void)
+{
+ if (bm->peer_linger_count == 0)
+ {
+ /* ask remaining pthreads to die
+ *
+ * Note that qpn_terminate does nothing if it has been called once
+ * already.
+ */
+ if (qpthreads_enabled && routing_nexus != NULL)
+ qpn_terminate(routing_nexus);
+
+ if (qpthreads_enabled && bgp_nexus != NULL)
+ qpn_terminate(bgp_nexus);
+
+ if (cli_nexus != NULL)
+ qpn_terminate(cli_nexus) ;
+ } ;
+
+ return 0 ; /* nothing to do, really. */
+} ;
+
+/*------------------------------------------------------------------------------
* SIGTERM: message sent to Routeing engine and the action it then takes.
*/
static void
@@ -760,19 +793,26 @@ sigterm_enqueue(void)
{
mqueue_block mqb = mqb_init_new(NULL, sigterm_action, NULL) ;
- mqueue_enqueue(routing_nexus->queue, mqb, 1) ;
-}
+ mqueue_enqueue(routing_nexus->queue, mqb, mqb_priority) ;
+} ;
/* dispatch a command from the message queue block */
static void
sigterm_action(mqueue_block mqb, mqb_flag_t flag)
{
- if (flag == mqb_action)
+ if ((flag == mqb_action) && !program_terminating)
{
/* send notify to all peers, wait for all sessions to be disables
- * then terminate all pthreads */
+ * then terminate all pthreads
+ */
+ program_terminating = true ;
+
bgp_terminate(1, retain_mode);
+
+ qpn_add_hook_function(&routing_nexus->foreground,
+ program_terminate_if_all_peers_deleted) ;
}
mqb_free(mqb);
-}
+} ;
+
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 0489cf0f..983a4867 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -92,7 +92,7 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr,
u_char *tagpnt;
/* Check peer status. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return 0;
/* Make prefix_rd */
diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c
index 664aed21..e0bbfef9 100644
--- a/bgpd/bgp_msg_read.c
+++ b/bgpd/bgp_msg_read.c
@@ -1420,8 +1420,9 @@ bgp_msg_notify_receive (bgp_connection connection, bgp_size_t body_size)
notification = bgp_notify_new_with_data(code, subcode,
stream_pnt(connection->ibuf), body_size - 2) ;
+ bgp_notify_set_received(notification) ;
- bgp_notify_print(connection->session->peer, notification, 0) ; /* Logging */
+ bgp_notify_print(connection->session->peer, notification) ; /* Logging */
bgp_fsm_notification_exception(connection, notification) ;
} ;
diff --git a/bgpd/bgp_msg_write.c b/bgpd/bgp_msg_write.c
index 0323fa83..ee4a510c 100644
--- a/bgpd/bgp_msg_write.c
+++ b/bgpd/bgp_msg_write.c
@@ -85,14 +85,13 @@ extern int
bgp_msg_write_notification(bgp_connection connection, bgp_notify notification)
{
struct stream *s = connection->obuf ;
- int length;
+ int length;
++connection->session->stats.notify_out ;
assert(notification != NULL) ;
- /* Logging */
- bgp_notify_print(connection->session->peer, notification, 1) ;
+ bgp_notify_print(connection->session->peer, notification) ;
/* Make NOTIFY message header */
bgp_packet_set_marker (s, BGP_MSG_NOTIFY);
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 77c89ff3..87f4f953 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -572,7 +572,7 @@ bgp_accept_action(qps_file qf, void* file_info)
bgp_connection connection ;
union sockunion su_remote ;
union sockunion su_local ;
- int exists ;
+ bool exists ;
int sock_fd ;
int err ;
int family ;
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index c72ca09f..de745007 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -438,7 +438,7 @@ bgp_scan (afi_t afi, safi_t safi)
/* Maximum prefix check */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
continue;
if (peer->afc[afi][SAFI_UNICAST])
diff --git a/bgpd/bgp_notification.c b/bgpd/bgp_notification.c
index 2763f296..45bf99b7 100644
--- a/bgpd/bgp_notification.c
+++ b/bgpd/bgp_notification.c
@@ -54,6 +54,8 @@ bgp_notify_size(bgp_size_t size)
* Allocate and initialise new notification
*
* Can add data later if required.
+ *
+ * NB: returns a 'NOT received' notification.
*/
extern bgp_notify
bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode)
@@ -67,9 +69,10 @@ bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode)
/* Implicitly:
*
- * notification->size = 0
- * notification->length = 0
- * notification->data = NULL
+ * notification->received = false ;
+ * notification->size = 0
+ * notification->length = 0
+ * notification->data = NULL
*/
return notification ;
@@ -82,6 +85,8 @@ bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode)
* ...but pre-allocates at least the expected amount.
*
* May expect 0.
+ *
+ * NB: returns a 'NOT received' notification.
*/
extern bgp_notify
bgp_notify_new_expect(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
@@ -102,6 +107,8 @@ bgp_notify_new_expect(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
* Allocate and initialise new notification, complete with data
*
* Can specify an expected amount of data.
+ *
+ * NB: returns a 'NOT received' notification.
*/
extern bgp_notify
bgp_notify_new_with_data(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
@@ -228,6 +235,8 @@ bgp_notify_set_mov(bgp_notify* p_dst, bgp_notify* p_src)
/*==============================================================================
* Set new Code and Subcode and discard and data accumulated so far.
+ *
+ * NB: does not change the received state of the notification.
*/
extern bgp_notify
bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code,
diff --git a/bgpd/bgp_notification.h b/bgpd/bgp_notification.h
index a7e04501..20e96063 100644
--- a/bgpd/bgp_notification.h
+++ b/bgpd/bgp_notification.h
@@ -38,7 +38,10 @@ typedef unsigned char bgp_nom_code_t ;
typedef unsigned char bgp_nom_subcode_t ;
/*==============================================================================
+ * Structure for notification.
*
+ * Note that vast majority of notification handling concerns notifications that
+ * are *sent* to the far end. Occasionally a notification will be received.
*/
typedef struct bgp_notify* bgp_notify ;
@@ -47,6 +50,8 @@ struct bgp_notify
bgp_nom_code_t code ;
bgp_nom_subcode_t subcode ;
+ bool received ;
+
bgp_size_t length ;
bgp_size_t size ;
ptr_t data ;
@@ -166,6 +171,12 @@ bgp_notify_set_subcode(bgp_notify notification, bgp_nom_subcode_t subcode)
notification->subcode = subcode ;
} ;
+Inline void
+bgp_notify_set_received(bgp_notify notification)
+{
+ notification->received = true ;
+} ;
+
extern bgp_notify
bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code,
bgp_nom_subcode_t subcode) ;
@@ -193,6 +204,12 @@ bgp_notify_get_subcode(bgp_notify notification)
return (notification != NULL) ? notification->subcode : BGP_NOMS_UNSPECIFIC ;
} ;
+Inline bool
+bgp_notify_get_received(bgp_notify notification)
+{
+ return (notification != NULL) ? notification->received : false ;
+} ;
+
Inline bgp_size_t
bgp_notify_get_length(bgp_notify notification)
{
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 7bcddca0..ab9acf63 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -58,7 +58,8 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
struct capability_mp_data mpc;
struct capability_header *hdr;
- if (peer == NULL || peer->session == NULL || peer->session->notification == NULL)
+ if ((peer == NULL) || (peer->session == NULL)
+ || (peer->session->notification == NULL))
return;
pnt = (char*)peer->session->notification->data;
@@ -254,8 +255,9 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
{
zlog_info ("%s ORF Capability entry length error,"
" Cap length %u, num %u",
- peer->host, hdr->length, entry.num);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ peer->host, hdr->length, entry.num) ;
+ /* TODO: is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -497,7 +499,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
if (stream_get_getp(s) + 2 > end)
{
zlog_info ("%s Capability length error (< header)", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -509,7 +512,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
if (start + caphdr.length > end)
{
zlog_info ("%s Capability length error (< length)", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -539,7 +543,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
LOOKUP (capcode_str, caphdr.code),
caphdr.length,
(unsigned) cap_minsizes[caphdr.code]);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
/* we deliberately ignore unknown codes, see below */
@@ -628,9 +633,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
static int
bgp_auth_parse (struct peer *peer, size_t length)
{
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_AUTH_FAILURE);
+ bgp_peer_down_error (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_AUTH_FAILURE);
return -1;
}
@@ -752,7 +756,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
if (STREAM_READABLE(s) < 2)
{
zlog_info ("%s Option length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -764,7 +769,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
if (STREAM_READABLE (s) < opt_length)
{
zlog_info ("%s Option length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -785,9 +791,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
*capability = 1;
break;
default:
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_PARAM);
+ bgp_peer_down_error (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_PARAM);
ret = -1;
break;
}
@@ -807,10 +812,10 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
/* If Unsupported Capability exists. */
if (error != error_data)
{
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL,
- error_data, error - error_data);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL,
+ error_data, error - error_data);
return -1;
}
@@ -818,9 +823,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
peer. */
if (! strict_capability_same (peer))
{
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL);
+ bgp_peer_down_error (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL);
return -1;
}
}
@@ -839,14 +843,13 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
if (error != error_data)
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL,
- error_data, error - error_data);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL,
+ error_data, error - error_data);
else
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL);
+ bgp_peer_down_error (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL);
return -1;
}
}
diff --git a/bgpd/bgp_open_state.c b/bgpd/bgp_open_state.c
index 17f9ae36..c08160eb 100644
--- a/bgpd/bgp_open_state.c
+++ b/bgpd/bgp_open_state.c
@@ -293,12 +293,15 @@ bgp_open_state_afi_safi_cap(bgp_open_state state, unsigned index)
*
*/
-/* Received an open, update the peer's state */
+/* Received an open, update the peer's state
+ *
+ * NB: for safety, best to have the session locked -- though won't, in fact,
+ * change any of this information after the session is established.
+ */
void
bgp_peer_open_state_receive(bgp_peer peer)
{
- bgp_session session = peer->session;
- bgp_open_state open_send = session->open_send;
+ bgp_session session = peer->session;
bgp_open_state open_recv = session->open_recv;
qAFI_t afi;
qSAFI_t safi;
@@ -315,16 +318,13 @@ bgp_peer_open_state_receive(bgp_peer peer)
implementation MAY adjust the rate at which it sends KEEPALIVE
messages as a function of the Hold Time interval. */
- peer->v_holdtime =
- (open_recv->holdtime < open_send->holdtime)
- ? open_recv->holdtime
- : open_send->holdtime;
-
- peer->v_keepalive = peer->v_holdtime / 3;
-
- /* TODO: update session state as well? */
- session->hold_timer_interval = peer->v_holdtime ;
- session->keepalive_timer_interval = peer->v_keepalive ;
+ /* The BGP Engine sets the session's HoldTimer and KeepaliveTimer intervals
+ * to the values negotiated when the OPEN messages were exchanged.
+ *
+ * Take copies of that information.
+ */
+ peer->v_holdtime = session->hold_timer_interval ;
+ peer->v_keepalive = session->keepalive_timer_interval ;
/* Set remote router-id */
peer->remote_id.s_addr = open_recv->bgp_id;
@@ -404,12 +404,18 @@ bgp_peer_open_state_receive(bgp_peer peer)
if (open_recv->can_dynamic)
SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
- /* Graceful restart */
+ /* Graceful restart
+ *
+ * NB: appear not to care about open_recv->has_restarted !
+ */
+ if (open_recv->can_g_restart)
+ SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV) ;
+
for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
{
qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi);
- if (peer->afc[afi][safi] && (qb & open_recv->can_g_restart))
+ if (peer->afc[afi][safi] && (qb & open_recv->can_preserve))
{
SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
if (qb & open_recv->has_preserved)
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 71779567..62d76c60 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -764,35 +764,6 @@ bgp_open_send (struct peer *peer)
}
#endif
-/* Send BGP notify packet with data portion. */
-void
-bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
- u_char *data, size_t datalen)
-{
- bgp_notify notification;
- notification = bgp_notify_new_with_data(code, sub_code, data, datalen);
-
- /* peer reset cause */
- if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE)
- {
- if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
- peer->last_reset = PEER_DOWN_USER_RESET;
- else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
- peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
- else
- peer->last_reset = PEER_DOWN_NOTIFY_SEND;
- }
-
- bgp_peer_disable(peer, notification);
-}
-
-/* Send BGP notify packet. */
-void
-bgp_notify_send (struct peer *peer, u_char code, u_char sub_code)
-{
- bgp_notify_send_with_data (peer, code, sub_code, NULL, 0);
-}
-
/* Send route refresh message to the peer. */
void
@@ -1449,11 +1420,11 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
char attrstr[BUFSIZ] = "";
/* Status must be Established. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
{
zlog_err ("%s [FSM] Update packet received under status %s",
peer->host, LOOKUP (bgp_peer_status_msg, peer->state));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0);
return -1;
}
@@ -1476,8 +1447,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_err ("%s [Error] Update packet error"
" (packet length is short for unfeasible length)",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1490,8 +1461,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_err ("%s [Error] Update packet error"
" (packet unfeasible length overflow %d)",
peer->host, withdraw_len);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1518,8 +1489,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_warn ("%s [Error] Packet Error"
" (update packet is short for attribute length)",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1532,8 +1503,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_warn ("%s [Error] Packet Error"
" (update packet attribute length overflow %d)",
peer->host, attribute_len);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1754,7 +1725,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* If peering is stopped due to some reason, do not generate BGP
event. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return 0;
/* Generate BGP event. */
@@ -1949,9 +1920,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
{
plog_err (peer->log, "%s [Error] BGP route refresh is not enabled",
peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESTYPE);
+ bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR,
+ BGP_NOTIFY_HEADER_BAD_MESTYPE);
return;
}
@@ -1961,7 +1931,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
plog_err (peer->log,
"%s [Error] Route refresh packet received under status %s",
peer->host, LOOKUP (bgp_status_msg, peer->status));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0);
return;
}
@@ -2003,7 +1973,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5)
{
zlog_info ("%s ORF route refresh length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return;
}
@@ -2130,7 +2100,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
if (pnt + 3 > end)
{
zlog_info ("%s Capability length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
action = *pnt;
@@ -2142,7 +2113,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
{
zlog_info ("%s Capability Action Value error %d",
peer->host, action);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -2154,7 +2126,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
if ((pnt + hdr->length + 3) > end)
{
zlog_info ("%s Capability length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -2200,16 +2173,20 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
{
peer->afc_recv[afi][safi] = 0;
peer->afc_nego[afi][safi] = 0;
+ bool completed ;
if (peer_active_nego (peer))
- bgp_clear_route_normal (peer, afi, safi);
+ completed = bgp_clear_routes (peer, afi, safi, false);
else
{
+ completed = true ;
/* TODO: only used for unit tests. Test will need fixing */
#if 0
BGP_EVENT_ADD (peer, BGP_Stop);
#endif
- }
+ } ;
+ /* if bgp_clear_routes does not complete. what do we do ? */
+ passert(completed) ;
}
}
else
@@ -2242,19 +2219,18 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)
{
plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled",
peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESTYPE);
+ bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR,
+ BGP_NOTIFY_HEADER_BAD_MESTYPE);
return -1;
}
/* Status must be Established. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
{
plog_err (peer->log,
"%s [Error] Dynamic capability packet received under status %s",
peer->host, LOOKUP (bgp_status_msg, peer->state));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0);
return -1;
}
@@ -2405,9 +2381,8 @@ bgp_read (struct thread *thread)
if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE))
&& ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE))
{
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_NOT_SYNC);
+ bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR,
+ BGP_NOTIFY_HEADER_NOT_SYNC);
goto done;
}
@@ -2508,7 +2483,7 @@ bgp_read (struct thread *thread)
{
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("%s [Event] Accepting BGP peer delete", peer->host);
- peer_delete (peer);
+ bgp_peer_delete (peer);
}
return 0;
}
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index f0798846..6cf9a394 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -46,11 +46,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
extern int bgp_read (struct thread *);
extern int bgp_write (bgp_peer peer, struct stream*);
-extern void bgp_keepalive_send (struct peer *);
-extern void bgp_open_send (struct peer *);
-extern void bgp_notify_send (struct peer *, u_int8_t, u_int8_t);
-extern void bgp_notify_send_with_data (struct peer *, u_int8_t, u_int8_t,
- u_int8_t *, size_t);
extern void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int);
extern void bgp_capability_send (struct peer *, afi_t, safi_t, int, int);
extern void bgp_default_update_send (struct peer *, struct attr *,
diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c
index 18634fb0..2062c527 100644
--- a/bgpd/bgp_peer.c
+++ b/bgpd/bgp_peer.c
@@ -58,16 +58,6 @@
#include "bgpd/bgp_snmp.h"
#endif /* HAVE_SNMP */
-/* prototypes */
-
-static int bgp_session_has_established(bgp_peer peer);
-static int bgp_session_has_stopped(bgp_peer peer);
-static int bgp_session_has_disabled(bgp_peer peer);
-static void bgp_uptime_reset (struct peer *peer);
-static int bgp_routeadv_timer (struct thread *thread);
-static int bgp_graceful_restart_timer_expire (struct thread *thread);
-static int bgp_graceful_stale_timer_expire (struct thread *thread);
-
/*==============================================================================
* This is the high level management of BGP Peers and peering conversations.
*
@@ -76,7 +66,7 @@ static int bgp_graceful_stale_timer_expire (struct thread *thread);
* Here we look after...
*
* * the peer state and the effects of changes in that state
- * *
+ *
* * timers for advertisements, graceful restart, ...
*
* The naming of peers/sessions and bgp_session_index
@@ -91,8 +81,122 @@ static int bgp_graceful_stale_timer_expire (struct thread *thread);
* The bgp_peer_index maps IP addresses to the peer, and hence to the session
* (if any exists and is active).
*
+ * [To support multi-instance BGP, might be nice to use the "update source"
+ * address as part of the name of a peer. But that is another story.]
+ *
+ *------------------------------------------------------------------------------
+ * The Peer State.
+ *
+ * The peer has a small number of states. Where there is a session, its state
+ * is a sub-state of the main peer state.
+ *
+ * The states of a peer are as follows:
+ *
+ * 1. bgp_peer_pIdle
+ *
+ * All peers start in this state.
+ *
+ * This is the case when:
+ *
+ * a. peer is administratively down/disabled/deactivated
+ *
+ * b. waiting for route flap or other such timer before reawakening.
+ *
+ * c. waiting for previous session to be closed -- in BGP Engine
+ *
+ * d. waiting for session to establish -- in BGP Engine
+ *
+ * The session states relate to the above as follows:
+ *
+ * sIdle, sDisabled or no session at all -- (a) or (b)
+ *
+ * sEnabled -- (d)
+ *
+ * sEstablished -- IMPOSSIBLE
+ *
+ * sLimping -- (c)
+ *
+ * Only when the peer is none of (a), (b) or (c) can a session be enabled
+ * and the session move to (d), sEnabled. So changes either in the state
+ * of the peer or in the state of the session have to check whether it
+ * is time to:
+ *
+ * 1. enable a new session
+ *
+ * 2. disable a session which has yet to reach sEstablished, but is
+ * now no longer correctly configured, or the like.
+ *
+ * 2. bgp_peer_pEstablished
+ *
+ * Reaches this state from pIdle when a session becomes established.
+ *
+ * This can only be the case when the session is sEstablished.
+ *
+ * If the session is stopped for any reason, issues a Disable request to
+ * the BGP Engine:
+ *
+ * peer -> pClearing
+ * session -> sLimping
+ *
+ * 3. bgp_peer_pClearing
+ *
+ * Reaches this state from pEstablished *only*, as above.
+ *
+ * In this state the session can only be:
+ *
+ * sLimping -- session disable has been sent to the BGP Engine.
+ * sDisabled -- session has been disabled by the BGP Engine
+ *
+ * Tidies up the peer, including clearing routes etc. Once the peer is
+ * completely tidy:
+ *
+ * peer -> pIdle
+ *
+ * On entry to pClearing the session will be sLimping, on exit it may be
+ * still sLimping, or have advanced to sDisabled.
+ *
+ * NB: while in pClearing the peer's routes and RIBs are being processed.
+ * All other parts of the peer may be modified... but mindful of the
+ * "background" task which is yet to complete.
+ *
+ * 4. bgp_peer_pDeleted
+ *
+ * This is an exotic state, reached only when a peer is being completely
+ * deleted.
+ *
+ * This state may be reached from any of the above.
+ *
+ * If there is an active session, it will be sLimping. When advances to
+ * sDisabled it will be deleted.
+ *
+ * The remaining tasks are to clear out routes, dismantle the peer
+ * structure and delete it. While that is happening, the peer is in this
+ * state.
*/
+/* prototypes */
+
+static void bgp_session_has_established(bgp_session session);
+static void bgp_session_has_stopped(bgp_session session);
+static void bgp_session_has_disabled(bgp_session session);
+static void bgp_uptime_reset (struct peer *peer);
+static void bgp_peer_stop (struct peer *peer, bool nsf) ;
+static void bgp_peer_reset_idle(struct peer *peer) ;
+static void bgp_peer_down_notify(bgp_peer peer, peer_down_t why_down,
+ bgp_notify notification) ;
+static void bgp_peer_shutdown(bgp_peer peer) ;
+static bgp_notify bgp_peer_map_peer_down(peer_down_t why_down) ;
+static peer_down_t bgp_peer_map_notification(bgp_notify notification) ;
+static void bgp_peer_free (struct peer *peer) ;
+static void bgp_peer_change_status (bgp_peer peer, bgp_peer_state_t new_state);
+static void bgp_peer_timers_set (struct peer *peer) ;
+static int bgp_routeadv_timer (struct thread *thread);
+static int bgp_graceful_restart_timer_expire (struct thread *thread);
+static void bgp_graceful_restart_timer_cancel (struct peer* peer) ;
+static int bgp_graceful_stale_timer_expire (struct thread *thread);
+static void bgp_graceful_stale_timer_cancel (struct peer* peer) ;
+
+
/*==============================================================================
* Deal with change in session state -- mqueue_action function.
*
@@ -106,17 +210,16 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag)
{
struct bgp_session_event_args * args = mqb_get_args(mqb) ;
- bgp_session session = mqb_get_arg0(mqb) ;
- bgp_peer peer = session->peer ;
+ bgp_session session = mqb_get_arg0(mqb) ;
if (flag == mqb_action)
{
- BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+ /* Pull stuff into Routing Engine *private* fields in the session */
session->event = args->event ; /* last event */
bgp_notify_set(&session->notification, args->notification) ;
/* if any sent/received */
- session->err = args->err ; /* errno, if any */
+ session->err = args->err ; /* errno, if any */
session->ordinal = args->ordinal ; /* primary/secondary connection */
switch(args->event)
@@ -132,14 +235,18 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag)
if (session->state == bgp_session_sLimping)
break ;
- bgp_session_has_established(peer);
+ bgp_session_has_established(session);
break ;
/* If now Disabled, then the BGP Engine is acknowledging the a
* session disable, and the session is now disabled.
+ *
+ * BEWARE: this may be the last thing that happens to the session
+ * and/or the related peer -- which may be deleted inside
+ * bgp_session_has_disabled().
*/
case bgp_session_eDisabled:
- bgp_session_has_disabled(peer);
+ bgp_session_has_disabled(session);
break ;
/* If now Stopped, then for some reason the BGP Engine has either
@@ -152,11 +259,9 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag)
break ;
if (args->stopped)
- bgp_session_has_stopped(peer);
+ bgp_session_has_stopped(session) ;
break ;
} ;
-
- BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
}
else
bgp_notify_free(args->notification) ;
@@ -164,41 +269,49 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag)
mqb_free(mqb) ;
}
-/* BGP Session has been Established.
- *
- * NB: holding the session structure mutex.
- *
- * Send keepalive packet then make first update information.
+/*------------------------------------------------------------------------------
+ * BGP Session has been Established.
*/
-static int
-bgp_session_has_established(bgp_peer peer)
+static void
+bgp_session_has_established(bgp_session session)
{
afi_t afi;
safi_t safi;
- int nsf_af_count = 0;
+ int nsf_af_count ;
- bgp_session session = peer->session ;
+ bgp_peer peer = session->peer ;
+ assert(peer->session == session) ; /* Safety first */
+ /* Session state change -- Routing Engine private fields */
assert(session->state == bgp_session_sEnabled) ;
session->state = bgp_session_sEstablished ;
session->flow_control = BGP_XON_REFRESH; /* updates can be sent */
- peer_change_status (peer, bgp_peer_sEstablished);
- /* update peer state from received open */
- bgp_peer_open_state_receive(peer);
+ /* Peer state change.
+ *
+ * This stops all timers other than the Graceful Stale Timer.
+ */
+ bgp_peer_change_status (peer, bgp_peer_pEstablished);
+
+ /* Extracting information from shared fields. */
+ BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- /* get the local and remote addresses, and set the nexthop. */
+ bgp_peer_open_state_receive(peer);
sockunion_set_dup(&peer->su_local, session->su_local) ;
sockunion_set_dup(&peer->su_remote, session->su_remote) ;
+
+ BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ /* Install next hop, as required. */
bgp_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop, peer) ;
/* Reset capability open status flag. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
- /* Clear last notification data. */
+ /* Clear last notification data -- Routing Engine private field */
bgp_notify_unset(&(peer->session->notification));
/* Clear start timer value to default. */
@@ -212,17 +325,29 @@ bgp_session_has_established(bgp_peer peer)
if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);
- /* graceful restart */
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+ /* graceful restart */
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) ;
+
+ nsf_af_count = 0 ;
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
{
+ /* If the afi/safi has been negotiated, and have received Graceful
+ * Restart capability, and is Restarting, and will Gracefully Restart
+ * the afi/safi, then....
+ */
if (peer->afc_nego[afi][safi]
&& CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV)
&& CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV))
{
+ /* If have held onto routes for this afi/safi but forwarding has
+ * not been preserved, then clean out the stale routes.
+ *
+ * Set NSF for this address family for next time.
+ */
if (peer->nsf[afi][safi]
- && ! CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV))
+ && ! CHECK_FLAG (peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_PRESERVE_RCV))
bgp_clear_stale_route (peer, afi, safi);
peer->nsf[afi][safi] = 1;
@@ -230,6 +355,7 @@ bgp_session_has_established(bgp_peer peer)
}
else
{
+ /* Remove stale routes, if any for this afi/safi */
if (peer->nsf[afi][safi])
bgp_clear_stale_route (peer, afi, safi);
peer->nsf[afi][safi] = 0;
@@ -241,28 +367,9 @@ bgp_session_has_established(bgp_peer peer)
else
{
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
- if (peer->t_gr_stale)
- {
- BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
+ bgp_graceful_stale_timer_cancel(peer) ;
}
- if (peer->t_gr_restart)
- {
- BGP_TIMER_OFF (peer->t_gr_restart);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart timer stopped", peer->host);
- }
-
-#ifdef HAVE_SNMP
- bgpTrapEstablished (peer);
-#endif /* HAVE_SNMP */
-
- /* Reset uptime, send keepalive, send current table. */
- bgp_uptime_reset (peer);
-
/* Send route-refresh when ORF is enabled */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
@@ -284,145 +391,268 @@ bgp_session_has_established(bgp_peer peer)
|| CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
+ /* Reset uptime, send current table. */
+ bgp_uptime_reset (peer);
+
bgp_announce_route_all (peer);
BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);
- return 0;
+#ifdef HAVE_SNMP
+ bgpTrapEstablished (peer);
+#endif /* HAVE_SNMP */
}
/*------------------------------------------------------------------------------
- * State change to sLimping, session mutex locked
+ * BGP Session has stopped of its own accord -> disable the peer & session.
*
* The BGP Engine has signalled that it has stopped the session. Response to
* that is to tell it to disable the session, and then wait in sLimping state
- * until the BGP Engine acknowledges the disable request.
+ * until the BGP Engine completes the disable request and signals that.
+ *
+ * TODO: session stopped because we stopped it or because the other end did ?
+ * TODO: restore NSF !!
*/
-static int
-bgp_session_has_stopped(bgp_peer peer)
+static void
+bgp_session_has_stopped(bgp_session session)
{
- bgp_session session = peer->session ;
+ peer_down_t why_down ;
- assert(bgp_session_is_active(session)) ;
- bgp_peer_disable(peer, NULL);
- /* TODO: needs to deal with NOTIFICATION, if any ?? */
+ bgp_peer peer = session->peer ;
+ assert(peer->session == session) ; /* Safety first */
- return 0;
-}
+ assert(bgp_session_is_active(session)) ; /* "confused" if not */
+
+ if (session->state == bgp_session_sEstablished)
+ {
+ /* This code has been moved from where it was, in bgp_write */
+ /* TODO: not clear whether v_start handling is still correct */
+ peer->v_start *= 2;
+ if (peer->v_start >= (60 * 2))
+ peer->v_start = (60 * 2);
+ } ;
+
+ if (session->notification == NULL)
+ why_down = PEER_DOWN_CLOSE_SESSION ;
+ else
+ {
+ if (session->notification->received)
+ why_down = PEER_DOWN_NOTIFY_RECEIVED ;
+ else
+ why_down = bgp_peer_map_notification(session->notification) ;
+ } ;
+
+ bgp_peer_down_notify(peer, why_down, session->notification) ;
+} ;
/*------------------------------------------------------------------------------
- * State change to sDisabled, session mutex locked
+ * BGP Session is now disabled -> can now move peer on to next state.
*
- * The BGP Engine has acknowledged the disable request.
+ * The BGP Engine has closed the session in response to a disable request, and
+ * no longer has an interest in it, and has signalled that.
*/
-static int
-bgp_session_has_disabled(bgp_peer peer)
+static void
+bgp_session_has_disabled(bgp_session session)
{
- bgp_session session = peer->session;
+ bgp_peer peer = session->peer ;
+ assert(peer->session == session) ; /* Safety first */
assert(session->state == bgp_session_sLimping) ;
session->state = bgp_session_sDisabled ;
- /* Immediately discard any other messages for this session. */
+ /* Immediately discard any other messages for this session. */
mqueue_revoke(routing_nexus->queue, session) ;
- /* does the peer need to be re-enabled? */
- if (session->defer_enable || peer->state == bgp_peer_sIdle)
- {
- session->defer_enable = 0;
- bgp_peer_enable(peer);
- }
- else if (peer->state == bgp_peer_sEstablished)
- {
- /* disable the peer */
- bgp_peer_stop(peer);
- peer_change_status(peer, bgp_peer_sClearing);
- bgp_clear_route_all(peer);
- }
-
- /* if the program is terminating then see if this was the last session
- * and if so ... die ....
+ /* If the session is marked "delete_me", do that.
+ *
+ * Otherwise, Old session now gone, so re-enable peer if now possible.
*/
- program_terminate_if_all_disabled();
- return 0;
-}
+ if (session->delete_me)
+ bgp_session_delete(peer) ; /* NB: this may also delete the peer. */
+ else
+ bgp_peer_enable(peer);
+} ;
-/* Administrative BGP peer stop event. */
-/* May be called multiple times for the same peer */
-int
-bgp_peer_stop (struct peer *peer)
+/*------------------------------------------------------------------------------
+ * Administrative BGP peer stop event -- stop pEstablished peer.
+ *
+ * MUST be pEstablished.
+ *
+ * Changes to pClearing and sets off to clear down all routes etc, subject to
+ * the required NSF.
+ *
+ * On exit the peer will be:
+ *
+ * - pIdle if the clearing of routes etc completed immediately.
+ *
+ * - pClearing if further work for clearing of routes has been scheduled
+ * for later.
+ *
+ * NB: Leaves any Max Prefix Timer running.
+ *
+ * Starts Graceful Restart and Stale Route timers iff NSF and at least one
+ * afi/safi is enabled for NSF.
+ */
+static void
+bgp_peer_stop (struct peer *peer, bool nsf)
{
- afi_t afi;
- safi_t safi;
- char orf_name[BUFSIZ];
+ bool cleared ;
- /* Can't do this in Clearing; events are used for state transitions */
- if (peer->state != bgp_peer_sClearing)
- {
- /* Delete all existing events of the peer */
- BGP_EVENT_FLUSH (peer);
- }
+ assert(peer->state == bgp_peer_pEstablished) ;
- /* Increment Dropped count. */
- if (peer->state == bgp_peer_sEstablished)
- {
- peer->dropped++;
+ /* Change state to pClearing.
+ *
+ * Turns off all timers.
+ */
+ bgp_peer_change_status(peer, bgp_peer_pClearing) ;
- /* bgp log-neighbor-changes of neighbor Down */
- if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
- zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
- peer_down_str [(int) peer->last_reset]);
+ peer->dropped++ ;
+ peer->resettime = time (NULL) ;
- /* graceful restart */
- if (peer->t_gr_stale)
- {
- BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- {
- if (BGP_DEBUG (events, EVENTS))
- {
- zlog_debug ("%s graceful restart timer started for %d sec",
- peer->host, peer->v_gr_restart);
- zlog_debug ("%s graceful restart stalepath timer started for %d sec",
- peer->host, peer->bgp->stalepath_time);
- }
- BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire,
- peer->v_gr_restart);
- BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire,
- peer->bgp->stalepath_time);
- }
- else
- {
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+ /* bgp log-neighbor-changes of neighbor Down */
+ if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
+ zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
+ peer_down_str [(int) peer->last_reset]);
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
- peer->nsf[afi][safi] = 0;
+ /* Clear out routes, with NSF if required.
+ *
+ * Sets PEER_STATUS_NSF_WAIT iff NSF and at least one afi/safi is enabled
+ * for NSF. Clears PEER_STATUS_NSF_WAIT otherwise.
+ */
+ cleared = bgp_clear_all_routes (peer, nsf) ;
+
+ /* graceful restart */
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ {
+ if (BGP_DEBUG (events, EVENTS))
+ {
+ zlog_debug ("%s graceful restart timer started for %d sec",
+ peer->host, peer->v_gr_restart);
+ zlog_debug ("%s graceful restart stalepath timer started for %d sec",
+ peer->host, peer->bgp->stalepath_time);
}
+ BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire,
+ peer->v_gr_restart);
+ BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire,
+ peer->bgp->stalepath_time);
+ } ;
- /* set last reset time */
- peer->resettime = time (NULL);
- /* Reset uptime. */
- bgp_uptime_reset (peer);
+ /* Reset uptime. */
+ bgp_uptime_reset (peer);
#ifdef HAVE_SNMP
- bgpTrapBackwardTransition (peer);
+ bgpTrapBackwardTransition (peer);
#endif /* HAVE_SNMP */
- /* Reset uptime. */
- bgp_uptime_reset (peer);
+ /* Reset peer synctime */
+ peer->synctime = 0;
- /* Reset peer synctime */
- peer->synctime = 0;
- }
+ /* If completed the clearing of routes, then can now go pIdle */
+ if (cleared)
+ bgp_peer_change_status(peer, bgp_peer_pIdle) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Clear out any stale routes, cancel any Graceful Restart timers.
+ *
+ * NB: may still be pClearing from when peer went down leaving these stale
+ * routes.
+ *
+ * NB: assumes clearing stale routes will complete immediately !
+ */
+static void
+bgp_peer_clear_all_stale_routes (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ if (peer->nsf[afi][safi])
+ bgp_clear_stale_route (peer, afi, safi);
+
+ bgp_graceful_restart_timer_cancel(peer) ;
+ bgp_graceful_stale_timer_cancel(peer) ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+} ;
+
+/*------------------------------------------------------------------------------
+ * If waiting for NSF peer to come back, stop now.
+ *
+ * When a session stops -- see bgp_peer_stop(), above -- the peer is set
+ * PEER_STATUS_NSF_WAIT iff there are now stale routes in the table, waiting
+ * for peer to come back.
+ *
+ * This function terminates that wait and clears out any stale routes, and
+ * cancels any timers.
+ *
+ * Also clears down all NSF flags.
+ *
+ * If is PEER_STATUS_NSF_WAIT, MUST be pIdle or pClearing.
+ *
+ * NB: may still be pClearing from when peer went down leaving these stale
+ * routes.
+ *
+ * NB: assumes clearing stale routes will complete immediately !
+ */
+static void
+bgp_peer_nsf_stop (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT))
+ {
+ assert( (peer->state == bgp_peer_pIdle)
+ || (peer->state == bgp_peer_pClearing) ) ;
+
+ bgp_peer_clear_all_stale_routes (peer) ;
+ } ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+ peer->nsf[afi][safi] = 0;
+} ;
- /* Stop all timers. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
+/*------------------------------------------------------------------------------
+ * Set the PEER_FLAG_SHUTDOWN flag and also:
+ *
+ * - turn off any NSF and related timers.
+ *
+ * - turn off any Max Prefix overflow and related timers.
+ */
+static void
+bgp_peer_shutdown(struct peer *peer)
+{
+ SET_FLAG (peer->flags, PEER_FLAG_SHUTDOWN) ;
+
+ bgp_maximum_prefix_cancel_timer(peer) ;
+
+ bgp_peer_nsf_stop (peer) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Reset state as peer goes to pIdle.
+ *
+ * This tidies things up, ready for session to be enabled again.
+ *
+ * NB: can be called any number of times... either to tidy up or to prepare
+ * for session to be enabled.
+ */
+static void
+bgp_peer_reset_idle(struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+ char orf_name[BUFSIZ];
+
+ assert(peer->state == bgp_peer_pIdle) ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE) ;
peer->cap = 0 ;
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
@@ -430,8 +660,9 @@ bgp_peer_stop (struct peer *peer)
{
/* Reset all negotiated variables */
peer->afc_nego[afi][safi] = 0;
- peer->afc_adv[afi][safi] = 0;
+ peer->afc_adv[afi][safi] = 0;
peer->afc_recv[afi][safi] = 0;
+ peer->nsf[afi][safi] = 0;
/* peer address family capability flags*/
peer->af_cap[afi][safi] = 0;
@@ -445,7 +676,7 @@ bgp_peer_stop (struct peer *peer)
/* ORF received prefix-filter pnt */
sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
prefix_bgp_orf_remove_all (orf_name);
- }
+ } ;
/* Reset keepalive and holdtime */
if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
@@ -457,283 +688,38 @@ bgp_peer_stop (struct peer *peer)
{
peer->v_keepalive = peer->bgp->default_keepalive;
peer->v_holdtime = peer->bgp->default_holdtime;
- }
-
-#if 0
- /* Reset prefix count */
- peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
- peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
- peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
- peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
- peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
-#endif
-
- return 0;
-}
-
-/*------------------------------------------------------------------------------
- * When a bgp_clear_route_all completes, this is called to move the peer state
- * on, if required.
- */
-extern void
-bgp_peer_clearing_completed(struct peer *peer)
-{
- /* Flush the event queue and ensure the peer is shut down */
- bgp_peer_stop(peer);
- BGP_EVENT_FLUSH (peer);
-
- if (peer->state == bgp_peer_sClearing)
- {
- peer_change_status (peer, bgp_peer_sIdle);
- /* enable peer if required */
- bgp_peer_enable(peer);
- }
+ } ;
} ;
-#if 0
-/* Stop all timers for the given peer
+/*------------------------------------------------------------------------------
+ * Allocate new peer object, implicitly locked.
*/
-static void
-bgp_peer_timers_stop(bgp_peer peer)
-{
- BGP_TIMER_OFF(peer->t_asorig) ;
- BGP_TIMER_OFF(peer->t_routeadv) ;
-
- BGP_TIMER_OFF (peer->t_gr_restart);
- BGP_TIMER_OFF (peer->t_gr_stale);
- BGP_TIMER_OFF (peer->t_pmax_restart);
-} ;
-#endif
-
-static void
-bgp_timer_set (struct peer *peer)
-{
- switch (peer->state)
- {
- case bgp_peer_sIdle:
- /* First entry point of peer's finite state machine. In Idle
- status start timer is on unless peer is shutdown or peer is
- inactive. All other timer must be turned off */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-
-#if 0
- case Connect:
- /* After start timer is expired, the peer moves to Connnect
- status. Make sure start timer is off and connect timer is
- on. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-
- case Active:
- /* Active is waiting connection from remote peer. And if
- connect timer is expired, change status to Connect. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-
- case OpenSent:
- /* OpenSent status. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-
- case OpenConfirm:
- /* OpenConfirm status. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-#endif
-
- case bgp_peer_sEstablished:
- /* In Established status start and connect timer is turned
- off. */
- BGP_TIMER_OFF (peer->t_asorig);
- break;
- case bgp_peer_sDeleted:
- BGP_TIMER_OFF (peer->t_gr_restart);
- BGP_TIMER_OFF (peer->t_gr_stale);
- BGP_TIMER_OFF (peer->t_pmax_restart);
- case bgp_peer_sClearing:
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
- default:
- assert(0);
- }
-}
-
-static int
-bgp_routeadv_timer (struct thread *thread)
-{
- struct peer *peer;
- uint32_t jittered ;
- uint32_t jitter ;
-
- peer = THREAD_ARG (thread);
- peer->t_routeadv = NULL;
-
- if (BGP_DEBUG (fsm, FSM))
- zlog (peer->log, LOG_DEBUG,
- "%s [FSM] Timer (routeadv timer expire)",
- peer->host);
-
- peer->synctime = time (NULL);
-
- bgp_write(peer, NULL);
-
- /* Apply +/- 10% jitter to the route advertise timer.
- *
- * The time is in seconds, so for anything less than 10 seconds this forced
- * to be +/- 1 second.
- */
- jittered = jitter = peer->v_routeadv ;
- if (jitter < 10)
- jitter = 10 ;
- jittered = (jittered * 90) + (rand() % (jitter * 20)) ; /* jitter is +/-10% */
- jittered = (jittered + 50) / 100 ;
-
- /* TODO: move this to the Routeing Engine qtimer pile. */
- BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, jittered) ;
-
- return 0;
-}
-
-/* Reset bgp update timer */
-static void
-bgp_uptime_reset (struct peer *peer)
-{
- peer->uptime = time (NULL);
-}
-
-/* BGP Peer Down Cause */
-const char *peer_down_str[] =
-{
- "",
- "Router ID changed",
- "Remote AS changed",
- "Local AS change",
- "Cluster ID changed",
- "Confederation identifier changed",
- "Confederation peer changed",
- "RR client config change",
- "RS client config change",
- "Update source change",
- "Address family activated",
- "Admin. shutdown",
- "User reset",
- "BGP Notification received",
- "BGP Notification send",
- "Peer closed the session",
- "Neighbor deleted",
- "Peer-group add member",
- "Peer-group delete member",
- "Capability changed",
- "Passive config change",
- "Multihop config change",
- "NSF peer closed the session"
-};
-
-static int
-bgp_graceful_restart_timer_expire (struct thread *thread)
-{
- struct peer *peer;
- afi_t afi;
- safi_t safi;
-
- peer = THREAD_ARG (thread);
- peer->t_gr_restart = NULL;
-
- /* NSF delete stale route */
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
- if (peer->nsf[afi][safi])
- bgp_clear_stale_route (peer, afi, safi);
-
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
- BGP_TIMER_OFF (peer->t_gr_stale);
-
- if (BGP_DEBUG (events, EVENTS))
- {
- zlog_debug ("%s graceful restart timer expired", peer->host);
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
-
- bgp_timer_set (peer);
-
- return 0;
-}
-
-static int
-bgp_graceful_stale_timer_expire (struct thread *thread)
-{
- struct peer *peer;
- afi_t afi;
- safi_t safi;
-
- peer = THREAD_ARG (thread);
- peer->t_gr_stale = NULL;
-
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart stalepath timer expired", peer->host);
-
- /* NSF delete stale route */
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
- if (peer->nsf[afi][safi])
- bgp_clear_stale_route (peer, afi, safi);
-
- return 0;
-}
-
-#if 0
-/* BGP peer is stopped by the error. */
-static int
-bgp_stop_with_error (struct peer *peer)
-{
- /* Double start timer. */
- peer->v_start *= 2;
-
- /* Overflow check. */
- if (peer->v_start >= (60 * 2))
- peer->v_start = (60 * 2);
-
- bgp_stop (peer);
-
- return 0;
-}
-#endif
-
-/* Allocate new peer object, implicitly locked. */
struct peer *
-peer_new (struct bgp *bgp)
+bgp_peer_new (struct bgp *bgp)
{
afi_t afi;
safi_t safi;
struct peer *peer;
struct servent *sp;
- /* bgp argument is absolutely required */
+ /* bgp argument is absolutely required */
assert (bgp);
- if (!bgp)
- return NULL;
+ bgp_lock (bgp);
- /* Allocate new peer. */
+ /* Allocate new peer. */
peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer));
/* Set default value. */
- peer->v_start = BGP_INIT_START_TIMER;
+ peer->v_start = BGP_INIT_START_TIMER;
peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
- peer->v_asorig = BGP_DEFAULT_ASORIGINATE;
- peer->state = bgp_peer_sIdle;
- peer->ostate = bgp_peer_sIdle;
- peer->weight = 0;
- peer->password = NULL;
- peer->bgp = bgp;
- peer = peer_lock (peer); /* initial reference */
- bgp_lock (bgp);
+ peer->v_asorig = BGP_DEFAULT_ASORIGINATE;
+ peer->state = bgp_peer_pIdle;
+ peer->ostate = bgp_peer_pIdle;
+ peer->weight = 0;
+ peer->password = NULL;
+ peer->bgp = bgp;
+
+ peer = bgp_peer_lock (peer); /* initial reference */
/* Set default flags. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
@@ -762,32 +748,41 @@ peer_new (struct bgp *bgp)
return peer;
}
-/* Create new BGP peer. */
+/*------------------------------------------------------------------------------
+ * Create new BGP peer -- if an AFI/SAFI is given, activate & enable for that.
+ *
+ * Peer starts in pIdle state.
+ *
+ * This is creating a PEER_STATUS_REAL_PEER, which is placed on the bgp->peer
+ * list.
+ */
struct peer *
-peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
- as_t remote_as, afi_t afi, safi_t safi)
+bgp_peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
+ as_t remote_as, afi_t afi, safi_t safi)
{
- int active;
struct peer *peer;
+ bool enable = (afi != 0) && (safi != 0) ;
+
+ /* TODO: should bgp_peer_new() set state pNull ?? */
+ peer = bgp_peer_new (bgp); /* sets peer->state == pIdle */
- peer = peer_new (bgp);
- peer->su = *su;
- peer->local_as = local_as;
- peer->as = remote_as;
- peer->local_id = bgp->router_id;
- peer->v_holdtime = bgp->default_holdtime;
+ peer->su = *su;
+ peer->local_as = local_as;
+ peer->as = remote_as;
+ peer->local_id = bgp->router_id;
+ peer->v_holdtime = bgp->default_holdtime;
peer->v_keepalive = bgp->default_keepalive;
if (peer_sort (peer) == BGP_PEER_IBGP)
peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- peer = peer_lock (peer); /* bgp peer list reference */
+ SET_FLAG(peer->sflags, PEER_STATUS_REAL_PEER) ;
+ peer = bgp_peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
- /* If "default ipv4-unicast", then this is implicit "activate" */
- active = peer_active (peer);
- if (afi && safi)
+ /* If required, activate given AFI/SAFI -- eg "default ipv4-unicast" */
+ if (enable)
peer->afc[afi][safi] = 1;
/* Last read time set */
@@ -802,70 +797,102 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
/* Make peer's address string. */
peer->host = sockunion_su2str (su, MTYPE_BGP_PEER_HOST) ;
- /* register */
+ /* session -- NB: *before* peer is registered, so before any possible
+ * lookup up by accept() in the BGP Engine
+ */
+ bgp_session_init_new(peer);
+
+ /* register -- NB: *after* peer->session set, so safe */
bgp_peer_index_register(peer, &peer->su);
- /* session */
- peer->session = bgp_session_init_new(peer->session, peer);
+ /* Fire up any timers that should run during pIdle */
+ bgp_peer_timers_set (peer);
- /* If implicit activate, Set up peer's events and timers. */
- if ((! active) && peer_active (peer))
- {
- bgp_timer_set (peer);
- bgp_peer_enable (peer);
- } ;
+ /* If require, enable now all is ready */
+ if (enable)
+ bgp_peer_enable(peer) ;
return peer;
}
-/* Delete peer from configuration.
+/*------------------------------------------------------------------------------
+ * Delete peer from configuration.
*
* The peer is moved to a dead-end "Deleted" neighbour-state, to allow
* it to "cool off" and refcounts to hit 0, at which state it is freed.
*
- * This function /should/ take care to be idempotent, to guard against
- * it being called multiple times through stray events that come in
- * that happen to result in this function being called again. That
- * said, getting here for a "Deleted" peer is a bug in the neighbour
- * FSM.
*/
int
-peer_delete (struct peer *peer)
+bgp_peer_delete (struct peer *peer)
{
int i;
afi_t afi;
safi_t safi;
struct bgp *bgp;
struct bgp_filter *filter;
- struct listnode *pn;
- assert (peer->state != bgp_peer_sDeleted);
+ bgp = peer->bgp ;
- bgp = peer->bgp;
+ /* Once peer is pDeleting it should be impossible to find in order to
+ * bgp_peer_delete() it !
+ */
+ assert (peer->state != bgp_peer_pDeleting);
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
+ /* If the peer is active, then need to shut it down now. If there are any
+ * stale routes, flush them now.
+ *
+ * If the peer ends up in pClearing state, that implies that some background
+ * work is required to completely clear this peer. So increment the
+ * reference count to hold the peer in existence. That will be decremented
+ * again in bgp_peer_clearing_completed().
+ *
+ * If the peer ends up in sIdle state, that implies that any routes that
+ * needed clearing have been dealt with.
+ *
+ * There may be a session in existence. If so, it must either be sLimping or
+ * sDisabled.
+ *
+ * Changing to pDeleting state turns off all timers.
+ */
+ bgp_peer_down(peer, PEER_DOWN_NEIGHBOR_DELETE) ;
- /* If this peer belongs to peer group, clear up the
- relationship. */
- if (peer->group)
- {
- if ((pn = listnode_lookup (peer->group->peer, peer)))
- {
- peer = peer_unlock (peer); /* group->peer list reference */
- list_delete_node (peer->group->peer, pn);
- }
- peer->group = NULL;
- }
+ if (peer->state == bgp_peer_pClearing)
+ bgp_peer_lock (peer) ;
+ else
+ assert(peer->state == bgp_peer_pIdle) ;
+
+ bgp_peer_change_status (peer, bgp_peer_pDeleting);
- /* Withdraw all information from routing table. We can not use
- * BGP_EVENT_ADD (peer, BGP_Stop) at here. Because the event is
- * executed after peer structure is deleted.
+ /* Increment count of peers lingering in pDeleting
+ *
+ * The count is used while terminating bgpd -- keeps all the nexuses running
+ * until this count drops to zero.
*/
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_peer_stop (peer);
- peer_change_status (peer, bgp_peer_sDeleted);
- bgp_clear_route_all(peer);
+ bm->peer_linger_count++ ;
+
+ /* If is an rsclient in its own right, remove from rsclient list */
+ if (peer_rsclient_active (peer))
+ {
+ struct listnode *pn;
+ pn = listnode_lookup (bgp->rsclient, peer) ;
+
+ bgp_peer_unlock (peer); /* rsclient list reference */
+ list_delete_node (bgp->rsclient, pn);
+ } ;
+
+ /* If this peer belongs to peer group, clear up the relationship. */
+ if (peer->group != NULL)
+ {
+ struct listnode *pn;
+ pn = listnode_lookup (peer->group->peer, peer) ;
+
+ assert(pn != NULL) ;
+
+ bgp_peer_unlock (peer); /* group->peer list reference */
+ list_delete_node (peer->group->peer, pn);
+
+ peer->group = NULL;
+ } ;
/* Password configuration */
if (peer->password)
@@ -874,36 +901,48 @@ peer_delete (struct peer *peer)
peer->password = NULL;
}
- bgp_timer_set (peer); /* stops all timers for Deleted */
-
- /* Delete from all peer list. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && (pn = listnode_lookup (bgp->peer, peer)))
+ /* Delete from bgp->peer list, if required. */
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_REAL_PEER))
{
- peer_unlock (peer); /* bgp peer list reference */
+ struct listnode *pn;
+ pn = listnode_lookup (bgp->peer, peer) ;
+
+ assert(pn != NULL) ;
+
+ bgp_peer_unlock (peer); /* bgp peer list reference */
list_delete_node (bgp->peer, pn);
- }
+ } ;
- if (peer_rsclient_active (peer)
- && (pn = listnode_lookup (bgp->rsclient, peer)))
- {
- peer_unlock (peer); /* rsclient list reference */
- list_delete_node (bgp->rsclient, pn);
+ /* Discard rsclient ribs which are owned by group
+ * and cross-check rib pointer and PEER_FLAG_RSERVER_CLIENT.
+ */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
+ {
+ assert(peer->rib[afi][safi] != NULL) ;
+ if (peer->af_group[afi][safi])
+ {
+ peer->rib[afi][safi] = NULL ;
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ;
+ } ;
+ }
+ else
+ assert(peer->rib[afi][safi] == NULL) ;
- /* Clear our own rsclient ribs. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_RSERVER_CLIENT))
- bgp_clear_route_rsclient(peer, afi, safi);
- }
+ /* Can now clear any rsclient ribs. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (peer->rib[afi][safi] != NULL)
+ {
+ bgp_clear_rsclient_rib(peer, afi, safi) ;
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ;
+ } ;
- /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not
- member of a peer_group. */
+ /* Have now finished with any rsclient ribs */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- if (peer->rib[afi][safi] && ! peer->af_group[afi][safi])
- bgp_table_finish (&peer->rib[afi][safi]);
+ bgp_table_finish (&peer->rib[afi][safi]) ;
/* Buffers. */
if (peer->ibuf)
@@ -955,27 +994,89 @@ peer_delete (struct peer *peer)
peer->default_rmap[afi][safi].name = NULL;
}
- peer_unlock (peer); /* initial reference */
+ /* Unregister the peer.
+ *
+ * NB: the peer can no longer be looked up by its 'name'.
+ *
+ * In particular this means that the accept() logic in the BGP Engine
+ * will conclude that the session should not be accepting connections.
+ *
+ * NB: also (currently) releases the peer_id -- which may not be so clever ?
+ */
+ if (peer->index_entry != NULL)
+ bgp_peer_index_deregister(peer, &peer->su);
+
+ /* Tear down session, if any and if possible. */
+ bgp_session_delete(peer) ;
+
+ /* Finally: count down the initial reference, which will delete the peer
+ * iff everything else has finished with it.
+ */
+ bgp_peer_unlock (peer); /* initial reference */
return 0;
+} ;
+
+/*------------------------------------------------------------------------------
+ * increase reference count on a struct peer
+ */
+struct peer *
+bgp_peer_lock (struct peer *peer)
+{
+ assert (peer && (peer->lock >= 0));
+
+ peer->lock++;
+
+ return peer;
}
-void
-peer_free (struct peer *peer)
+/*------------------------------------------------------------------------------
+ * decrease reference count on a struct peer
+ *
+ * If is last reference, the structure is freed and NULL returned
+ */
+struct peer *
+bgp_peer_unlock (struct peer *peer)
{
- assert (peer->state == bgp_peer_sDeleted);
+ assert (peer && (peer->lock > 0));
- bgp_unlock(peer->bgp);
+ peer->lock--;
- /* this /ought/ to have been done already through bgp_stop earlier,
- * but just to be sure..
- */
- bgp_timer_set (peer);
- BGP_EVENT_FLUSH (peer);
+ if (peer->lock == 0)
+ {
+#if 0
+ zlog_debug ("unlocked and freeing");
+ zlog_backtrace (LOG_DEBUG);
+#endif
+ bgp_peer_free (peer);
+ return NULL;
+ }
- /* unregister */
- if (peer->index_entry != NULL)
- bgp_peer_index_deregister(peer, &peer->su);
+#if 0
+ if (peer->lock == 1)
+ {
+ zlog_debug ("unlocked to 1");
+ zlog_backtrace (LOG_DEBUG);
+ }
+#endif
+
+ return peer;
+}
+
+/*------------------------------------------------------------------------------
+ * Dismantle and free peer data structure.
+ */
+static void
+bgp_peer_free (struct peer *peer)
+{
+ struct bgp* bgp ;
+
+ assert (peer->state == bgp_peer_pDeleting);
+ assert (peer->session == NULL) ; /* session holds a lock on peer */
+
+ bm->peer_linger_count-- ;
+
+ bgp = peer->bgp ;
if (peer->desc)
XFREE (MTYPE_PEER_DESC, peer->desc);
@@ -991,110 +1092,785 @@ peer_free (struct peer *peer)
if (peer->update_if)
XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- if (peer->clear_node_queue)
- work_queue_free (peer->clear_node_queue);
-
- /* session */
- if (peer->session)
- bgp_session_free(peer->session);
-
bgp_sync_delete (peer);
- memset (peer, 0, sizeof (struct peer));
+ memset (peer, 0, sizeof (struct peer));
+ peer->lock = -54321 ;
XFREE (MTYPE_BGP_PEER, peer);
-}
+ bgp_unlock(bgp);
+} ;
+
+/*------------------------------------------------------------------------------
+ * Enable Peer
+ *
+ * This means that something has changed, and session can be started, if no
+ * session has already started.
+ *
+ * So does nothing unless in pIdle, and expects the session state to be:
+ *
+ * - sIdle, sDisabled or no session at all -- session enabled if possible
+ *
+ * - sEnabled -- session already enabled, so do nothing
+ *
+ * - sEstablished -- IMPOSSIBLE
+ *
+ * - sLimping -- cannot, yet, start a new session -- that will happen in due
+ * course.
+ *
+ * This means that any change which requires the session to be taken down and
+ * restarted needs to call bgp_peer_disable().
+ *
+ * The other peer states:
+ *
+ * - pEstablished == sEstablished
+ *
+ * - pClearing -- cannot restart the peer yet, that will happen in due course.
+ *
+ * - pDeleted -- Enable peer makes no sense... asserts invalid.
+ *
+ * TODO: assert !pEstablished in bgp_peer_enable ?
+ */
void
-peer_nsf_stop (struct peer *peer)
+bgp_peer_enable(bgp_peer peer)
{
- afi_t afi;
- safi_t safi;
+ switch (peer->state)
+ {
+ case bgp_peer_pIdle:
+
+ /* Enable the session unless:
+ * 1) session is active -- ie sEnabled/sLimping (see above)
+ * 2) no address family is activated
+ * 3) the peer has been shutdown
+ * 4) is dealing with prefix overflow (waiting for timer)
+ */
+
+ if (bgp_session_is_active(peer->session))
+ assert(peer->session->state != bgp_session_sEstablished) ;
+ else
+ {
+ if (peer_active (peer)
+ && !CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)
+ && !CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
+ {
+ /* enable the session */
+ zlog_err ("%s: enabling peer %s:", __func__, peer->host) ;
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+ bgp_peer_reset_idle(peer) ; /* tidy up */
+ bgp_session_enable(peer);
+ } ;
+ } ;
+ break ;
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
- peer->nsf[afi][safi] = 0;
+ case bgp_peer_pEstablished:
+ break ;
- if (peer->t_gr_restart)
+ case bgp_peer_pClearing:
+ break ;
+
+ case bgp_peer_pDeleting:
+ zabort("cannot enable a pDeleting peer") ;
+ break ;
+
+ default:
+ zabort("unknown peer->state") ;
+ break ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Down Peer -- bring down any existing session and restart if possible.
+ *
+ * The following "why_down" values are special:
+ *
+ * - PEER_DOWN_NSF_CLOSE_SESSION
+ *
+ * causes NSF to be turned on as the peer is stopped and routes are cleared.
+ *
+ * - PEER_DOWN_USER_SHUTDOWN
+ *
+ * causes the peer to be shutdown -- so won't restart.
+ *
+ * - PEER_DOWN_NEIGHBOR_DELETE
+ *
+ * prevents the peer from restarting.
+ *
+ * If there is an active session, then it must be disabled, sending the given
+ * notification, or one based on the reason for downing the peer.
+ *
+ * If there is no active session, any stale NSF routes will be cleared.
+ *
+ * So any session ends up as:
+ *
+ * sIdle -- wasn't active and still isn't
+ *
+ * sLimping -- was sEnabled or sEstablished, we now wait for BGP Engine
+ * to complete the disable action and signal when done.
+ *
+ * sDisabled -- has previously been disabled.
+ *
+ * The result depends on the initial peer state:
+ *
+ * 1. bgp_peer_pIdle
+ *
+ * Any session that was sEnabled will have been disabled -- and will now
+ * be sLimping.
+ *
+ * The peer will have automatically restarted, if possible.
+ *
+ * Noting that PEER_DOWN_USER_SHUTDOWN and PEER_DOWN_NEIGHBOR_DELETE both
+ * prevent any restart.
+ *
+ * 2. bgp_peer_pEstablished
+ *
+ * The session will have been disabled -- and will now be sLimping.
+ *
+ * See bgp_peer_stop() for the state of the peer.
+ *
+ * 3. bgp_peer_pClearing
+ *
+ * In this state the session can only be:
+ *
+ * sLimping -- session disable has been sent to the BGP Engine.
+ * sDisabled -- session has been disabled by the BGP Engine
+ *
+ * because peer must have been pEstablished immediately before.
+ *
+ * Do nothing -- will proceed to pIdle in due course.
+ *
+ * 4. bgp_peer_pDeleting
+ *
+ * In this state there may be no session at all, or the session can
+ * only be:
+ *
+ * sIdle -- session never got going
+ * sLimping -- session disable has been sent to the BGP Engine.
+ * sDisabled -- session has been disabled by the BGP Engine
+ *
+ * Do nothing -- peer will be deleted in due course.
+ */
+void
+bgp_peer_down(bgp_peer peer, peer_down_t why_down)
+{
+ bgp_peer_down_notify(peer, why_down, NULL) ;
+} ;
+
+static void
+bgp_peer_down_notify(bgp_peer peer, peer_down_t why_down,
+ bgp_notify notification)
+{
+ /* Deal with session (if any). */
+
+ if (bgp_session_is_active(peer->session))
{
- BGP_TIMER_OFF (peer->t_gr_restart);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart timer stopped", peer->host);
+ if (notification == NULL)
+ notification = bgp_peer_map_peer_down(why_down) ;
+
+ bgp_notify_set_dup(&peer->session->notification, notification) ;
+
+ bgp_session_disable(peer, notification) ;
}
- if (peer->t_gr_stale)
+ else
+ bgp_notify_free(notification) ; /* Discard unused notification */
+
+ /* Now worry about the state of the peer */
+
+ if (why_down == PEER_DOWN_USER_SHUTDOWN)
+ bgp_peer_shutdown(peer) ;
+
+ if (why_down != PEER_DOWN_NULL)
+ peer->last_reset = why_down ;
+
+ switch (peer->state)
+ {
+ case bgp_peer_pIdle:
+ assert(!bgp_session_is_active(peer->session)
+ || (peer->session->state == bgp_session_sLimping)) ;
+
+ bgp_peer_nsf_stop (peer) ; /* flush stale routes, if any */
+
+ if (why_down != PEER_DOWN_NEIGHBOR_DELETE)
+ bgp_peer_enable(peer) ; /* Restart if possible. */
+
+ break ;
+
+ case bgp_peer_pEstablished:
+ assert(peer->session->state == bgp_session_sLimping) ;
+
+ bgp_peer_stop(peer, why_down == PEER_DOWN_NSF_CLOSE_SESSION) ;
+
+ break ;
+
+ case bgp_peer_pClearing:
+ assert( (peer->session->state == bgp_session_sLimping)
+ || (peer->session->state == bgp_session_sDisabled) ) ;
+
+ bgp_peer_nsf_stop (peer) ; /* flush stale routes, if any */
+
+ break ;
+
+ case bgp_peer_pDeleting:
+ assert( (peer->session == NULL)
+ || (peer->session->state == bgp_session_sIdle)
+ || (peer->session->state == bgp_session_sLimping)
+ || (peer->session->state == bgp_session_sDisabled) ) ;
+ break ;
+
+ default:
+ zabort("unknown peer->state") ;
+ break ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Notify the far end that an error has been detected, and close down the
+ * session.
+ *
+ * The session will have been established, so the IdleHoldTime will be extended.
+ *
+ * Because it knows no better, the session will be restarted.
+ */
+extern void
+bgp_peer_down_error(struct peer* peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode)
+{
+ bgp_peer_down_error_with_data (peer, code, subcode, NULL, 0);
+}
+
+/*------------------------------------------------------------------------------
+ * Notify the far end that an error has been detected, and close down the
+ * session.
+ *
+ * Same as above, except that this accepts a data part for the notification
+ * message.
+ */
+extern void
+bgp_peer_down_error_with_data (struct peer* peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode,
+ const u_int8_t* data, size_t datalen)
+{
+ bgp_notify notification;
+ notification = bgp_notify_new_with_data(code, subcode, data, datalen);
+
+ bgp_peer_down_notify(peer, bgp_peer_map_notification(notification),
+ notification) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Construct notification based on the reason for bringing down the session
+ *
+ * Where the session is brought down by the other end, returns NULL.
+ */
+static bgp_notify
+bgp_peer_map_peer_down(peer_down_t why_down)
+{
+ bgp_nom_code_t code ;
+ bgp_nom_subcode_t subcode ;
+
+ assert((why_down >= PEER_DOWN_first) && (why_down < PEER_DOWN_count)) ;
+
+ code = BGP_NOMC_CEASE ; /* Default values */
+ subcode = BGP_NOMS_UNSPECIFIC ;
+
+ switch(why_down)
+ {
+ case PEER_DOWN_NULL:
+ return NULL ;
+
+ /* Session taken down at this end for some unspecified reason */
+
+ case PEER_DOWN_UNSPECIFIED:
+ break ;
+
+ /* Configuration changes that cause a session to be reset. */
+
+ case PEER_DOWN_CONFIG_CHANGE:
+ case PEER_DOWN_RID_CHANGE:
+ case PEER_DOWN_REMOTE_AS_CHANGE:
+ case PEER_DOWN_LOCAL_AS_CHANGE:
+ case PEER_DOWN_CLID_CHANGE:
+ case PEER_DOWN_CONFED_ID_CHANGE:
+ case PEER_DOWN_CONFED_PEER_CHANGE:
+ case PEER_DOWN_RR_CLIENT_CHANGE:
+ case PEER_DOWN_RS_CLIENT_CHANGE:
+ case PEER_DOWN_UPDATE_SOURCE_CHANGE:
+ case PEER_DOWN_AF_ACTIVATE:
+ case PEER_DOWN_RMAP_BIND:
+ case PEER_DOWN_RMAP_UNBIND:
+ case PEER_DOWN_CAPABILITY_CHANGE:
+ case PEER_DOWN_PASSIVE_CHANGE:
+ case PEER_DOWN_MULTIHOP_CHANGE:
+ case PEER_DOWN_AF_DEACTIVATE:
+ case PEER_DOWN_PASSWORD_CHANGE:
+ case PEER_DOWN_ALLOWAS_IN_CHANGE:
+ subcode = BGP_NOMS_C_CONFIG ;
+ break ;
+
+ /* Other actions that cause a session to be reset */
+
+ case PEER_DOWN_USER_SHUTDOWN:
+ subcode = BGP_NOMS_C_SHUTDOWN ;
+ break ;
+
+ case PEER_DOWN_USER_RESET:
+ subcode = BGP_NOMS_C_RESET ;
+ break ;
+
+ case PEER_DOWN_NEIGHBOR_DELETE:
+ subcode = BGP_NOMS_C_DECONFIG ;
+ break ;
+
+ case PEER_DOWN_INTERFACE_DOWN:
+ return NULL ; /* nowhere to send a notification ! */
+
+ /* Errors and problems that cause a session to be reset */
+ /* */
+ /* SHOULD really have a notification constructed for these, but for */
+ /* completeness construct an "unspecified" for these. */
+
+ case PEER_DOWN_MAX_PREFIX:
+ subcode = BGP_NOMS_C_MAX_PREF ;
+ break ;
+
+ case PEER_DOWN_HEADER_ERROR:
+ code = BGP_NOMC_HEADER ;
+ break ;
+
+ case PEER_DOWN_OPEN_ERROR:
+ code = BGP_NOMC_OPEN ;
+ break ;
+
+ case PEER_DOWN_UPDATE_ERROR:
+ code = BGP_NOMC_UPDATE ;
+ break ;
+
+ case PEER_DOWN_HOLD_TIMER:
+ code = BGP_NOMC_HOLD_EXP ;
+ break ;
+
+ case PEER_DOWN_FSM_ERROR:
+ code = BGP_NOMC_FSM ;
+ break ;
+
+ case PEER_DOWN_DYN_CAP_ERROR:
+ code = BGP_NOMC_DYN_CAP ;
+ break ;
+
+ /* Things the far end can do to cause a session to be reset */
+
+ case PEER_DOWN_NOTIFY_RECEIVED:
+ return NULL ; /* should not get here ! */
+
+ case PEER_DOWN_CLOSE_SESSION:
+ case PEER_DOWN_NSF_CLOSE_SESSION:
+ return NULL ; /* nowhere to send a notification ! */
+
+ /* To keep the compiler happy. */
+ case PEER_DOWN_count:
+ break ; /* should have asserted already */
+ } ;
+
+ return bgp_notify_new(code, subcode) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Construct reason for bringing down the session based on the notification
+ */
+static peer_down_t
+bgp_peer_map_notification(bgp_notify notification)
+{
+ switch (bgp_notify_get_code(notification)) /* deals with NULL */
+ {
+ case BGP_NOMC_UNDEF:
+ break ;
+
+ case BGP_NOMC_HEADER:
+ return PEER_DOWN_HEADER_ERROR ;
+
+ case BGP_NOMC_OPEN:
+ return PEER_DOWN_OPEN_ERROR ;
+
+ case BGP_NOMC_UPDATE:
+ return PEER_DOWN_UPDATE_ERROR ;
+
+ case BGP_NOMC_HOLD_EXP:
+ return PEER_DOWN_HOLD_TIMER ;
+
+ case BGP_NOMC_FSM:
+ return PEER_DOWN_FSM_ERROR ;
+
+ case BGP_NOMC_CEASE:
+ switch (notification->subcode)
+ {
+ case BGP_NOMS_C_MAX_PREF:
+ return PEER_DOWN_MAX_PREFIX ;
+
+ case BGP_NOMS_C_SHUTDOWN:
+ return PEER_DOWN_USER_SHUTDOWN ;
+
+ case BGP_NOMS_C_DECONFIG:
+ return PEER_DOWN_NEIGHBOR_DELETE ;
+
+ case BGP_NOMS_C_RESET:
+ return PEER_DOWN_USER_RESET ;
+
+ case BGP_NOMS_C_REJECTED: /* should not get here */
+ return PEER_DOWN_NULL ;
+
+ case BGP_NOMS_C_CONFIG:
+ return PEER_DOWN_CONFIG_CHANGE ;
+
+ case BGP_NOMS_C_COLLISION: /* should not get here */
+ return PEER_DOWN_NULL ;
+
+ case BGP_NOMS_C_RESOURCES: /* not used */
+ return PEER_DOWN_NULL ;
+
+ default:
+ break ;
+ } ;
+ break ;
+
+ case BGP_NOMC_DYN_CAP:
+ return PEER_DOWN_DYN_CAP_ERROR ;
+
+ default:
+ break ;
+ } ;
+
+ return PEER_DOWN_UNSPECIFIED ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Background route clearing has completed.
+ *
+ * If there is any background work required to clear routes for a given peer,
+ * then when that completes, this is called to move the state of the peer
+ * forwards.
+ */
+extern void
+bgp_peer_clearing_completed(struct peer *peer)
+{
+ switch (peer->state)
+ {
+ case bgp_peer_pIdle:
+ case bgp_peer_pEstablished:
+ zabort("invalid peer->state") ;
+ break ;
+
+ case bgp_peer_pClearing:
+ bgp_peer_change_status (peer, bgp_peer_pIdle);
+ bgp_peer_enable(peer);
+ break ;
+
+ case bgp_peer_pDeleting:
+ bgp_peer_unlock (peer); /* route clearing "reference" */
+ break ;
+
+ default:
+ zabort("unknown peer->state") ;
+ break ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set new peer state.
+ *
+ * If state changes, do dump new state and log state change if required.
+ *
+ * In any case, set timers for the new state -- so if state hasn't changed,
+ * will restart those timers.
+ */
+static void
+bgp_peer_change_status (bgp_peer peer, bgp_peer_state_t new_state)
+{
+ if (peer->state != new_state)
{
+ bgp_dump_state (peer, peer->state, new_state);
+
+ /* Preserve old status and change into new status. */
+ peer->ostate = peer->state ;
+ peer->state = new_state ;
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s went from %s to %s", peer->host,
+ LOOKUP (bgp_peer_status_msg, peer->ostate),
+ LOOKUP (bgp_peer_status_msg, peer->state)) ;
+
+ if (new_state == bgp_peer_pIdle)
+ bgp_peer_reset_idle(peer) ; /* tidy up */
+ } ;
+
+ bgp_peer_timers_set (peer);
+} ;
+
+/*==============================================================================
+ * Timer handling
+ */
+
+static void
+bgp_peer_timers_set (struct peer *peer)
+{
+ switch (peer->state)
+ {
+ case bgp_peer_pIdle:
+ /* On entry to pIdle the Graceful Restart Timers are left running:
+ *
+ * - if no connection is established within the Graceful Restart time,
+ * then things are no longer graceful, and the stale routes have to
+ * be thrown away.
+ *
+ * - if routes do not thereafter arrive quickly enough, then the
+ * Graceful Stale time kicks in and stale routes will be thrown away.
+ */
+ BGP_TIMER_OFF (peer->t_routeadv) ;
+ BGP_TIMER_OFF (peer->t_pmax_restart) ;
+ break;
+
+ case bgp_peer_pEstablished:
+ /* On entry to pEstablished only the the Graceful Stale Timer is left
+ * running.
+ *
+ * Any Graceful Restart Timer can be cancelled -- have established in
+ * time.
+ */
+ BGP_TIMER_OFF (peer->t_routeadv) ;
+ BGP_TIMER_OFF (peer->t_pmax_restart) ;
+
+ bgp_graceful_restart_timer_cancel(peer) ;
+ break;
+
+ case bgp_peer_pClearing:
+ /* On entry to pClearing, turn off all timers.
+ *
+ * The Graceful Restart timer should not be running in any case.
+ *
+ * If the session is brought down quickly enough, the Graceful Stale
+ * timer may be running.
+ */
+ BGP_TIMER_OFF (peer->t_routeadv);
+ BGP_TIMER_OFF (peer->t_pmax_restart);
+ BGP_TIMER_OFF (peer->t_gr_restart);
+
+ bgp_graceful_stale_timer_cancel(peer) ;
+ break ;
+
+ case bgp_peer_pDeleting:
+ /* On entry to pDeleting, turn off all timers.
+ */
+ BGP_TIMER_OFF (peer->t_routeadv);
+ BGP_TIMER_OFF (peer->t_pmax_restart);
+ BGP_TIMER_OFF (peer->t_gr_restart);
BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
- bgp_clear_route_all (peer);
-}
+ break;
-/* enable the peer */
-void
-bgp_peer_enable(bgp_peer peer)
+ default:
+ assert(0);
+ } ;
+} ;
+
+static int
+bgp_routeadv_timer (struct thread *thread)
{
- /* Don't enable the session if:
- * 1) the peer not idle, which means not ready yet: clearing, deleting or
- * waiting for disable.
- * 2) no address family is activated
- * 3) the peer has been shutdown
- * 4) is dealing with prefix overflow: its timer will enable peer when ready
+ struct peer *peer;
+ uint32_t jittered ;
+ uint32_t jitter ;
+
+ peer = THREAD_ARG (thread);
+ peer->t_routeadv = NULL;
+
+ if (BGP_DEBUG (fsm, FSM))
+ zlog (peer->log, LOG_DEBUG,
+ "%s [FSM] Timer (routeadv timer expire)",
+ peer->host);
+
+ peer->synctime = time (NULL);
+
+ bgp_write(peer, NULL);
+
+ /* Apply +/- 10% jitter to the route advertise timer.
+ *
+ * The time is in seconds, so for anything less than 10 seconds this forced
+ * to be +/- 1 second.
*/
+ jittered = jitter = peer->v_routeadv ;
+ if (jitter < 10)
+ jitter = 10 ;
+ jittered = (jittered * 90) + (rand() % (jitter * 20)) ; /* jitter is +/-10% */
+ jittered = (jittered + 50) / 100 ;
- if ((peer->state == bgp_peer_sIdle)
- && peer_active (peer)
- && !CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)
- && !CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
- {
- /* enable the session */
- zlog_err ("%s: enabling peer %s:", __func__, peer->host) ;
+ /* TODO: move this to the Routeing Engine qtimer pile. */
+ BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, jittered) ;
- bgp_session_enable(peer);
- }
+ return 0;
+}
+
+/* Reset bgp update timer */
+static void
+bgp_uptime_reset (struct peer *peer)
+{
+ peer->uptime = time (NULL);
}
-/* disable the peer
- * sent notification, disable session
+/*------------------------------------------------------------------------------
+ * BGP Peer Down Causes mapped to strings
*/
-void
-bgp_peer_disable(bgp_peer peer, bgp_notify notification)
+const char *peer_down_str[] =
{
- if (bgp_session_is_active(peer->session))
- {
- /* This code has been moved from where it was, in bgp_write */
- /* TODO: not clear whether v_start handling is still correct */
- peer->v_start *= 2;
- if (peer->v_start >= (60 * 2))
- peer->v_start = (60 * 2);
+ [PEER_DOWN_NULL] = "",
+
+ [PEER_DOWN_UNSPECIFIED] = "Unspecified reason",
+
+ [PEER_DOWN_CONFIG_CHANGE] = "Unspecified config change",
+
+ [PEER_DOWN_RID_CHANGE] = "Router ID changed",
+ [PEER_DOWN_REMOTE_AS_CHANGE] = "Remote AS changed",
+ [PEER_DOWN_LOCAL_AS_CHANGE] = "Local AS change",
+ [PEER_DOWN_CLID_CHANGE] = "Cluster ID changed",
+ [PEER_DOWN_CONFED_ID_CHANGE] = "Confederation identifier changed",
+ [PEER_DOWN_CONFED_PEER_CHANGE] = "Confederation peer changed",
+ [PEER_DOWN_RR_CLIENT_CHANGE] = "RR client config change",
+ [PEER_DOWN_RS_CLIENT_CHANGE] = "RS client config change",
+ [PEER_DOWN_UPDATE_SOURCE_CHANGE] = "Update source change",
+ [PEER_DOWN_AF_ACTIVATE] = "Address family activated",
+ [PEER_DOWN_RMAP_BIND] = "Peer-group add member",
+ [PEER_DOWN_RMAP_UNBIND] = "Peer-group delete member",
+ [PEER_DOWN_CAPABILITY_CHANGE] = "Capability changed",
+ [PEER_DOWN_PASSIVE_CHANGE] = "Passive config change",
+ [PEER_DOWN_MULTIHOP_CHANGE] = "Multihop config change",
+ [PEER_DOWN_AF_DEACTIVATE] = "Address family deactivated",
+ [PEER_DOWN_PASSWORD_CHANGE] = "MD5 Password changed",
+ [PEER_DOWN_ALLOWAS_IN_CHANGE] = "Allow AS in changed",
+
+ [PEER_DOWN_USER_SHUTDOWN] = "Admin. shutdown",
+ [PEER_DOWN_USER_RESET] = "User reset",
+ [PEER_DOWN_NEIGHBOR_DELETE] = "Neighbor deleted",
+
+ [PEER_DOWN_INTERFACE_DOWN] = "Interface down",
+
+ [PEER_DOWN_MAX_PREFIX] = "Max Prefix Limit exceeded",
+
+ [PEER_DOWN_HEADER_ERROR] = "Error in message header",
+ [PEER_DOWN_OPEN_ERROR] = "Error in BGP OPEN message",
+ [PEER_DOWN_UPDATE_ERROR] = "Error in BGP UPDATE message",
+ [PEER_DOWN_HOLD_TIMER] = "HoldTimer expired",
+ [PEER_DOWN_FSM_ERROR] = "Error in FSM sequence",
+ [PEER_DOWN_DYN_CAP_ERROR] = "Error in Dynamic Capability",
+
+ [PEER_DOWN_NOTIFY_RECEIVED] = "Notification received",
+ [PEER_DOWN_NSF_CLOSE_SESSION] = "NSF peer closed the session",
+ [PEER_DOWN_CLOSE_SESSION] = "Peer closed the session",
+} ;
+
+CONFIRM(sizeof(peer_down_str) == (PEER_DOWN_count * sizeof(const char*))) ;
- bgp_session_disable(peer, notification);
+/*------------------------------------------------------------------------------
+ * Graceful Restart timer has expired.
+ *
+ * MUST be pIdle or pClearing -- transition to pEstablished cancels this timer.
+ *
+ * Clears out stale routes and stops the Graceful Restart Stale timer.
+ *
+ * Clears down PEER_STATUS_NSF_MODE & PEER_STATUS_NSF_WAIT.
+ */
+static int
+bgp_graceful_restart_timer_expire (struct thread *thread)
+{
+ struct peer *peer;
+
+ peer = THREAD_ARG (thread);
+ peer->t_gr_restart = NULL;
+
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart timer expired", peer->host) ;
+
+ bgp_peer_nsf_stop (peer) ;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ * Cancel any Graceful Restart timer
+ *
+ * NB: does NOT do anything about any stale routes or about any stale timer !
+ */
+static void
+bgp_graceful_restart_timer_cancel (struct peer* peer)
+{
+ if (peer->t_gr_restart)
+ {
+ BGP_TIMER_OFF (peer->t_gr_restart);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart timer stopped", peer->host);
}
+} ;
+
+/*------------------------------------------------------------------------------
+ * Graceful Restart Stale timer has expired.
+ *
+ * SHOULD be pEstablished, because otherwise the Graceful Restart timer should
+ * have gone off before this does, and cancelled this.
+ *
+ * To be safe, if not pEstablished, then MUST be pIdle or pClearing, so can do
+ * bgp_peer_nsf_stop (peer).
+ *
+ * Clears out stale routes and stops the Graceful Restart Stale timer.
+ *
+ * Clears down PEER_STATUS_NSF_MODE & PEER_STATUS_NSF_WAIT.
+ */
+static int
+bgp_graceful_stale_timer_expire (struct thread *thread)
+{
+ struct peer *peer;
+
+ peer = THREAD_ARG (thread);
+ peer->t_gr_stale = NULL;
+
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart stalepath timer expired", peer->host);
+
+ if (peer->state == bgp_peer_pEstablished)
+ bgp_peer_clear_all_stale_routes(peer) ;
else
+ bgp_peer_nsf_stop(peer) ;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ * Cancel any Graceful Restart Stale timer
+ *
+ * NB: does NOT do anything about any stale routes !
+ */
+static void
+bgp_graceful_stale_timer_cancel (struct peer* peer)
+{
+ if (peer->t_gr_stale)
{
- bgp_notify_free(notification) ;
- bgp_peer_stop(peer);
+ BGP_TIMER_OFF (peer->t_gr_stale);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
}
-}
+} ;
-/* Called after event occurred, this function changes status */
-void
-peer_change_status (bgp_peer peer, int status)
+#if 0
+/* BGP peer is stopped by the error. */
+static int
+bgp_stop_with_error (struct peer *peer)
{
- bgp_dump_state (peer, peer->state, status);
+ /* Double start timer. */
+ peer->v_start *= 2;
- /* Preserve old status and change into new status. */
- peer->ostate = peer->state;
- peer->state = status;
+ /* Overflow check. */
+ if (peer->v_start >= (60 * 2))
+ peer->v_start = (60 * 2);
+
+ bgp_stop (peer);
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s went from %s to %s",
- peer->host,
- LOOKUP (bgp_peer_status_msg, peer->ostate),
- LOOKUP (bgp_peer_status_msg, peer->state));
+ return 0;
}
+#endif
+
/*==============================================================================
* For the given interface name, get a suitable address so can bind() before
diff --git a/bgpd/bgp_peer.h b/bgpd/bgp_peer.h
index 91070377..ab32117c 100644
--- a/bgpd/bgp_peer.h
+++ b/bgpd/bgp_peer.h
@@ -106,6 +106,72 @@ struct bgp_filter
*
*/
+enum PEER_DOWN {
+ PEER_DOWN_first = 0,
+
+ PEER_DOWN_NULL = 0, /* Not a PEER_DOWN */
+
+ /* Session taken down at this end for some unspecified reason */
+
+ PEER_DOWN_UNSPECIFIED,
+
+ /* Configuration changes that cause a session to be reset. */
+
+ PEER_DOWN_CONFIG_CHANGE, /* Unspecified config change */
+
+ PEER_DOWN_RID_CHANGE, /* 'bgp router-id' */
+ PEER_DOWN_REMOTE_AS_CHANGE, /* 'neighbor remote-as' */
+ PEER_DOWN_LOCAL_AS_CHANGE, /* 'neighbor local-as' */
+ PEER_DOWN_CLID_CHANGE, /* 'bgp cluster-id' */
+ PEER_DOWN_CONFED_ID_CHANGE, /* 'bgp confederation identifier' */
+ PEER_DOWN_CONFED_PEER_CHANGE, /* 'bgp confederation peer' */
+ PEER_DOWN_RR_CLIENT_CHANGE, /* 'neighbor route-reflector-client' */
+ PEER_DOWN_RS_CLIENT_CHANGE, /* 'neighbor route-server-client' */
+ PEER_DOWN_UPDATE_SOURCE_CHANGE, /* 'neighbor update-source' */
+ PEER_DOWN_AF_ACTIVATE, /* 'neighbor activate' */
+ PEER_DOWN_RMAP_BIND, /* 'neighbor peer-group' */
+ PEER_DOWN_RMAP_UNBIND, /* 'no neighbor peer-group' */
+ PEER_DOWN_CAPABILITY_CHANGE, /* 'neighbor capability' */
+ PEER_DOWN_PASSIVE_CHANGE, /* 'neighbor passive' */
+ PEER_DOWN_MULTIHOP_CHANGE, /* 'neighbor multihop' */
+ PEER_DOWN_AF_DEACTIVATE, /* 'no neighbor activate' */
+ PEER_DOWN_PASSWORD_CHANGE, /* password changed */
+ PEER_DOWN_ALLOWAS_IN_CHANGE, /* allowas-in change */
+
+ /* Other actions that cause a session to be reset */
+
+ PEER_DOWN_USER_SHUTDOWN, /* 'neighbor shutdown' */
+ PEER_DOWN_USER_RESET, /* 'clear ip bgp' */
+ PEER_DOWN_NEIGHBOR_DELETE, /* neighbor delete */
+
+ PEER_DOWN_INTERFACE_DOWN, /* interface reported to be down */
+
+ /* Errors and problems that cause a session to be reset */
+
+ PEER_DOWN_MAX_PREFIX, /* max prefix limit exceeded */
+
+ PEER_DOWN_HEADER_ERROR, /* error in BGP Message header */
+ PEER_DOWN_OPEN_ERROR, /* error in BGP OPEN message */
+ PEER_DOWN_UPDATE_ERROR, /* error in BGP UPDATE message */
+ PEER_DOWN_HOLD_TIMER, /* HoldTimer expired */
+ PEER_DOWN_FSM_ERROR, /* error in FSM sequence */
+ PEER_DOWN_DYN_CAP_ERROR, /* error in Dynamic Capability */
+
+ /* Things the far end can do to cause a session to be reset */
+
+ PEER_DOWN_NOTIFY_RECEIVED, /* notification received */
+ PEER_DOWN_CLOSE_SESSION, /* tcp session close */
+ PEER_DOWN_NSF_CLOSE_SESSION, /* NSF tcp session close */
+
+ /* Number of down causes */
+ PEER_DOWN_count
+} ;
+
+typedef enum PEER_DOWN peer_down_t ;
+
+
+
+
struct peer
{
/* BGP structure. */
@@ -156,35 +222,35 @@ struct peer
struct stream *work;
/* Status of the peer. */
- bgp_peer_state_t state; /* current state */
- bgp_peer_state_t ostate; /* old state */
+ bgp_peer_state_t state; /* current state */
+ bgp_peer_state_t ostate; /* old state */
/* Peer index, used for dumping TABLE_DUMP_V2 format */
uint16_t table_dump_index;
/* Peer information */
+ bgp_peer_index_entry index_entry ;
bgp_session session ; /* Current session */
- bgp_peer_index_entry index_entry ; /* and our index entry */
-
- int ttl; /* TTL of TCP connection to the peer. */
- char *desc; /* Description of the peer. */
- unsigned short port; /* Destination port for peer */
- char *host; /* Printable address of the peer. */
- union sockunion su; /* Sockunion address of the peer. */
- time_t uptime; /* Last Up/Down time */
- time_t readtime; /* Last read time */
- time_t resettime; /* Last reset time */
-
- unsigned int ifindex; /* ifindex of the BGP connection. */
- char *ifname; /* bind interface name. */
+
+ int ttl; /* TTL of TCP connection to the peer. */
+ char *desc; /* Description of the peer. */
+ unsigned short port; /* Destination port for peer */
+ char *host; /* Printable address of the peer. */
+ union sockunion su; /* Sockunion address of the peer. */
+ time_t uptime; /* Last Up/Down time */
+ time_t readtime; /* Last read time */
+ time_t resettime; /* Last reset time */
+
+ unsigned int ifindex; /* ifindex of the BGP connection. */
+ char *ifname; /* bind interface name. */
char *update_if;
union sockunion *update_source;
struct zlog *log;
- union sockunion *su_local; /* Sockunion of local address. */
- union sockunion *su_remote; /* Sockunion of remote address. */
- int shared_network; /* Is this peer shared same network. */
- struct bgp_nexthop nexthop; /* Nexthop */
+ union sockunion *su_local; /* Sockunion of local address. */
+ union sockunion *su_remote; /* Sockunion of remote address. */
+ int shared_network; /* Is this peer shared same network. */
+ struct bgp_nexthop nexthop; /* Nexthop */
/* Peer address family configuration. */
u_char afc[AFI_MAX][SAFI_MAX];
@@ -265,13 +331,13 @@ struct peer
/* Peer status flags. */
u_int16_t sflags;
-#define PEER_STATUS_ACCEPT_PEER (1 << 0) /* accept peer */
-#define PEER_STATUS_PREFIX_OVERFLOW (1 << 1) /* prefix-overflow */
-#define PEER_STATUS_CAPABILITY_OPEN (1 << 2) /* capability open send */
-#define PEER_STATUS_HAVE_ACCEPT (1 << 3) /* accept peer's parent */
-#define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */
-#define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */
-#define PEER_STATUS_NSF_WAIT (1 << 6) /* wait comeback peer */
+#define PEER_STATUS_REAL_PEER (1 << 0) /* not group conf or peer_self */
+#define PEER_STATUS_PREFIX_OVERFLOW (1 << 1) /* prefix-overflow */
+#define PEER_STATUS_CAPABILITY_OPEN (1 << 2) /* capability open send */
+#define PEER_STATUS_HAVE_ACCEPT (1 << 3) /* accept peer's parent */
+#define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */
+#define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */
+#define PEER_STATUS_NSF_WAIT (1 << 6) /* wait comeback peer */
/* Peer status af flags (reset in bgp_stop) */
u_int16_t af_sflags[AFI_MAX][SAFI_MAX];
@@ -285,17 +351,17 @@ struct peer
/* Default attribute value for the peer. */
u_int32_t config;
-#define PEER_CONFIG_WEIGHT (1 << 0) /* Default weight. */
-#define PEER_CONFIG_TIMER (1 << 1) /* keepalive & holdtime */
-#define PEER_CONFIG_CONNECT (1 << 2) /* connect */
-#define PEER_CONFIG_ROUTEADV (1 << 3) /* route advertise */
+#define PEER_CONFIG_WEIGHT (1 << 0) /* Default weight. */
+#define PEER_CONFIG_TIMER (1 << 1) /* keepalive & holdtime */
+#define PEER_CONFIG_CONNECT (1 << 2) /* connect */
+#define PEER_CONFIG_ROUTEADV (1 << 3) /* route advertise */
u_int32_t weight;
u_int32_t holdtime;
u_int32_t keepalive;
u_int32_t connect;
u_int32_t routeadv;
- /* Timer values. */
+ /* Timer values. */
u_int32_t v_start;
u_int32_t v_connect;
u_int32_t v_holdtime;
@@ -305,74 +371,51 @@ struct peer
u_int32_t v_pmax_restart;
u_int32_t v_gr_restart;
- /* Threads. */
+ /* Threads. */
struct thread *t_asorig;
struct thread *t_routeadv;
struct thread *t_pmax_restart;
struct thread *t_gr_restart;
struct thread *t_gr_stale;
- /* workqueues */
- struct work_queue *clear_node_queue;
-
- /* BGP state count */
- u_int32_t established; /* Established */
- u_int32_t dropped; /* Dropped */
+ /* BGP state count */
+ u_int32_t established;
+ u_int32_t dropped;
- /* Synchronization list and time. */
+ /* Synchronization list and time. */
struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX];
time_t synctime;
- /* Send prefix count. */
+ /* Send prefix count. */
unsigned long scount[AFI_MAX][SAFI_MAX];
- /* Announcement attribute hash. */
+ /* Announcement attribute hash. */
struct hash *hash[AFI_MAX][SAFI_MAX];
- /* Filter structure. */
+ /* Filter structure. */
struct bgp_filter filter[AFI_MAX][SAFI_MAX];
- /* ORF Prefix-list */
+ /* ORF Prefix-list */
struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX];
- /* Prefix count. */
+ /* Prefix count. */
unsigned long pcount[AFI_MAX][SAFI_MAX];
- /* Max prefix count. */
+ /* Max prefix count. */
unsigned long pmax[AFI_MAX][SAFI_MAX];
u_char pmax_threshold[AFI_MAX][SAFI_MAX];
u_int16_t pmax_restart[AFI_MAX][SAFI_MAX];
#define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75
- /* allowas-in. */
+ /* allowas-in. */
char allowas_in[AFI_MAX][SAFI_MAX];
- /* peer reset cause */
- char last_reset;
-#define PEER_DOWN_RID_CHANGE 1 /* bgp router-id command */
-#define PEER_DOWN_REMOTE_AS_CHANGE 2 /* neighbor remote-as command */
-#define PEER_DOWN_LOCAL_AS_CHANGE 3 /* neighbor local-as command */
-#define PEER_DOWN_CLID_CHANGE 4 /* bgp cluster-id command */
-#define PEER_DOWN_CONFED_ID_CHANGE 5 /* bgp confederation identifier command */
-#define PEER_DOWN_CONFED_PEER_CHANGE 6 /* bgp confederation peer command */
-#define PEER_DOWN_RR_CLIENT_CHANGE 7 /* neighbor route-reflector-client command */
-#define PEER_DOWN_RS_CLIENT_CHANGE 8 /* neighbor route-server-client command */
-#define PEER_DOWN_UPDATE_SOURCE_CHANGE 9 /* neighbor update-source command */
-#define PEER_DOWN_AF_ACTIVATE 10 /* neighbor activate command */
-#define PEER_DOWN_USER_SHUTDOWN 11 /* neighbor shutdown command */
-#define PEER_DOWN_USER_RESET 12 /* clear ip bgp command */
-#define PEER_DOWN_NOTIFY_RECEIVED 13 /* notification received */
-#define PEER_DOWN_NOTIFY_SEND 14 /* notification send */
-#define PEER_DOWN_CLOSE_SESSION 15 /* tcp session close */
-#define PEER_DOWN_NEIGHBOR_DELETE 16 /* neghbor delete */
-#define PEER_DOWN_RMAP_BIND 17 /* neghbor peer-group command */
-#define PEER_DOWN_RMAP_UNBIND 18 /* no neighbor peer-group command */
-#define PEER_DOWN_CAPABILITY_CHANGE 19 /* neighbor capability command */
-#define PEER_DOWN_PASSIVE_CHANGE 20 /* neighbor passive command */
-#define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop command */
-#define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */
-
- /* The kind of route-map Flags.*/
+ /* peer reset cause */
+ peer_down_t last_reset;
+
+ bgp_notify notification ;
+
+ /* The kind of route-map Flags. */
u_char rmap_type;
#define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */
#define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */
@@ -387,7 +430,7 @@ struct peer
#define BGP_TIMER_ON(T,F,V) \
do { \
- if (!(T) && (peer->state != bgp_peer_sDeleted)) \
+ if (!(T) && (peer->state != bgp_peer_pDeleting)) \
THREAD_TIMER_ON(master,(T),(F),peer,(V)); \
} while (0)
@@ -399,7 +442,7 @@ struct peer
#define BGP_EVENT_ADD(P,E) \
do { \
- if ((P)->state != bgp_peer_sDeleted) \
+ if ((P)->state != bgp_peer_pDeleting) \
thread_add_event (master, bgp_event, (P), (E)); \
} while (0)
@@ -426,39 +469,38 @@ extern const char *peer_down_str[];
extern void
bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag);
-void
-bgp_peer_reenable(bgp_peer peer, bgp_notify notification);
-
extern void
bgp_peer_enable(bgp_peer peer);
extern void
-bgp_peer_disable(bgp_peer peer, bgp_notify notification);
-
-extern int
-bgp_peer_stop (struct peer *peer) ;
+bgp_peer_down(bgp_peer peer, peer_down_t why_down) ;
extern void
-bgp_peer_clearing_completed(struct peer *peer) ;
+bgp_peer_down_error(struct peer* peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode) ;
+extern void
+bgp_peer_down_error_with_data (struct peer* peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode,
+ const u_int8_t* data, size_t datalen) ;
extern void
-peer_change_status (bgp_peer peer, int status);
+bgp_peer_clearing_completed(struct peer *peer) ;
extern struct peer *
-peer_new (struct bgp *bgp);
+bgp_peer_new (struct bgp *bgp);
extern struct peer *
-peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
- as_t remote_as, afi_t afi, safi_t safi);
+bgp_peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
+ as_t remote_as, afi_t afi, safi_t safi);
-extern int
-peer_delete (struct peer *peer);
+extern struct
+peer *bgp_peer_lock (struct peer *) ;
-extern void
-peer_free (struct peer *peer);
+extern struct
+peer *bgp_peer_unlock (struct peer *) ;
-extern void
-peer_nsf_stop (struct peer *peer);
+extern int
+bgp_peer_delete (struct peer *peer);
extern sockunion
bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, pAF_t paf) ;
diff --git a/bgpd/bgp_peer_index.c b/bgpd/bgp_peer_index.c
index 5bb7f3d0..518a22bc 100644
--- a/bgpd/bgp_peer_index.c
+++ b/bgpd/bgp_peer_index.c
@@ -24,6 +24,7 @@
#include "bgpd/bgp_peer_index.h"
#include "bgpd/bgp_peer.h"
#include "bgpd/bgp_session.h"
+#include "bgpd/bgp_connection.h"
#include "lib/symtab.h"
#include "lib/vector.h"
@@ -35,17 +36,26 @@
* BGP Peer Index
*
* When peers are created, they are registered in the bgp_peer_index. When
- * they are destroyed, they are removed. This is done by the Routeing Engine.
+ * they are destroyed, they are removed. This is done by the Routing Engine.
*
- * The peer index is used by the Routeing Engine to lookup peers either by
+ * The Peer Index is used by the Routing Engine to lookup peers either by
* name (IP address) or by peer_id.
*
* The BGP Engine needs to lookup sessions when a listening socket accepts a
* connection -- first, to decide whether to continue with the connection, and
- * second, to tie the connection to the right session. It uses the peer index
+ * second, to tie the connection to the right session. It uses the Peer Index
* to do this.
*
- * A mutex is used to coordinate access to the index.
+ * A mutex is used to coordinate access to the index. Only the Routing engine
+ * makes changes to the Peer Index, so it only needs to lock the mutex when it
+ * does make changes. The BGP Engine needs to lock the Peer Index whenever it
+ * accesses it.
+ *
+ * The BGP Engine needs the session associated with a given address if and only
+ * if the session is enabled for accept(), which implies that it is active and
+ * in the hands of the BGP Engine. To get to the session it needs to step
+ * via the peer->session pointer, having found the peer via the index. So,
+ * setting the peer->session pointer is done under the Peer Index Mutex.
*/
static struct symbol_table bgp_peer_index ; /* lookup by 'name' */
@@ -140,7 +150,7 @@ bgp_peer_index_reset(void)
/* Ream out the peer id vector -- checking that all entries are empty */
while ((entry = vector_ream_keep(&bgp_peer_id_index)) != NULL)
- passert(entry->peer == NULL) ;
+ passert((entry->peer == NULL) && (entry->next_free != entry)) ;
/* Discard body of symbol table -- must be empty ! */
symbol_table_reset_keep(&bgp_peer_index) ;
@@ -192,13 +202,14 @@ bgp_peer_index_register(bgp_peer peer, union sockunion* su)
bgp_peer_id_table_make_ids() ;
entry = bgp_peer_id_free_head ;
- bgp_peer_id_free_head = (void*)entry->accept ;
+ bgp_peer_id_free_head = entry->next_free ;
assert(vector_get_item(&bgp_peer_id_index, entry->id) == entry) ;
/* Initialise the entry -- the id is already set */
entry->peer = peer ;
- entry->accept = NULL ;
+ entry->next_free = entry ;
+
peer->index_entry = entry;
/* Insert the new entry into the symbol table. */
@@ -235,7 +246,9 @@ bgp_peer_index_deregister(bgp_peer peer, union sockunion* su)
entry = symbol_delete(sym) ;
- passert((entry != NULL) && (entry->peer == peer) && (entry->accept == NULL)) ;
+ passert( (entry != NULL) && (entry->id != bgp_peer_id_null)
+ && (entry->peer == peer)
+ && (entry->next_free == entry) ) ;
bgp_peer_id_table_free_entry(entry) ;
@@ -271,21 +284,47 @@ bgp_peer_index_seek(union sockunion* su)
extern bgp_peer_index_entry
bgp_peer_index_seek_entry(union sockunion* su)
{
+ bgp_peer_index_entry entry ;
+
/* Only the Routing Engine can add/delete entries -- so no lock required */
- return symbol_get_value(symbol_seek(&bgp_peer_index, su)) ;
+ entry = symbol_get_value(symbol_seek(&bgp_peer_index, su)) ;
+
+ if (entry != NULL)
+ assert((entry->peer != NULL) && (entry->next_free = entry)) ;
+
+ return entry ;
} ;
/*------------------------------------------------------------------------------
- * Lookup a peer by its address.
+ * Set peer->session field.
*
- * Return a pointer to its session iff it is prepared to accept() a connection.
+ * This is done under the Peer Index Mutex, so that the BGP Engine can step
+ * from the Peer Index entry, via the peer structure, to the session, which is
+ * also controlled by that Mutex, in safety.
+ */
+extern void
+bgp_peer_index_set_session(bgp_peer peer, bgp_session session)
+{
+ BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ peer->session = session ;
+
+ BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+} ;
+
+/*------------------------------------------------------------------------------
+ * Find whether given address is for a known peer, and if so whether it has
+ * an active session which is prepared to accept() a connection.
*
* For use by the BGP Engine.
*
* Returns: bgp_connection if: peer with given address is configured
* and: the session is prepared to accept()
*
+ * Note that the session cannot be deleted while it is in a prepared
+ * to accept state.
+ *
* or: NULL otherwise
*
* Sets *p_found <=> a peer with the given address is configured.
@@ -294,17 +333,25 @@ bgp_peer_index_seek_entry(union sockunion* su)
* is initialised NULL when the index entry is created.
*/
extern bgp_connection
-bgp_peer_index_seek_accept(union sockunion* su, int* p_found)
+bgp_peer_index_seek_accept(union sockunion* su, bool* p_found)
{
- bgp_connection accept ;
+ bgp_connection accept ;
bgp_peer_index_entry entry ;
BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
entry = symbol_get_value(symbol_seek(&bgp_peer_index, su)) ;
- *p_found = (entry != NULL) ;
- accept = *p_found ? entry->accept : NULL ;
+ if (entry != NULL)
+ {
+ *p_found = true ;
+ accept = bgp_connection_query_accept(entry->peer->session) ;
+ }
+ else
+ {
+ *p_found = false ;
+ accept = NULL ;
+ } ;
BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
@@ -333,10 +380,10 @@ bgp_peer_id_table_free_entry(bgp_peer_index_entry entry)
if (bgp_peer_id_free_head == NULL)
bgp_peer_id_free_head = entry ;
else
- bgp_peer_id_free_tail->accept = (void*)entry ;
+ bgp_peer_id_free_tail->next_free = entry ;
bgp_peer_id_free_tail = entry ;
- entry->accept = NULL ; /* used as 'next' for free list */
+ entry->next_free = NULL ;
entry->peer = NULL ; /* only when free ! */
} ;
@@ -363,9 +410,9 @@ bgp_peer_id_table_make_ids(void)
{
confirm(bgp_peer_id_null == 0) ;
- entry->id = 0 ; /* should never be used */
- entry->peer = NULL ; /* invalid in use */
- entry->accept = (void*)entry ; /* invalid if not active ! */
+ entry->id = 0 ; /* should never be used */
+ entry->peer = NULL ; /* invalid in use */
+ entry->next_free = NULL ; /* invalid in use */
++entry ; /* step past id == 0 */
id_new = 1 ; /* avoid setting id == 0 free */
diff --git a/bgpd/bgp_peer_index.h b/bgpd/bgp_peer_index.h
index c99ec710..2ce3fb16 100644
--- a/bgpd/bgp_peer_index.h
+++ b/bgpd/bgp_peer_index.h
@@ -40,20 +40,10 @@ typedef unsigned bgp_peer_id_t ;
struct bgp_peer_index_entry
{
- bgp_peer peer ; /* used by Routing Engine */
+ bgp_peer_index_entry next_free ; /* for list of free peer_id's */
+ /* points to self if entry is in use */
- /* The accept pointer is used by the listening socket(s) to find the
- * session when it is prepared to accept a connection.
- *
- * This pointer MUST be NULL when not sEnabled or sEstablished. It
- * will be set by the BGP Engine when it decides to accept connections,
- * and cleared by it otherwise (and when a session stops).
- *
- * An active session contains a pointer to the peer index entry to
- * facilitate this.
- */
-
- bgp_connection accept ; /* used by BGP Engine */
+ bgp_peer peer ; /* NULL if entry is not in use */
bgp_peer_id_t id ; /* maps IP address to peer_id */
} ;
@@ -88,8 +78,11 @@ bgp_peer_index_seek(sockunion su) ;
extern bgp_peer_index_entry
bgp_peer_index_seek_entry(sockunion su) ;
+extern void
+bgp_peer_index_set_session(bgp_peer peer, bgp_session session) ;
+
extern bgp_connection
-bgp_peer_index_seek_accept(sockunion su, int* p_found) ;
+bgp_peer_index_seek_accept(sockunion su, bool* p_found) ;
#endif /* _QUAGGA_BGP_PEER_INDEX_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index ff7dada3..ca8bee8c 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -205,7 +205,7 @@ bgp_info_add (struct bgp_node *rn, struct bgp_info *ri)
bgp_info_lock (ri);
bgp_lock_node (rn);
- peer_lock (peer); /* bgp_info peer reference */
+ bgp_peer_lock (peer); /* bgp_info peer reference */
}
/* Do the actual removal of info from RIB, for use by bgp_process
@@ -237,7 +237,7 @@ bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri)
bgp_info_unlock (ri); /* fewer references to bgp_info */
bgp_unlock_node (rn); /* fewer references to bgp_node */
- peer_unlock (peer); /* fewer references to peer */
+ bgp_peer_unlock (peer); /* fewer references to peer */
}
void
@@ -1434,7 +1434,7 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
p = &rn->p;
/* Announce route to Established peer. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return 0;
/* Address family configuration check. */
@@ -1493,6 +1493,7 @@ bgp_process_rsclient (struct work_queue *wq, work_queue_item item)
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
struct listnode *node, *nnode;
+ struct bgp_table *table ;
struct peer *rsclient ;
assert(wq->spec.data == item) ;
@@ -1503,12 +1504,20 @@ bgp_process_rsclient (struct work_queue *wq, work_queue_item item)
return WQ_SUCCESS ;
/* hack off queue and prepare to process */
- pq->head = rn->wq_next ;
- rn->on_wq = 0 ;
- rsclient = rn->table->owner;
- afi = rn->table->afi;
- safi = rn->table->safi;
+ dassert((rn->on_wq != 0) && (rn->lock > 0)) ;
+
+ pq->head = rn->wq_next ;
+ rn->wq_next = NULL ; /* Keep tidy */
+ rn->on_wq = 0 ;
+
+ table = rn->table ;
+ rsclient = table->owner;
+ afi = table->afi;
+ safi = table->safi;
+
+ dassert(table->lock > 0) ;
+ dassert(rsclient->lock > 0) ;
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new);
@@ -1552,8 +1561,8 @@ bgp_process_rsclient (struct work_queue *wq, work_queue_item item)
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap (rn, old_select);
- bgp_table_unlock (rn->table);
bgp_unlock_node (rn);
+ bgp_table_unlock (table); /* NB: *after* node, in case table is deleted */
bgp_unlock (bgp);
if (pq->head == NULL)
@@ -1575,6 +1584,7 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
struct listnode *node, *nnode;
+ struct bgp_table *table ;
struct peer *peer;
assert(wq->spec.data == item) ;
@@ -1585,11 +1595,18 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
return WQ_SUCCESS ;
/* hack off queue and prepare to process */
- pq->head = rn->wq_next ;
- rn->on_wq = 0 ;
- afi = rn->table->afi;
- safi = rn->table->safi;
+ dassert((rn->on_wq != 0) && (rn->lock > 0)) ;
+
+ pq->head = rn->wq_next ;
+ rn->wq_next = NULL ; /* Keep tidy */
+ rn->on_wq = 0 ;
+
+ table = rn->table ;
+ afi = table->afi;
+ safi = table->safi;
+
+ dassert(table->lock > 0) ;
p = &rn->p ;
@@ -1599,7 +1616,7 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
new_select = old_and_new.new;
/* Nothing to do. */
- if (old_select && old_select == new_select)
+ if (old_select && (old_select == new_select))
{
if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
{
@@ -1626,19 +1643,17 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
}
/* FIB update. */
- if (safi == SAFI_UNICAST && ! bgp->name &&
- ! bgp_option_check (BGP_OPT_NO_FIB))
+ if ((safi == SAFI_UNICAST) && (bgp->name == NULL) &&
+ ! bgp_option_check (BGP_OPT_NO_FIB))
{
- if (new_select
- && new_select->type == ZEBRA_ROUTE_BGP
- && new_select->sub_type == BGP_ROUTE_NORMAL)
+ if (new_select && (new_select->type == ZEBRA_ROUTE_BGP)
+ && (new_select->sub_type == BGP_ROUTE_NORMAL))
bgp_zebra_announce (p, new_select, bgp);
else
{
/* Withdraw the route from the kernel. */
- if (old_select
- && old_select->type == ZEBRA_ROUTE_BGP
- && old_select->sub_type == BGP_ROUTE_NORMAL)
+ if (old_select && (old_select->type == ZEBRA_ROUTE_BGP)
+ && (old_select->sub_type == BGP_ROUTE_NORMAL))
bgp_zebra_withdraw (p, old_select);
}
}
@@ -1650,9 +1665,9 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
/* Finish up */
finish:
- bgp_table_unlock (rn->table);
- bgp_unlock_node (rn);
- bgp_unlock (bgp);
+ bgp_unlock_node (rn) ;
+ bgp_table_unlock (table) ; /* NB: *after* node, in case table is deleted */
+ bgp_unlock (bgp) ;
if (pq->head == NULL)
return WQ_SUCCESS ;
@@ -1660,6 +1675,9 @@ finish:
return WQ_REQUEUE ;
}
+/*------------------------------------------------------------------------------
+ * Delete item from work queue
+ */
static void
bgp_processq_del (struct work_queue *wq, work_queue_item item)
{
@@ -1670,17 +1688,29 @@ bgp_processq_del (struct work_queue *wq, work_queue_item item)
while ((rn = pq->head) != NULL)
{
- pq->head = rn->wq_next ;
- rn->on_wq = 0 ;
+ struct bgp_table *table ;
+
+ dassert((rn->on_wq != 0) && (rn->lock > 0)) ;
+
+ pq->head = rn->wq_next ;
+ rn->wq_next = NULL ; /* Keep tidy */
+ rn->on_wq = 0 ;
+
+ table = rn->table ;
+
+ dassert(table->lock > 0) ;
- bgp_table_unlock (rn->table);
bgp_unlock_node (rn);
+ bgp_table_unlock (table); /* NB: *after* node, in case table is deleted */
bgp_unlock (pq->bgp);
} ;
wq->spec.data = NULL ;
} ;
+/*------------------------------------------------------------------------------
+ * Create new work queue for given bgp instance and given type of table
+ */
static work_queue
bgp_process_queue_init (struct bgp* bgp, bgp_table_t type)
{
@@ -1718,6 +1748,10 @@ bgp_process_queue_init (struct bgp* bgp, bgp_table_t type)
return *p_wq = wq ;
}
+/*------------------------------------------------------------------------------
+ * Place given route node on appropriate work queue, so that best path
+ * selection etc. can take place later.
+ */
void
bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
{
@@ -1762,9 +1796,9 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
pq = work_queue_item_args(item) ;
/* all unlocked when processed or deleted */
+ bgp_lock (bgp);
bgp_table_lock (rn->table);
bgp_lock_node (rn);
- bgp_lock (bgp);
/* add to the queue */
if (pq->head == NULL)
@@ -1780,6 +1814,11 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
return;
}
+/*============================================================================*/
+
+/*------------------------------------------------------------------------------
+ * Max Prefix Overflow timer expired -- turn off overflow status and enable.
+ */
static int
bgp_maximum_prefix_restart_timer (struct thread *thread)
{
@@ -1788,15 +1827,42 @@ bgp_maximum_prefix_restart_timer (struct thread *thread)
peer = THREAD_ARG (thread);
peer->t_pmax_restart = NULL;
+ assert(CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) ;
+
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("%s Maximum-prefix restart timer expired, restore peering",
peer->host);
- peer_clear (peer);
+ UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+
+ bgp_peer_enable(peer);
return 0;
}
+/*------------------------------------------------------------------------------
+ * If there is an active max prefix restart timer, cancel it now.
+ *
+ * NB: clears PEER_STATUS_PREFIX_OVERFLOW, but does NOT enable the peer.
+ */
+void
+bgp_maximum_prefix_cancel_timer (struct peer *peer)
+{
+ if (peer->t_pmax_restart)
+ {
+ assert(CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) ;
+
+ BGP_TIMER_OFF (peer->t_pmax_restart);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s Maximum-prefix restart timer cancelled", peer->host) ;
+ } ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Number of prefixes has overflowed.
+ */
int
bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
safi_t safi, int always)
@@ -1814,10 +1880,11 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
"%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, "
"limit %ld", afi_safi_print (afi, safi), peer->host,
peer->pcount[afi][safi], peer->pmax[afi][safi]);
+
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT);
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
- return 0;
+ return 0;
{
u_int8_t ndata[7];
@@ -1835,8 +1902,8 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
SET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
/* Disable the peer, the timer routine will reenable. */
- bgp_notify_send_with_data(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7);
+ bgp_peer_down_error_with_data(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7);
}
/* restart timer start */
@@ -1874,7 +1941,10 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
return 0;
}
-/* Unconditionally remove the route from the RIB, without taking
+/*============================================================================*/
+
+/*------------------------------------------------------------------------------
+ * Unconditionally remove the route from the RIB, without taking
* damping into consideration (eg, because the session went down)
*/
static void
@@ -2671,7 +2741,7 @@ bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi)
struct bgp_node *rn;
struct bgp_table *table;
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return;
if (! peer->afc_nego[afi][safi])
@@ -2773,7 +2843,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
struct bgp_node *rn;
struct bgp_table *table;
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return;
if (safi != SAFI_MPLS_VPN)
@@ -2790,14 +2860,18 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
*
* There are two (quite different) forms of clearing:
*
- * 1. Normal clearing -- mass withdraw of given client's routes for all
+ * 1. Normal clearing -- mass withdraw of given peer's routes for all
* or individual AFI/SAFI.
*
+ * This is clears the routes *from* the given peer.
+ *
* Note that normal clearing deals with the main RIB and any RS Client
* RIBs that may also contain routes.
*
* 2. RS Client clearing -- dismantling of RS Client RIB for an AFI/SAFI.
*
+ * This clears out the routes *for* the given RS Client.
+ *
*------------------------------------------------------------------------------
* Normal clearing
*
@@ -2834,9 +2908,20 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
* The peer's:
*
* struct bgp_info* routes_head[AFI_MAX][SAFI_MAX] ;
+ *
+ * This list threads through every use of all routes which belong to
+ * the peer, in all RIBs.
+ *
* struct bgp_adj_in* adj_in_head[AFI_MAX][SAFI_MAX] ;
+ *
+ * This list threads through every copy of all routes which belong to the
+ * peer and which have been preserved for soft reconfiguration, in all RIBs.
+ *
* struct bgp_adj_out* adj_out_head[AFI_MAX][SAFI_MAX] ;
*
+ * This list threads through every route which has been selected for the
+ * peer, in all RIBs.
+ *
* Are maintained for exactly this purpose.
*
* NB: this is now a linear process, because the lists identify the stuff to
@@ -2860,6 +2945,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
*
* [The MPLS VPN stuff has a two level RIB, which the above probably doesn't
* work for... more work required, here.]
+ *
* TODO: fix bgp_clear_route() and MPLS VPN !!
*
*------------------------------------------------------------------------------
@@ -2873,28 +2959,226 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
*/
/*------------------------------------------------------------------------------
- * Clear given route -- respecting NSF for peer whose route this is.
+ * Normal clearing of a a given peer's routes.
+ *
+ * The following lists are processed:
+ *
+ * * struct bgp_info* routes_head
+ *
+ * Walks this and clears each route.
+ *
+ * * struct bgp_adj_in* adj_in_head
+ * * struct bgp_adj_out* adj_out_head
+ *
+ * These two are simply emptied out.
+ *
+ * NB: in the latest scheme of things this is completed immediately...
+ *
+ * ...however, retain the ability for this to kick off background or other
+ * activity.
+ *
+ * Returns: true <=> clearing has completed
*
- * Will mark the bgp_info as stale, or will remove altogether. If removes the
- * route will set the bgp_node to be reprocessed.
*/
-static void
-bgp_clear_this_route(bgp_peer peer, struct bgp_node* rn, struct bgp_info* ri,
- afi_t afi, safi_t safi)
-{
- assert (rn && peer && ri) ;
- assert ((rn == ri->rn) && (peer == ri->peer)) ;
-
- /* graceful restart STALE flag set. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)
- && peer->nsf[afi][safi]
- && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE)
- && ! CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
- bgp_info_set_flag (rn, ri, BGP_INFO_STALE);
- else
- bgp_rib_remove (rn, ri, peer, afi, safi);
+extern bool
+bgp_clear_routes(struct peer *peer, afi_t afi, safi_t safi, bool nsf)
+{
+ struct bgp_info* ri ;
+ struct bgp_info* next_ri ;
+ struct bgp_adj_in* adj_in ;
+ struct bgp_adj_out* adj_out ;
+ struct bgp_adj_in** adj_in_head ;
+ struct bgp_adj_out** adj_out_head ;
+
+ next_ri = peer->routes_head[afi][safi] ;
+
+ /* If NSF requested and nsf configured for this afi/safi, do nsf and
+ * set flag to indicate that at least one afi/safi may have stale routes.
+ */
+ nsf = nsf && peer->nsf[afi][safi] ;
+ if (nsf)
+ SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) ;
+
+ /* TODO: fix bgp_clear_route_normal() so can clear an MPLS VPN table.... */
+ if (next_ri != NULL)
+ assert(safi != SAFI_MPLS_VPN) ;
+
+ while (next_ri != NULL)
+ {
+ /* The current bgp_info object may vanish, so bank the next */
+ ri = next_ri ;
+ next_ri = ri->routes_next ;
+
+ assert (peer == ri->peer) ;
+
+ if (nsf && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE)
+ && ! CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
+ bgp_info_set_flag (ri->rn, ri, BGP_INFO_STALE);
+ else
+ bgp_rib_remove (ri->rn, ri, peer, afi, safi);
+ } ;
+
+ /* Empty out all adjacencies */
+ adj_in_head = &(peer->adj_in_head[afi][safi]) ;
+ while ((adj_in = *adj_in_head) != NULL)
+ {
+ assert(adj_in->route_prev == NULL) ;
+ bgp_adj_in_remove (adj_in->rn, adj_in) ;
+ assert(adj_in != *adj_in_head) ;
+ } ;
+
+ adj_out_head = &(peer->adj_out_head[afi][safi]) ;
+ while ((adj_out = *adj_out_head) != NULL)
+ {
+ assert(adj_out->route_prev == NULL) ;
+ bgp_adj_out_remove (adj_out->rn, adj_out, peer, afi, safi) ;
+ assert(adj_out != *adj_out_head) ;
+ } ;
+
+ return true ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Normal clearing of given peer for all AFI/SAFI -- respecting NSF if required.
+ *
+ * NB: in the latest scheme of things this is completed immediately...
+ *
+ * ...however, retain the ability to run this in the background with the
+ * peer in bgp_peer_pClearing.
+ *
+ * Returns: true <=> all clearing completed
+ * so false => something running in the background.
+ */
+extern bool
+bgp_clear_all_routes (struct peer *peer, bool nsf)
+{
+ bool completed ;
+ afi_t afi;
+ safi_t safi;
+
+ assert(peer->state == bgp_peer_pClearing) ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) ;
+
+ completed = true ;
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (!bgp_clear_routes(peer, afi, safi, nsf))
+ completed = false ;
+
+ return completed ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Clear Route Server RIB for given AFI/SAFI -- unconditionally
+ *
+ * This is used to dismantle a Route Server Client's RIB -- this is removing
+ * all the routes from all *other* Route Server Clients that have been placed
+ * in this Clients RIB.
+ *
+ * Walks all the nodes in the table and discards all routes, all adj_in and
+ * all adj_out.
+ *
+ * Does nothing if there is no RIB for that AFI/SAFI.
+ */
+extern void
+bgp_clear_rsclient_rib(struct peer* rsclient, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn ;
+ struct bgp_table* table ;
+
+ table = rsclient->rib[afi][safi] ;
+
+ if (table == NULL)
+ return ; /* Ignore unconfigured afi/safi or similar */
+
+ /* TODO: fix bgp_clear_rsclient_rib() so that will clear an MPLS VPN table. */
+ passert(table->safi != SAFI_MPLS_VPN) ;
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ {
+ struct bgp_info *ri;
+ struct bgp_info *next_ri ;
+ struct bgp_adj_in *ain;
+ struct bgp_adj_out *aout;
+
+ next_ri = rn->info ;
+ while(next_ri != NULL)
+ {
+ ri = next_ri ;
+ next_ri = ri->info_next ; /* bank this */
+
+ bgp_rib_remove (rn, ri, rsclient, table->afi, table->safi);
+ } ;
+
+ while ((ain = rn->adj_in) != NULL)
+ {
+ assert(ain->adj_prev == NULL) ;
+ bgp_adj_in_remove (rn, ain);
+ assert(ain != rn->adj_in) ;
+ } ;
+
+ while ((aout = rn->adj_out) != NULL)
+ {
+ assert(aout->adj_prev == NULL) ;
+ bgp_adj_out_remove (rn, aout, aout->peer, table->afi, table->safi) ;
+ assert(aout != rn->adj_out) ;
+ } ;
+ }
+ return ;
+}
+
+/*------------------------------------------------------------------------------
+ * Walk main RIB and remove any adj_in for given peer.
+ *
+ * TODO: walk peer->bgp_adj_in_head[afi][safi] -- but check which table ?
+ */
+void
+bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct bgp_table *table;
+ struct bgp_node *rn;
+ struct bgp_adj_in *ain;
+
+ table = peer->bgp->rib[afi][safi];
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ for (ain = rn->adj_in; ain ; ain = ain->adj_next)
+ if (ain->peer == peer)
+ {
+ bgp_adj_in_remove (rn, ain);
+ break;
+ }
} ;
+/*------------------------------------------------------------------------------
+ * Walk main RIB and remove all stale routes for the given peer.
+ *
+ * NB: is required to complete immediately !
+ *
+ * TODO: walk peer->routes_head[afi][safi]
+ */
+void
+bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn;
+ struct bgp_info *ri;
+ struct bgp_table *table;
+
+ table = peer->bgp->rib[afi][safi];
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ {
+ for (ri = rn->info; ri; ri = ri->info_next)
+ if (ri->peer == peer)
+ {
+ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
+ bgp_rib_remove (rn, ri, peer, afi, safi);
+ break;
+ }
+ }
+}
+
#if 0
struct bgp_clear_node_queue
@@ -2952,14 +3236,14 @@ bgp_clear_node_complete (struct work_queue *wq)
/* Flush the event queue and ensure the peer is shut down */
bgp_peer_stop(peer);
BGP_EVENT_FLUSH (peer);
- if (peer->state == bgp_peer_sClearing)
+ if (peer->state == bgp_peer_pClearing)
{
- peer_change_status (peer, bgp_peer_sIdle);
+ peer_change_status (peer, bgp_peer_pIdle);
/* enable peer if required */
bgp_peer_enable(peer);
}
- peer_unlock (peer); /* bgp_clear_route */
+ bgp_peer_unlock (peer); /* bgp_clear_route */
}
static void
@@ -2985,120 +3269,6 @@ bgp_clear_node_queue_init (struct peer *peer)
peer->clear_node_queue->spec.data = peer;
}
-#endif
-
-/*------------------------------------------------------------------------------
- * Completely empty the given table which belongs to the given peer.
- *
- * Used for RS Client RIB clearing.
- *
- * Walks the table, *unconditionally* deleting all routes.
- *
- * Deletes any and all adj_in and adj_out.
- *
- * TODO: fix bgp_clear_route_table() so that will clear an MPLS VPN table....
- */
-static void
-bgp_clear_route_table (bgp_peer peer, struct bgp_table* table)
-{
- struct bgp_node *rn ;
-
- if (table == NULL)
- return ; /* Ignore unconfigured afi/safi or similar */
-
- passert(table->safi != SAFI_MPLS_VPN) ;
-
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- {
- struct bgp_info *ri;
- struct bgp_info *next_ri ;
- struct bgp_adj_in *ain;
- struct bgp_adj_out *aout;
-
- next_ri = rn->info ;
- while(next_ri != NULL)
- {
- ri = next_ri ;
- next_ri = ri->info_next ; /* bank this */
-
- bgp_rib_remove (rn, ri, peer, table->afi, table->safi);
- } ;
-
- while ((ain = rn->adj_in) != NULL)
- {
- assert(ain->adj_prev == NULL) ;
- bgp_adj_in_remove (rn, ain);
- assert(ain != rn->adj_in) ;
- } ;
-
- while ((aout = rn->adj_out) != NULL)
- {
- assert(aout->adj_prev == NULL) ;
- bgp_adj_out_remove (rn, aout, aout->peer, table->afi, table->safi) ;
- assert(aout != rn->adj_out) ;
- } ;
- }
- return ;
-}
-
-/*------------------------------------------------------------------------------
- * Normal clearing of a a given peer's routes.
- *
- * The following lists are processed:
- *
- * * struct bgp_info* routes_head
- *
- * Walks this and clears each route.
- *
- * * struct bgp_adj_in* adj_in_head
- * * struct bgp_adj_out* adj_out_head
- *
- * These two are simply emptied out.
- *
- * TODO: fix bgp_clear_route_normal() so that will clear an MPLS VPN table....
- */
-extern void
-bgp_clear_route_normal(struct peer *peer, afi_t afi, safi_t safi)
-{
- struct bgp_info* ri ;
- struct bgp_info* next_ri ;
- struct bgp_adj_in* adj_in ;
- struct bgp_adj_out* adj_out ;
- struct bgp_adj_in** adj_in_head ;
- struct bgp_adj_out** adj_out_head ;
-
- next_ri = peer->routes_head[afi][safi] ;
-
- assert((safi != SAFI_MPLS_VPN) || (next_ri == NULL)) ;
-
- while (next_ri != NULL)
- {
- /* The current bgp_info object may vanish, so bank the next */
- ri = next_ri ;
- next_ri = ri->routes_next ;
-
- bgp_clear_this_route(peer, ri->rn, ri, afi, safi) ;
- } ;
-
- /* Empty out all adjacencies */
- adj_in_head = &(peer->adj_in_head[afi][safi]) ;
- while ((adj_in = *adj_in_head) != NULL)
- {
- assert(adj_in->route_prev == NULL) ;
- bgp_adj_in_remove (adj_in->rn, adj_in) ;
- assert(adj_in != *adj_in_head) ;
- } ;
-
- adj_out_head = &(peer->adj_out_head[afi][safi]) ;
- while ((adj_out = *adj_out_head) != NULL)
- {
- assert(adj_out->route_prev == NULL) ;
- bgp_adj_out_remove (adj_out->rn, adj_out, peer, afi, safi) ;
- assert(adj_out != *adj_out_head) ;
- } ;
-} ;
-
-#if 0
void
bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
{
@@ -3123,7 +3293,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
* to grow and grow.
*/
//if (!peer->clear_node_queue->thread)
- peer_lock (peer); /* bgp_clear_node_complete */
+ bgp_peer_lock (peer); /* bgp_clear_node_complete */
switch (purpose)
{
@@ -3181,91 +3351,14 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
/* The following was in bgp_clear_node_complete */
- peer_unlock (peer); /* bgp_clear_route */
+ bgp_peer_unlock (peer); /* bgp_clear_route */
}
#endif
-/*------------------------------------------------------------------------------
- * Clear Route Server RIB for given AFI/SAFI -- unconditionally
- *
- * Does nothing if there is no RIB for that AFI/SAFI.
- */
-extern void
-bgp_clear_route_rsclient(struct peer* rsclient, afi_t afi, safi_t safi)
-{
- bgp_clear_route_table (rsclient, rsclient->rib[afi][safi]) ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Normal clearing of given peer for all AFI/SAFI -- respecting NSF.
- *
- * NB: in the latest scheme of things this is completed immediately...
- *
- * ...however, retain the ability to run this in the background with the
- * peer in bgp_peer_sClearing.
- *
- * Caller should set state of peer *before* calling this.
- */
-extern void
-bgp_clear_route_all (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++)
- bgp_clear_route_normal(peer, afi, safi);
-
- bgp_peer_clearing_completed(peer) ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Walk main RIB and remove all adj_in for given peer.
- */
-void
-bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct bgp_table *table;
- struct bgp_node *rn;
- struct bgp_adj_in *ain;
-
- table = peer->bgp->rib[afi][safi];
-
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- for (ain = rn->adj_in; ain ; ain = ain->adj_next)
- if (ain->peer == peer)
- {
- bgp_adj_in_remove (rn, ain);
- break;
- }
-}
-
-/*------------------------------------------------------------------------------
- * Walk main RIB and remove all stale routes for the given peer.
- */
-void
-bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct bgp_node *rn;
- struct bgp_info *ri;
- struct bgp_table *table;
-
- table = peer->bgp->rib[afi][safi];
-
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- {
- for (ri = rn->info; ri; ri = ri->info_next)
- if (ri->peer == peer)
- {
- if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
- bgp_rib_remove (rn, ri, peer, afi, safi);
- break;
- }
- }
-}
/*============================================================================*/
-/* Delete all kernel routes. */
+#if 0
+/* Delete all kernel routes. */
void
bgp_cleanup_routes (void)
{
@@ -3296,6 +3389,7 @@ bgp_cleanup_routes (void)
bgp_zebra_withdraw (&rn->p, ri);
}
}
+#endif
void
bgp_reset (void)
@@ -3317,7 +3411,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
int ret;
/* Check peer status. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return 0;
pnt = packet->nlri;
@@ -3432,8 +3526,8 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
plog_err (peer->log,
"%s [Error] Update packet error (wrong prefix length %d)",
peer->host, prefixlen);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+ bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
@@ -3446,8 +3540,8 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
"%s [Error] Update packet error"
" (prefix data overflow prefix size is %d)",
peer->host, psize);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+ bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
@@ -3461,8 +3555,8 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
"%s [Error] Update packet error"
" (prefix length mismatch with total length)",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+ bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
return 0;
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 97ee39ab..e1e8f18d 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -174,7 +174,7 @@ enum bgp_clear_route_type
/* Prototypes. */
extern void bgp_route_init (void);
extern void bgp_route_finish (void);
-extern void bgp_cleanup_routes (void);
+
extern void bgp_announce_route (struct peer *, afi_t, safi_t);
extern void bgp_announce_route_all (struct peer *);
extern void bgp_default_originate (struct peer *, afi_t, safi_t, int);
@@ -182,10 +182,11 @@ extern void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t);
extern void bgp_soft_reconfig_rsclient (struct peer *, afi_t, safi_t);
extern void bgp_check_local_routes_rsclient (struct peer *rsclient,
afi_t afi, safi_t safi);
-extern void bgp_clear_route_normal(struct peer *peer, afi_t afi, safi_t safi) ;
-extern void bgp_clear_route_rsclient(struct peer* rsclient,
+extern bool bgp_clear_routes(struct peer *peer, afi_t afi, safi_t safi,
+ bool nsf) ;
+extern void bgp_clear_rsclient_rib(struct peer* rsclient,
afi_t afi, safi_t safi) ;
-extern void bgp_clear_route_all (struct peer *);
+extern bool bgp_clear_all_routes (struct peer *, bool nsf);
extern void bgp_clear_adj_in (struct peer *, afi_t, safi_t);
extern void bgp_clear_stale_route (struct peer *, afi_t, safi_t);
@@ -201,6 +202,7 @@ extern int bgp_nlri_sanity_check (struct peer *, int, u_char *, bgp_size_t);
extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int);
+extern void bgp_maximum_prefix_cancel_timer (struct peer *peer) ;
extern void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t,
u_char);
diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c
index 8d8bfea2..9de8678a 100644
--- a/bgpd/bgp_session.c
+++ b/bgpd/bgp_session.c
@@ -40,7 +40,6 @@
#include "lib/zassert.h"
/* prototypes */
-static int bgp_session_defer_if_limping(bgp_session session);
static void bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag) ;
static void bgp_session_do_update_recv(mqueue_block mqb, mqb_flag_t flag);
static void bgp_session_do_update_send(mqueue_block mqb, mqb_flag_t flag);
@@ -99,7 +98,7 @@ static void bgp_session_do_route_refresh_recv(mqueue_block mqb, mqb_flag_t flag)
*/
/*------------------------------------------------------------------------------
- * Initialise new session structure -- allocate if required.
+ * Allocate & initialise new session structure.
*
* Ties peer and session together. Sets session sIdle, initialises mutex.
*
@@ -108,30 +107,34 @@ static void bgp_session_do_route_refresh_recv(mqueue_block mqb, mqb_flag_t flag)
* NB: if not allocating, the existing session MUST be sIdle/sDisabled OR never
* been kissed.
*
- * NB: in any event, the peer's peer index entry MUST have a NULL accept
- * pointer.
+ * NB: peer MUST NOT have a session set up:
+ *
+ * (a) because if there was a session, there would have to be code here
+ * to worry about its state, and tearing it down etc.
+ *
+ * (b) so that do not have to worry about BGP Engine reaching the old
+ * session while it was being replaced or whatever.
*/
extern bgp_session
-bgp_session_init_new(bgp_session session, bgp_peer peer)
+bgp_session_init_new(bgp_peer peer)
{
+ bgp_session session ;
+
assert(peer->session == NULL) ;
- assert(peer->index_entry->accept == NULL) ;
- if (session == NULL)
- session = XCALLOC(MTYPE_BGP_SESSION, sizeof(struct bgp_session)) ;
- else
- memset(session, 0, sizeof(struct bgp_session)) ;
+ session = XCALLOC(MTYPE_BGP_SESSION, sizeof(struct bgp_session)) ;
qpt_mutex_init_new(&session->mutex, qpt_mutex_recursive) ;
- peer->session = session ;
session->peer = peer ;
- session->state = bgp_session_sIdle ;
+ bgp_peer_lock(peer) ; /* Account for the session->peer pointer */
- session->index_entry = peer->index_entry ;
+ session->state = bgp_session_sIdle ;
/* Zeroising the structure has set:
*
+ * delete_me -- 0 -- false
+ *
* event -- bgp_session_null_event
* notification -- NULL -- none
* err -- 0 -- none
@@ -173,25 +176,73 @@ bgp_session_init_new(bgp_session session, bgp_peer peer)
*
* connections[] -- NULL -- none
* active -- false, not yet active
+ * accept -- false, not yet ready to accept()
*/
confirm(bgp_session_null_event == 0) ;
+ /* Once the session is fully initialised, can set peer->session pointer.
+ *
+ * NB: this is done last and under the Peer Index Mutex, so that the
+ * accept() code does not trip over.
+ */
+ bgp_peer_index_set_session(peer, session) ;
+
return session ;
} ;
-/* Free session structure
+/*==============================================================================
+ * Routing Engine: delete session for given peer.
+ *
+ * This is for use when the peer itself is being deleted. (Peer MUST be in
+ * pDeleting state.)
+ *
+ * Does nothing if there is no session !
+ *
+ * If the session is active, simply sets delete_me flag, which will be honoured
+ * when the session goes dDisabled. Note, it is the callers responsibility
+ * to arrange for that to happen.
+ *
+ * If the session is not active, it is immediately freed.
*
+ * NB: if the session is freed, the peer may vanish at the same time !
*/
-extern bgp_session
-bgp_session_free(bgp_session session)
+extern void
+bgp_session_delete(bgp_peer peer)
{
+ bgp_session session = peer->session ;
+
if (session == NULL)
- return NULL;
+ return ; /* easy if no session anyway */
+
+ assert(peer == session->peer) ;
+
+ /* If is active, set flag so that session is deleted when next it becomes
+ * sDisabled.
+ */
+ if (bgp_session_is_active(session))
+ {
+ session->delete_me = true ;
+ return ;
+ } ;
+
+ /*--------------------------------------------------------------------------*/
+ /* Proceed to free the session structure. */
+
+ /* Make sure that the BGP Engine has, in fact, let go of the session.
+ *
+ * The LOCK/UNLOCK makes sure that the BGP Engine has unlocked the session.
+ *
+ * Without this, the qpt_mutex_destroy() can fail horribly, if the BGP
+ * Engine sends the disable acknowledge before finally unlocking the session.
+ */
+ BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- assert(!bgp_session_is_active(session)) ;
+ BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
qpt_mutex_destroy(&session->mutex, 0) ;
+ /* Proceed to dismantle the session. */
+
bgp_notify_unset(&session->notification);
bgp_open_state_free(session->open_send);
bgp_open_state_free(session->open_recv);
@@ -206,12 +257,24 @@ bgp_session_free(bgp_session session)
sockunion_unset(&session->su_local) ;
sockunion_unset(&session->su_remote) ;
+ /* Drop the peer->session and session->peer pointers
+ *
+ * NB: the peer->session pointer is cleared under the Peer Index Mutex,
+ * so that the accept() code does not trip over.
+ *
+ * NB: at this point it is possible for the peer structure to suddenly
+ * vanish -- if peer has been deleted, and has been waiting for the
+ * session to go sDisabled.
+ */
+ bgp_peer_index_set_session(peer, NULL) ;
+
+ session->peer = NULL ;
+ bgp_peer_unlock(peer) ; /* NB: peer->session == NULL */
+
/* Zeroize to catch dangling references asap */
memset(session, 0, sizeof(struct bgp_session)) ;
XFREE(MTYPE_BGP_SESSION, session);
-
- return NULL;
-}
+} ;
/*==============================================================================
* Routing Engine: enable session for given peer -- allocate if required.
@@ -226,6 +289,8 @@ bgp_session_enable(bgp_peer peer)
bgp_session session ;
mqueue_block mqb ;
+ assert(peer->state = bgp_peer_pIdle) ;
+
/* Set up session if required. Check session if already exists.
*
* Only the Routing Engine creates sessions, so it is safe to pick up the
@@ -238,27 +303,24 @@ bgp_session_enable(bgp_peer peer)
session = peer->session ;
if (session == NULL)
- session = bgp_session_init_new(NULL, peer) ;
+ session = bgp_session_init_new(peer) ;
else
{
assert(session->peer == peer) ;
- /* if session is limping then defer the enable */
- if (bgp_session_defer_if_limping(session))
- return;
assert(!bgp_session_is_active(session)) ;
} ;
/* Initialise what we need to make and run connections */
- session->state = bgp_session_sIdle;
- session->defer_enable = 0;
- session->flow_control = 0;
- session->event = bgp_session_null_event;
- bgp_notify_unset(&session->notification);
- session->err = 0;
- session->ordinal = 0;
+ session->state = bgp_session_sIdle ;
+ session->delete_me = false ;
+ session->flow_control = 0 ;
+ session->event = bgp_session_null_event ;
+ bgp_notify_unset(&session->notification) ;
+ session->err = 0 ;
+ session->ordinal = 0 ;
- session->open_send = bgp_peer_open_state_init_new(session->open_send, peer);
- bgp_open_state_unset(&session->open_recv);
+ session->open_send = bgp_peer_open_state_init_new(session->open_send, peer) ;
+ bgp_open_state_unset(&session->open_recv) ;
session->connect = (peer->flags & PEER_FLAG_PASSIVE) == 0 ;
session->listen = 1 ;
@@ -306,12 +368,22 @@ bgp_session_enable(bgp_peer peer)
session->hold_timer_interval = peer->v_holdtime ;
session->keepalive_timer_interval = peer->v_keepalive ;
- session->as4 = 0;
- session->route_refresh_pre = 0;
+ session->as4 = false ;
+ session->route_refresh_pre = false ;
+ session->orf_prefix_pre = false ;
/* su_local set when session Established */
/* su_remote set when session Established */
+ /* TODO: check whether session stats should persist */
+ memset(&session->stats, 0, sizeof(struct bgp_session_stats)) ;
+
+ memset(&session->connections, 0,
+ sizeof(bgp_connection) * bgp_connection_count) ;
+
+ session->active = false ;
+ session->accept = false ;
+
/* Routeing Engine does the state change now. */
/* Now pass the session to the BGP Engine, which will set about */
@@ -340,7 +412,7 @@ bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag)
BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- session->active = 1 ;
+ session->active = true ;
bgp_fsm_enable_session(session) ;
BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
@@ -352,6 +424,8 @@ bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag)
/*==============================================================================
* Routing Engine: disable session for given peer -- if enabled (!).
*
+ * Does nothing if the session is not sEnabled or sEstablished.
+ *
* Passes any bgp_notify to the BGP Engine, which will dispose of it in due
* course.
*
@@ -390,7 +464,6 @@ bgp_session_disable(bgp_peer peer, bgp_notify notification)
/* Now change to limping state */
session->state = bgp_session_sLimping;
- session->defer_enable = 0;
/* Ask the BGP engine to disable the session.
*
@@ -470,7 +543,10 @@ bgp_session_event(bgp_session session, bgp_session_event_t event,
mqueue_block mqb ;
if (stopped)
- session->active = 0 ; /* ignore updates etc */
+ {
+ session->active = false ; /* ignore updates etc */
+ session->accept = false ; /* for completeness */
+ } ;
mqb = mqb_init_new(NULL, bgp_session_do_event, session) ;
@@ -774,6 +850,8 @@ bgp_session_update_recv(bgp_session session, struct stream* buf, bgp_size_t size
/*------------------------------------------------------------------------------
* Routing Engine: process incoming update message -- mqb action function.
+ *
+ * Discard the update if the session is not sEstablished.
*/
static void
bgp_session_do_update_recv(mqueue_block mqb, mqb_flag_t flag)
@@ -781,10 +859,9 @@ bgp_session_do_update_recv(mqueue_block mqb, mqb_flag_t flag)
bgp_session session = mqb_get_arg0(mqb) ;
struct bgp_session_update_args* args = mqb_get_args(mqb) ;
- if ((flag == mqb_action) && (session->state == bgp_session_sEstablished))
+ if ( (flag == mqb_action) && (session->state == bgp_session_sEstablished) )
{
- bgp_peer peer = session->peer;
-
+ bgp_peer peer = session->peer;
stream_free(peer->ibuf);
peer->ibuf = args->buf;
bgp_update_receive (peer, args->size);
@@ -826,8 +903,8 @@ bgp_session_do_route_refresh_recv(mqueue_block mqb, mqb_flag_t flag)
struct bgp_session_route_refresh_args* args = mqb_get_args(mqb) ;
bgp_session session = mqb_get_arg0(mqb) ;
- if ((flag == mqb_action) && (session->state == bgp_session_sEstablished))
- bgp_route_refresh_recv(session->peer, args->rr);
+ if ( (flag == mqb_action) && (session->state == bgp_session_sEstablished) )
+ bgp_route_refresh_recv(session->peer, args->rr) ;
bgp_route_refresh_free(args->rr);
mqb_free(mqb);
@@ -860,9 +937,10 @@ bgp_session_do_XON(mqueue_block mqb, mqb_flag_t flag)
{
bgp_session session = mqb_get_arg0(mqb) ;
- if ((flag == mqb_action) && (session->state == bgp_session_sEstablished))
+ if ( (flag == mqb_action) && (session->state == bgp_session_sEstablished) )
{
int xoff = (session->flow_control <= 0);
+
session->flow_control = BGP_XON_REFRESH;
if (xoff)
bgp_write (session->peer, NULL) ;
@@ -923,59 +1001,46 @@ bgp_session_do_set_ttl(mqueue_block mqb, mqb_flag_t flag)
*/
/*------------------------------------------------------------------------------
- * See if session exists and is active.
+ * Routing Engine: see if session exists and is active.
*
- * Ensure that if exists and is not active, that the peer index entry accept
- * pointer is NULL -- this is largely paranoia, but it would be a grave
- * mistake for the listening socket(s) to find a session which is not active !
+ * If exists then performs a few checks, just to make sure things are straight.
*
- * NB: accessing Routing Engine "private" variable -- no lock required.
+ * NB: accessing Routing Engine "private" variable -- no lock required.
*
- * accessing index_entry when not active -- no lock required.
+ * checks session->active, only when not active -- no lock required.
*/
-extern int
+extern bool
bgp_session_is_active(bgp_session session)
{
- int active ;
+ bool active ;
if (session == NULL)
- active = 0 ;
+ active = false ;
else
{
- active = ( (session->state == bgp_session_sEnabled)
- || (session->state == bgp_session_sEstablished)
- || (session->state == bgp_session_sLimping) ) ;
-
- if (!active)
- assert(session->index_entry->accept == NULL) ;
+ switch (session->state)
+ {
+ case bgp_session_sIdle:
+ case bgp_session_sDisabled:
+ assert(!session->active) ;
+ active = false ;
+ break ;
+
+ case bgp_session_sEnabled:
+ case bgp_session_sEstablished:
+ case bgp_session_sLimping:
+ active = true ;
+ break ;
+
+ default:
+ zabort("invalid session->state") ;
+ } ;
} ;
return active ;
} ;
/*------------------------------------------------------------------------------
- * Routing Engine: if session is limping we defer re-enabling the session
- * until it is disabled.
- *
- * returns 1 if limping and defer
- * returns 0 if not limping
- *
- * NB: accessing Routing Engine "private" variable -- no lock required.
- */
-static int
-bgp_session_defer_if_limping(bgp_session session)
-{
- int defer_enable = 0 ;
-
- if (session == NULL)
- defer_enable = 0 ;
- else
- defer_enable = (session->state == bgp_session_sLimping) ;
-
- return session->defer_enable = defer_enable ;
-} ;
-
-/*------------------------------------------------------------------------------
* Get a copy of the session statistics, copied all at once so
* forms a consistent snapshot
*/
diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h
index 6f449bec..79b6f1a4 100644
--- a/bgpd/bgp_session.h
+++ b/bgpd/bgp_session.h
@@ -89,23 +89,22 @@ struct bgp_session_stats
struct bgp_session
{
- /* The following are set when the session is created, and not changed
- * thereafter.
+ /* The following is set when the session is created, and not changed
+ * thereafter, so do not need to lock the session to access this.
*/
bgp_peer peer ; /* peer whose session this is */
- bgp_peer_index_entry index_entry ; /* and its index entry */
/* This is a *recursive* mutex */
qpt_mutex_t mutex ; /* for access to the rest */
- /* While sIdle and sStopped:
+ /* While sIdle and sDisabled -- aka not "active" states:
*
* the session belongs to the Routing Engine.
*
* The BGP Engine will not touch a session in these states and the
* Routing Engine may do what it likes with it.
*
- * While sEnabled, sEstablished and sStopping:
+ * While sEnabled, sEstablished and sLimping -- aka "active" states:
*
* the session belongs to the BGP Engine.
*
@@ -119,11 +118,12 @@ struct bgp_session
* These are private to the Routing Engine.
*/
bgp_session_state_t state ;
- int defer_enable ; /* set when waiting for stop */
int flow_control ; /* limits number of updates sent
by the Routing Engine */
+ bool delete_me ; /* when next goes sDisabled */
+
/* These are private to the Routing Engine, and are set each time a session
* event message is received from the BGP Engine.
*/
@@ -211,10 +211,15 @@ struct bgp_session
* and enable are ignored. This deals with the hiatus that exists between
* the BGP Engine signalling that it has stopped (because of some exception)
* and the Routing Engine acknowledging that (by disabling the session).
+ *
+ * The accept flag is set when the secondary connection is completely ready
+ * to accept connections. It is cleared otherwise, or when the active flag
+ * is cleared.
*/
bgp_connection connections[bgp_connection_count] ;
bool active ;
+ bool accept ;
} ;
/*==============================================================================
@@ -267,7 +272,7 @@ MQB_ARGS_SIZE_OK(bgp_session_end_of_rib_args) ;
struct bgp_session_event_args /* to Routeing Engine */
{
- bgp_session_event_t event ;
+ bgp_session_event_t event ; /* what just happened */
bgp_notify notification ; /* sent or received (if any) */
int err ; /* errno if any */
bgp_connection_ord_t ordinal ; /* primary/secondary connection */
@@ -309,10 +314,7 @@ inline static void BGP_SESSION_UNLOCK(bgp_session session)
*/
extern bgp_session
-bgp_session_init_new(bgp_session session, bgp_peer peer) ;
-
-extern bgp_session
-bgp_session_free(bgp_session session);
+bgp_session_init_new(bgp_peer peer) ;
extern void
bgp_session_enable(bgp_peer peer) ;
@@ -321,6 +323,9 @@ extern void
bgp_session_disable(bgp_peer peer, bgp_notify notification) ;
extern void
+bgp_session_delete(bgp_peer peer);
+
+extern void
bgp_session_event(bgp_session session, bgp_session_event_t event,
bgp_notify notification,
int err,
@@ -358,7 +363,7 @@ bgp_session_get_stats(bgp_session session, struct bgp_session_stats *stats);
* Session data access functions.
*/
-extern int
+extern bool
bgp_session_is_active(bgp_session session) ;
#endif /* QUAGGA_BGP_SESSION_H */
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 91cab606..a2581e3c 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -96,6 +96,7 @@ bgp_node_set (struct bgp_table *table, struct prefix *prefix)
static void
bgp_node_free (struct bgp_node *node)
{
+ node->lock = -54321 ;
XFREE (MTYPE_BGP_NODE, node);
}
@@ -128,11 +129,17 @@ bgp_table_free (struct bgp_table *rt)
continue;
}
+ assert( (node->info == NULL)
+ && (node->adj_out == NULL)
+ && (node->adj_in == NULL)
+ && (node->on_wq == 0) ) ;
+
tmp_node = node;
node = node->parent;
tmp_node->table->count--;
tmp_node->lock = 0; /* to cause assert if unlocked after this */
+
bgp_node_free (tmp_node);
if (node != NULL)
@@ -152,10 +159,11 @@ bgp_table_free (struct bgp_table *rt)
if (rt->owner)
{
- peer_unlock (rt->owner);
+ bgp_peer_unlock (rt->owner);
rt->owner = NULL;
}
+ rt->lock = -54321 ;
XFREE (MTYPE_BGP_TABLE, rt);
return;
}
@@ -371,6 +379,7 @@ bgp_node_delete (struct bgp_node *node)
assert (node->lock == 0);
assert (node->info == NULL);
+ assert (node->on_wq == 0) ;
if (node->l_left && node->l_right)
return;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 1afc9f94..2a5acb05 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1353,7 +1353,7 @@ DEFUN (no_neighbor,
{
peer = peer_lookup (vty->index, &su);
if (peer)
- peer_delete (peer);
+ bgp_peer_delete (peer);
}
return CMD_SUCCESS;
@@ -1794,7 +1794,7 @@ DEFUN (no_neighbor_dont_capability_negotiate,
static int
peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi,
- safi_t safi, u_int32_t flag, int set)
+ safi_t safi, u_int32_t flag, bool set)
{
int ret;
struct peer *peer;
@@ -1803,10 +1803,7 @@ peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi,
if (! peer)
return CMD_WARNING;
- if (set)
- ret = peer_af_flag_set (peer, afi, safi, flag);
- else
- ret = peer_af_flag_unset (peer, afi, safi, flag);
+ ret = peer_af_flag_modify(peer, afi, safi, flag, set);
return bgp_vty_return (vty, ret);
}
@@ -1815,14 +1812,14 @@ static int
peer_af_flag_set_vty (struct vty *vty, const char *peer_str, afi_t afi,
safi_t safi, u_int32_t flag)
{
- return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1);
+ return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, true);
}
static int
peer_af_flag_unset_vty (struct vty *vty, const char *peer_str, afi_t afi,
safi_t safi, u_int32_t flag)
{
- return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0);
+ return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, false);
}
/* neighbor capability orf prefix-list. */
@@ -2080,7 +2077,7 @@ peer_rsclient_set_vty (struct vty *vty, const char *peer_str,
struct listnode *node, *nnode;
struct bgp_filter *pfilter;
struct bgp_filter *gfilter;
- int locked_and_added = 0;
+ bool was_active ;
bgp = vty->index;
@@ -2092,29 +2089,22 @@ peer_rsclient_set_vty (struct vty *vty, const char *peer_str,
if ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) )
return CMD_SUCCESS;
- if ( ! peer_rsclient_active (peer) )
- {
- peer = peer_lock (peer); /* rsclient peer list reference */
- listnode_add_sort (bgp->rsclient, peer);
- locked_and_added = 1;
- }
+ was_active = peer_rsclient_active(peer) ;
ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT);
if (ret < 0)
- {
- if (locked_and_added)
- {
- listnode_delete (bgp->rsclient, peer);
- peer_unlock (peer); /* rsclient peer list reference */
- }
+ return bgp_vty_return (vty, ret);
- return bgp_vty_return (vty, ret);
- }
+ if (!was_active)
+ {
+ bgp_peer_lock (peer); /* rsclient peer list reference */
+ listnode_add_sort (bgp->rsclient, peer);
+ } ;
peer->rib[afi][safi] = bgp_table_init (afi, safi);
peer->rib[afi][safi]->type = BGP_TABLE_RSCLIENT;
/* RIB peer reference. Released when table is free'd in bgp_table_free. */
- peer->rib[afi][safi]->owner = peer_lock (peer);
+ peer->rib[afi][safi]->owner = bgp_peer_lock (peer);
/* Check for existing 'network' and 'redistribute' routes. */
bgp_check_local_routes_rsclient (peer, afi, safi);
@@ -2181,10 +2171,19 @@ peer_rsclient_unset_vty (struct vty *vty, const char *peer_str,
if ( ! peer )
return CMD_WARNING;
+ assert(bgp == peer->bgp) ;
+
/* If it is not a RS-Client, don't do anything. */
if ( ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) )
return CMD_SUCCESS;
+ /* If this is a Peer Group, then need to undo the relevant rsclient state
+ * for all the group members.
+ *
+ * That means clearing the state flag and the pointer to the shared RIB.
+ *
+ * TODO: peer_af_flag_unset PEER_FLAG_RSERVER_CLIENT fails for group members ?
+ */
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
{
group = peer->group;
@@ -2201,20 +2200,63 @@ peer_rsclient_unset_vty (struct vty *vty, const char *peer_str,
peer = group->conf;
}
+ /* Unset the rsclient flag and remove from rsclient list if no longer a
+ * distinct rsclient.
+ *
+ * NB: this takes care of downing the peer, if required.
+ */
ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT);
if (ret < 0)
return bgp_vty_return (vty, ret);
- if ( ! peer_rsclient_active (peer) )
+ /* Now tidy up the data structures. */
+ peer_rsclient_unset(peer, afi, safi, false) ;
+
+ return CMD_SUCCESS;
+}
+
+/* Have unset rsclient state for a peer that was a distinct rsclient.
+ *
+ * Tidy up the data structures.
+ *
+ * NB: does not down the peer or deal with other consequences.
+ */
+void
+peer_rsclient_unset(struct peer* peer, int afi, int safi, bool keep_export)
+{
+ assert(peer->rib[afi][safi] != NULL) ;
+
+ /* If the peer is no longer a distinct rsclient, remove from list of same. */
+ if (! peer_rsclient_active (peer))
{
- bgp_clear_route_rsclient (peer, afi, safi);
- listnode_delete (bgp->rsclient, peer);
- peer_unlock (peer); /* peer bgp rsclient reference */
+ struct listnode *pn;
+ pn = listnode_lookup (peer->bgp->rsclient, peer) ;
+
+ assert(pn != NULL) ;
+
+ bgp_peer_unlock (peer); /* peer rsclient reference */
+ list_delete_node (peer->bgp->rsclient, pn);
}
- bgp_table_finish (&peer->rib[bgp_node_afi(vty)][bgp_node_safi(vty)]);
+ /* Discard the rsclient rib */
+ bgp_clear_rsclient_rib (peer, afi, safi);
+ bgp_table_finish (&peer->rib[afi][safi]);
- return CMD_SUCCESS;
+ /* Discard import policy unconditionally */
+ if (peer->filter[afi][safi].map[RMAP_IMPORT].name)
+ {
+ free (peer->filter[afi][safi].map[RMAP_IMPORT].name);
+ peer->filter[afi][safi].map[RMAP_IMPORT].name = NULL;
+ peer->filter[afi][safi].map[RMAP_IMPORT].map = NULL;
+ }
+
+ /* Discard export policy unless should be kept. */
+ if (peer->filter[afi][safi].map[RMAP_EXPORT].name && !keep_export)
+ {
+ free (peer->filter[afi][safi].map[RMAP_EXPORT].name);
+ peer->filter[afi][safi].map[RMAP_EXPORT].name = NULL;
+ peer->filter[afi][safi].map[RMAP_EXPORT].map = NULL;
+ }
}
/* neighbor route-server-client. */
@@ -6778,7 +6820,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
vty_out (vty, "%8s",
peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
- if (peer->state == bgp_peer_sEstablished)
+ if (peer->state == bgp_peer_pEstablished)
{
vty_out (vty, " %8ld", peer->pcount[afi][safi]);
}
@@ -7315,7 +7357,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
/* Status. */
vty_out (vty, " BGP state = %s",
LOOKUP (bgp_peer_status_msg, p->state));
- if (p->state == bgp_peer_sEstablished)
+ if (p->state == bgp_peer_pEstablished)
vty_out (vty, ", up for %8s",
peer_uptime (p->uptime, timebuf, BGP_UPTIME_LEN));
/* TODO: what is state "Active" now? sEnabled? */
@@ -7344,7 +7386,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
}
/* Capability. */
- if (p->state == bgp_peer_sEstablished)
+ if (p->state == bgp_peer_pEstablished)
{
if (p->cap
|| p->afc_adv[AFI_IP][SAFI_UNICAST]
@@ -7466,7 +7508,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
int eor_receive_af_count = 0;
vty_out (vty, " Graceful restart informations:%s", VTY_NEWLINE);
- if (p->state == bgp_peer_sEstablished)
+ if (p->state == bgp_peer_pEstablished)
{
vty_out (vty, " End-of-RIB send: ");
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index c0fc3628..195ccaef 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -167,7 +167,7 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length)
continue;
if (ifp == peer_if)
- bgp_peer_disable(peer, NULL);
+ bgp_peer_down(peer, PEER_DOWN_INTERFACE_DOWN);
}
}
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 1176d2d0..dfcc7ff0 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -80,9 +80,6 @@ qpn_nexus routing_nexus = NULL;
/* BGP community-list. */
struct community_list_handler *bgp_clist;
-/* true while program terminating */
-static int program_terminating = 0;
-
/* BGP global flag manipulation. */
int
bgp_option_set (int flag)
@@ -183,13 +180,7 @@ bgp_router_id_set (struct bgp *bgp, struct in_addr *id)
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
IPV4_ADDR_COPY (&peer->local_id, id);
-
- if (peer->state == bgp_peer_sEstablished)
- {
- peer->last_reset = PEER_DOWN_RID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
+ bgp_peer_down(peer, PEER_DOWN_RID_CHANGE) ;
}
return 0;
}
@@ -214,12 +205,7 @@ bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id)
if (peer_sort (peer) != BGP_PEER_IBGP)
continue;
- if (peer->state == bgp_peer_sEstablished)
- {
- peer->last_reset = PEER_DOWN_CLID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
+ bgp_peer_down(peer, PEER_DOWN_CLID_CHANGE) ;
}
return 0;
}
@@ -242,12 +228,7 @@ bgp_cluster_id_unset (struct bgp *bgp)
if (peer_sort (peer) != BGP_PEER_IBGP)
continue;
- if (peer->state == bgp_peer_sEstablished)
- {
- peer->last_reset = PEER_DOWN_CLID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
+ bgp_peer_down(peer, PEER_DOWN_CLID_CHANGE) ;
}
return 0;
}
@@ -267,7 +248,7 @@ int
bgp_timers_unset (struct bgp *bgp)
{
bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
- bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
+ bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
return 0;
}
@@ -300,23 +281,20 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as)
if (peer_sort (peer) == BGP_PEER_EBGP)
{
peer->local_as = as;
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_CONFED_ID_CHANGE) ;
}
}
else
{
- /* Not doign confederation before, so reset every non-local
+ /* Not doing confederation before, so reset every non-local
session */
if (peer_sort (peer) != BGP_PEER_IBGP)
{
/* Reset the local_as to be our EBGP one */
if (peer_sort (peer) == BGP_PEER_EBGP)
peer->local_as = as;
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+
+ bgp_peer_down(peer, PEER_DOWN_CONFED_ID_CHANGE) ;
}
}
}
@@ -338,9 +316,7 @@ bgp_confederation_id_unset (struct bgp *bgp)
if (peer_sort (peer) != BGP_PEER_IBGP)
{
peer->local_as = bgp->as;
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_CONFED_ID_CHANGE) ;
}
}
return 0;
@@ -396,9 +372,7 @@ bgp_confederation_peers_add (struct bgp *bgp, as_t as)
if (peer->as == as)
{
peer->local_as = bgp->as;
- peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_CONFED_PEER_CHANGE) ;
}
}
}
@@ -447,9 +421,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t as)
if (peer->as == as)
{
peer->local_as = bgp->confed_id;
- peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_CONFED_PEER_CHANGE) ;
}
}
}
@@ -535,7 +507,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
filter->aslist[i].name = NULL;
}
}
- for (i = RMAP_IN; i < RMAP_MAX; i++)
+ for (i = RMAP_IN; i < RMAP_MAX; i++)
{
if (filter->map[i].name)
{
@@ -664,59 +636,15 @@ peer_sort (struct peer *peer)
}
}
-
-/* increase reference count on a struct peer */
-struct peer *
-peer_lock (struct peer *peer)
-{
- assert (peer && (peer->lock >= 0));
-
- peer->lock++;
-
- return peer;
-}
-
-/* decrease reference count on a struct peer
- * struct peer is freed and NULL returned if last reference
- */
-struct peer *
-peer_unlock (struct peer *peer)
-{
- assert (peer && (peer->lock > 0));
-
- peer->lock--;
-
- if (peer->lock == 0)
- {
-#if 0
- zlog_debug ("unlocked and freeing");
- zlog_backtrace (LOG_DEBUG);
-#endif
- peer_free (peer);
- return NULL;
- }
-
-#if 0
- if (peer->lock == 1)
- {
- zlog_debug ("unlocked to 1");
- zlog_backtrace (LOG_DEBUG);
- }
-#endif
-
- return peer;
-}
-
-
/* Make accept BGP peer. Called from bgp_accept (). */
struct peer *
peer_create_accept (struct bgp *bgp)
{
struct peer *peer;
- peer = peer_new (bgp);
+ peer = bgp_peer_new (bgp);
- peer = peer_lock (peer); /* bgp peer list reference */
+ peer = bgp_peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
return peer;
@@ -728,13 +656,6 @@ peer_as_change (struct peer *peer, as_t as)
{
int type;
- /* Stop peer. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
type = peer_sort (peer);
peer->as = as;
@@ -772,12 +693,16 @@ peer_as_change (struct peer *peer, as_t as)
PEER_FLAG_REFLECTOR_CLIENT);
}
- /* local-as reset */
+ /* local-as reset */
if (peer_sort (peer) != BGP_PEER_EBGP)
{
peer->change_local_as = 0;
UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
}
+
+ /* Down peer. */
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ bgp_peer_down(peer, PEER_DOWN_REMOTE_AS_CHANGE) ;
}
/* If peer does not exist, create new one. If peer already exists,
@@ -836,14 +761,16 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
else
local_as = bgp->as;
- /* If this is IPv4 unicast configuration and "no bgp default
- ipv4-unicast" is specified. */
+ /* TODO: report bug... if is IPv4 unicast, may implicitly activate */
- if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
- && afi == AFI_IP && safi == SAFI_UNICAST)
- peer = peer_create (su, bgp, local_as, *as, 0, 0);
+ /* If this is IPv4 unicast configuration and "no bgp default
+ ipv4-unicast" is NOT specified.
+ */
+ if (!bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
+ && (afi == AFI_IP) && (safi == SAFI_UNICAST))
+ peer = bgp_peer_create (su, bgp, local_as, *as, afi, safi);
else
- peer = peer_create (su, bgp, local_as, *as, afi, safi);
+ peer = bgp_peer_create (su, bgp, local_as, *as, 0, 0);
}
return 0;
@@ -853,7 +780,7 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
int
peer_activate (struct peer *peer, afi_t afi, safi_t safi)
{
- int active;
+ bool was_active;
if (peer->afc[afi][safi])
return 0;
@@ -863,15 +790,19 @@ peer_activate (struct peer *peer, afi_t afi, safi_t safi)
peer->afc[afi][safi] = 1;
else
{
- active = peer_active (peer);
-
+ was_active = peer_active (peer);
peer->afc[afi][safi] = 1;
- if (! active && peer_active (peer))
+ /* If wasn't active, can now enable since now is.
+ *
+ * Otherwise, to enable an extra AFI/SAFI need either to use Dynamic
+ * Capabilities or restart the session.
+ */
+ if (! was_active)
bgp_peer_enable (peer);
else
-#if 0
/* TODO: Dynamic capability */
+#if 0
{
if (peer->status == Established)
{
@@ -890,9 +821,7 @@ peer_activate (struct peer *peer, afi_t afi, safi_t safi)
else
#endif
{
- peer->last_reset = PEER_DOWN_AF_ACTIVATE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_AF_ACTIVATE) ;
}
#if 0
}
@@ -905,17 +834,19 @@ peer_activate (struct peer *peer, afi_t afi, safi_t safi)
int
peer_deactivate (struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_group *group;
- struct peer *peer1;
- struct listnode *node, *nnode;
+ bool was_rsclient ;
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct peer* group_member ;
+
group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1))
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, group_member))
{
- if (peer1->af_group[afi][safi])
+ if (group_member->af_group[afi][safi])
return BGP_ERR_PEER_GROUP_MEMBER_EXISTS;
}
}
@@ -928,53 +859,56 @@ peer_deactivate (struct peer *peer, afi_t afi, safi_t safi)
if (! peer->afc[afi][safi])
return 0;
- /* De-activate the address family configuration. */
+ /* If we arrive here, the peer is either:
+ *
+ * - a real peer which is not a group member for this afi/safi
+ *
+ * - a group which has no members for this afi/safi.
+ *
+ * In which case, if this is an rsclient, it is a distinct rsclient, and the
+ * rsclient RIB should be discarded.
+ */
+ was_rsclient = CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_RSERVER_CLIENT) ;
+
+ /* De-activate the address family configuration. */
peer->afc[afi][safi] = 0;
peer_af_flag_reset (peer, afi, safi);
+ /* Tidy up if was rsclient */
+ if (was_rsclient)
+ peer_rsclient_unset(peer, afi, safi, false) ;
+
+ /* Deal with knock on effect on real peer */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->state == bgp_peer_sEstablished)
- {
- /* Unless can dynamically reconfigure: once a session is established,
- * turning off an address family requires the session to be dropped
- * and restarted.
- */
- if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV))
- {
- peer->afc_adv[afi][safi] = 0;
- peer->afc_nego[afi][safi] = 0;
+ bool down = true ;
- if (peer_active_nego (peer))
- {
- bgp_capability_send (peer, afi, safi,
- CAPABILITY_CODE_MP,
- CAPABILITY_ACTION_UNSET);
- bgp_clear_route_normal(peer, afi, safi);
- peer->pcount[afi][safi] = 0;
- }
- else
- {
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- else
- {
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- else if ((peer->state == bgp_peer_sIdle) && !peer_active (peer))
+ if ( (peer->state == bgp_peer_pEstablished)
+ && CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV) )
{
- /* In sIdle, the BGP Engine may be trying to connect... if no address
- * family is now active, need now to shut down the session.
- */
- bgp_peer_disable(peer, NULL) ;
+ /* If can dynamically reconfigure can avoid restarting the session. */
+ peer->afc_adv[afi][safi] = 0;
+ peer->afc_nego[afi][safi] = 0;
+
+ if (peer_active_nego (peer))
+ {
+ bool completed ;
+ bgp_capability_send (peer, afi, safi, CAPABILITY_CODE_MP,
+ CAPABILITY_ACTION_UNSET);
+ completed = bgp_clear_routes(peer, afi, safi, false) ;
+ /* If clearing routes does not complete, what do we do ? */
+ passert(completed) ;
+ peer->pcount[afi][safi] = 0;
+
+ down = false ; /* don't need to down the peer */
+ } ;
} ;
- }
+
+ if (down)
+ bgp_peer_down(peer, PEER_DOWN_AF_DEACTIVATE) ;
+ } ;
+
return 0;
}
@@ -1038,7 +972,7 @@ peer_group_get (struct bgp *bgp, const char *name)
group->bgp = bgp;
group->name = strdup (name);
group->peer = list_new ();
- group->conf = peer_new (bgp);
+ group->conf = bgp_peer_new (bgp);
if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
group->conf->host = XSTRDUP (MTYPE_BGP_PEER_HOST, name);
@@ -1133,6 +1067,7 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
/* Import policy. */
if (pfilter->map[RMAP_IMPORT].name)
free (pfilter->map[RMAP_IMPORT].name);
+
if (gfilter->map[RMAP_IMPORT].name)
{
pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name);
@@ -1336,7 +1271,7 @@ peer_group_delete (struct peer_group *group)
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
peer->group = NULL;
- peer_delete (peer);
+ bgp_peer_delete (peer);
}
list_delete (group->peer);
@@ -1344,7 +1279,7 @@ peer_group_delete (struct peer_group *group)
group->name = NULL;
group->conf->group = NULL;
- peer_delete (group->conf);
+ bgp_peer_delete (group->conf);
/* Delete from all peer_group list. */
listnode_delete (bgp->group, group);
@@ -1366,7 +1301,7 @@ peer_group_remote_as_delete (struct peer_group *group)
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
peer->group = NULL;
- peer_delete (peer);
+ bgp_peer_delete (peer);
}
list_delete_all_node (group->peer);
@@ -1381,7 +1316,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
struct peer_group *group, afi_t afi, safi_t safi, as_t *as)
{
struct peer *peer;
- int first_member = 0;
+ bool first_member ;
/* Check peer group's address family. */
if (! group->conf->afc[afi][safi])
@@ -1390,63 +1325,94 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
/* Lookup the peer. */
peer = peer_lookup (bgp, su);
- /* Create a new peer. */
+ /* Create a new peer -- iff group specifies a remote-as. */
if (! peer)
{
if (! group->conf->as)
return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
- peer = peer_create (su, bgp, bgp->as, group->conf->as, afi, safi);
+ peer = bgp_peer_create (su, bgp, bgp->as, group->conf->as, afi, safi);
peer->group = group;
peer->af_group[afi][safi] = 1;
- peer = peer_lock (peer); /* group->peer list reference */
+ peer = bgp_peer_lock (peer); /* group->peer list reference */
listnode_add (group->peer, peer);
peer_group2peer_config_copy (group, peer, afi, safi);
- return 0;
+ return 0 ; /* Done */
}
- /* When the peer already belongs to peer group, check the consistency. */
+ assert(bgp == peer->bgp) ;
+
+ /* When the peer already belongs to peer group, check the consistency.
+ *
+ * If already belong to a group for the current afi/safi, then must be the
+ * same group -- cannot change group association by this means.
+ */
if (peer->af_group[afi][safi])
{
if (strcmp (peer->group->name, group->name) != 0)
return BGP_ERR_PEER_GROUP_CANT_CHANGE;
- return 0;
+ return 0; /* Done */
}
- /* Check current peer group configuration. */
+ /* Check current peer group configuration.
+ *
+ * Can only belong to one group at a time. All afi/safi which are members of
+ * a group, must be members of the same group.
+ */
if (peer_group_active (peer)
&& strcmp (peer->group->name, group->name) != 0)
return BGP_ERR_PEER_GROUP_MISMATCH;
- if (! group->conf->as)
- {
- if (peer_sort (group->conf) != BGP_PEER_INTERNAL
- && peer_sort (group->conf) != peer_sort (peer))
- {
- if (as)
- *as = peer->as;
- return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
- }
+ /* If binding to this group would change the sort of peer, then cannot
+ * do it.
+ *
+ * The group itself may not carry a sort of peer ?? Or something ??
+ */
+ first_member = false ;
+ if (! group->conf->as) /* If group does NOT specify a remote AS ? */
+ {
if (peer_sort (group->conf) == BGP_PEER_INTERNAL)
- first_member = 1;
+ first_member = true ;
+ else
+ {
+ if (peer_sort (group->conf) != peer_sort (peer))
+ {
+ if (as)
+ *as = peer->as;
+ return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
+ }
+ }
}
+ /* Can join the group.
+ *
+ * NB: if we get to here, then we know that this afi/safi was NOT a member
+ * of any group.
+ *
+ * Note that this appears to implicitly activate the afi/safi... but does
+ * not go through the rest of the activation process ???
+ *
+ * TODO: why does implicit activation of afi/safi not do more work ?
+ */
peer->af_group[afi][safi] = 1;
peer->afc[afi][safi] = 1;
+
+ /* If not already a member, add to list of members. */
if (! peer->group)
{
peer->group = group;
- peer = peer_lock (peer); /* group->peer list reference */
+ peer = bgp_peer_lock (peer); /* group->peer list reference */
listnode_add (group->peer, peer);
}
else
assert (group && peer->group == group);
+ /* Further magic stuff to do with peer sort. */
if (first_member)
{
/* Advertisement-interval reset */
@@ -1467,48 +1433,39 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
}
}
+ /* Worry about rsclient state of the peer for this afi/safi.
+ *
+ * A peer cannot be an rsclient separately from its group.
+ *
+ * This peer was not previously a member of any group for this afi/safi.
+ *
+ * So if the peer is an rsclient for this afi/safi, it had better stop
+ * that now.
+ */
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
{
- struct listnode *pn;
-
- /* If it's not configured as RSERVER_CLIENT in any other address
- family, without being member of a peer_group, remove it from
- list bgp->rsclient.*/
- if (! peer_rsclient_active (peer)
- && (pn = listnode_lookup (bgp->rsclient, peer)))
- {
- peer_unlock (peer); /* peer rsclient reference */
- list_delete_node (bgp->rsclient, pn);
+ /* Now that we have set peer->af_group for this afi/safi, this peer
+ * may no longer have any distinct rsclient status, in which case it
+ * must be removes from list bgp->rsclient.
+ *
+ * Note that it must have had distinct rsclient status, because it is
+ * an rsclient in this afi/safi, and it was not a group member in this
+ * afi/safi.
+ *
+ * We discard any import and export route map, except if the group is
+ * an rsclient, when we keep the export route map.
+ */
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ;
- /* Clear our own rsclient rib for this afi/safi. */
- bgp_clear_route_rsclient (peer, afi, safi);
- }
-
- bgp_table_finish (&peer->rib[afi][safi]);
-
- /* Import policy. */
- if (peer->filter[afi][safi].map[RMAP_IMPORT].name)
- {
- free (peer->filter[afi][safi].map[RMAP_IMPORT].name);
- peer->filter[afi][safi].map[RMAP_IMPORT].name = NULL;
- peer->filter[afi][safi].map[RMAP_IMPORT].map = NULL;
- }
-
- /* Export policy. */
- if (! CHECK_FLAG(group->conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
- && peer->filter[afi][safi].map[RMAP_EXPORT].name)
- {
- free (peer->filter[afi][safi].map[RMAP_EXPORT].name);
- peer->filter[afi][safi].map[RMAP_EXPORT].name = NULL;
- peer->filter[afi][safi].map[RMAP_EXPORT].map = NULL;
- }
+ peer_rsclient_unset(peer, afi, safi,
+ CHECK_FLAG(group->conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) ;
}
+ /* Now deal with the rest of the group configuration. */
peer_group2peer_config_copy (group, peer, afi, safi);
- peer->last_reset = PEER_DOWN_RMAP_BIND;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ /* And down the peer to push into new state. */
+ bgp_peer_down(peer, PEER_DOWN_RMAP_BIND) ;
return 0;
}
@@ -1518,35 +1475,42 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,
struct peer_group *group, afi_t afi, safi_t safi)
{
if (! peer->af_group[afi][safi])
- return 0;
+ return 0; /* quit if not member of any group */
if (group != peer->group)
- return BGP_ERR_PEER_GROUP_MISMATCH;
+ return BGP_ERR_PEER_GROUP_MISMATCH; /* quit if not member of this group */
+ /* So is a member of this group for this afi/safi.
+ *
+ * This is an implied deactivation for this peer. That is taken care of in
+ * bgp_peer_down().
+ */
peer->af_group[afi][safi] = 0;
peer->afc[afi][safi] = 0;
peer_af_flag_reset (peer, afi, safi);
- if (peer->rib[afi][safi])
- peer->rib[afi][safi] = NULL;
+ /* Is member of group, so if it is an rsclient we were using its rsclient
+ * RIB, which must now forget.
+ */
+ peer->rib[afi][safi] = NULL;
+ /* If is now not a member of any group */
if (! peer_group_active (peer))
{
assert (listnode_lookup (group->peer, peer));
- peer_unlock (peer); /* peer group list reference */
+ bgp_peer_unlock (peer); /* peer group list reference */
listnode_delete (group->peer, peer);
peer->group = NULL;
if (group->conf->as)
{
- peer_delete (peer);
+ bgp_peer_delete (peer);
return 0;
}
peer_global_config_reset (peer);
}
- peer->last_reset = PEER_DOWN_RMAP_UNBIND;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_RMAP_UNBIND) ;
+
return 0;
}
@@ -1562,7 +1526,7 @@ bgp_create (as_t *as, const char *name)
return NULL;
bgp_lock (bgp);
- bgp->peer_self = peer_new (bgp);
+ bgp->peer_self = bgp_peer_new (bgp);
bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static announcement");
bgp->peer = list_new ();
@@ -1710,7 +1674,7 @@ bgp_delete (struct bgp *bgp)
bgp_redistribute_unset (bgp, afi, i);
for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
- peer_delete (peer);
+ bgp_peer_delete (peer);
for (ALL_LIST_ELEMENTS (bgp->group, node, next, group))
peer_group_delete (group);
@@ -1718,7 +1682,7 @@ bgp_delete (struct bgp *bgp)
assert (listcount (bgp->rsclient) == 0);
if (bgp->peer_self) {
- peer_delete(bgp->peer_self);
+ bgp_peer_delete(bgp->peer_self);
bgp->peer_self = NULL;
}
@@ -1783,8 +1747,7 @@ peer_lookup (struct bgp *bgp, union sockunion *su)
if (bgp != NULL)
{
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (sockunion_same (&peer->su, su)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ if (sockunion_same (&peer->su, su))
return peer;
}
else if (bm->bgp != NULL)
@@ -1793,13 +1756,13 @@ peer_lookup (struct bgp *bgp, union sockunion *su)
for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (sockunion_same (&peer->su, su)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ if (sockunion_same (&peer->su, su))
return peer;
}
return NULL;
}
+#if 0
struct peer *
peer_lookup_with_open (union sockunion *su, as_t remote_as,
struct in_addr *remote_id, int *as)
@@ -1842,6 +1805,7 @@ peer_lookup_with_open (union sockunion *su, as_t remote_as,
}
return NULL;
}
+#endif
/* If peer is configured at least one address family return 1. */
int
@@ -1869,200 +1833,222 @@ peer_active_nego (struct peer *peer)
return 0;
}
-/* peer_flag_change_type. */
+/*------------------------------------------------------------------------------
+ * Actions required after a change of state of a peer.
+ */
enum peer_change_type
{
- peer_change_none,
- peer_change_reset,
- peer_change_reset_in,
- peer_change_reset_out,
-};
-
+ peer_change_none, /* no further action */
+ peer_change_reset, /* drop any existing session and restart */
+ peer_change_reset_in, /* if possible, ask for route refresh,
+ otherwise drop and restart. */
+ peer_change_reset_out, /* reannounce everything */
+} ;
+
+typedef enum peer_change_type peer_change_type_t ;
+
+/* Perform action after change of state of a peer for the given afi/safi.
+ *
+ * If has to down the peer (drop any existing session and restart), then
+ * requires a peer_down_t to record why.
+ */
static void
peer_change_action (struct peer *peer, afi_t afi, safi_t safi,
- enum peer_change_type type)
+ enum peer_change_type type,
+ peer_down_t why_changed)
{
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
return;
- if (type == peer_change_reset)
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else if (type == peer_change_reset_in)
- {
- if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
- || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
- bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
- else
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else if (type == peer_change_reset_out)
- bgp_announce_route (peer, afi, safi);
-}
+ switch (type)
+ {
+ case peer_change_none:
+ break ;
+ case peer_change_reset:
+ bgp_peer_down(peer, why_changed) ;
+ break ;
+
+ case peer_change_reset_in:
+ if (peer->state == bgp_peer_pEstablished)
+ {
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ else
+ bgp_peer_down(peer, why_changed);
+ } ;
+ break ;
+
+ case peer_change_reset_out:
+ bgp_announce_route (peer, afi, safi) ; /* Does nothing if !pEstablished */
+ break ;
+
+ default:
+ zabort("unknown peer_change_type") ;
+ break ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ *
+ *
+ */
struct peer_flag_action
{
- /* Peer's flag. */
+ /* Peer's flag. */
u_int32_t flag;
- /* This flag can be set for peer-group member. */
- u_char not_for_member;
+ /* This flag can be set for peer-group member. */
+ bool not_for_member;
- /* Action when the flag is changed. */
- enum peer_change_type type;
+ /* Action when the flag is changed. */
+ peer_change_type_t type;
- /* Peer down cause */
- u_char peer_down;
+ /* Peer down cause */
+ peer_down_t peer_down;
};
+/*------------------------------------------------------------------------------
+ * Table of actions for changing peer->flags
+ *
+ * NB: change actions are peer_change_none or peer_change_reset ONLY.
+ * (The peer->flags apply to all afi/safi.)
+ *
+ * NB: PEER_FLAG_LOCAL_AS_NO_PREPEND is dealt with eslewhere.
+ *
+ * NB: all flags are set/cleared individually.
+ */
static const struct peer_flag_action peer_flag_action_list[] =
{
- { PEER_FLAG_PASSIVE, 0, peer_change_reset },
- { PEER_FLAG_SHUTDOWN, 0, peer_change_reset },
- { PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none },
- { PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none },
- { PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none },
- { PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset },
- { PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset },
- { 0, 0, 0 }
+ { PEER_FLAG_PASSIVE,
+ false, peer_change_reset, PEER_DOWN_PASSIVE_CHANGE},
+ { PEER_FLAG_SHUTDOWN,
+ false, peer_change_reset, PEER_DOWN_USER_SHUTDOWN },
+ { PEER_FLAG_DONT_CAPABILITY,
+ false, peer_change_none, PEER_DOWN_NULL },
+ { PEER_FLAG_OVERRIDE_CAPABILITY,
+ false, peer_change_none, PEER_DOWN_NULL },
+ { PEER_FLAG_STRICT_CAP_MATCH,
+ false, peer_change_none, PEER_DOWN_NULL },
+ { PEER_FLAG_DYNAMIC_CAPABILITY,
+ false, peer_change_reset, PEER_DOWN_CAPABILITY_CHANGE },
+ { PEER_FLAG_DISABLE_CONNECTED_CHECK,
+ false, peer_change_reset, PEER_DOWN_CONFIG_CHANGE },
+ { 0, false, peer_change_none, PEER_DOWN_NULL }
};
+/*------------------------------------------------------------------------------
+ * Table of actions for changing peer->af_flags
+ *
+ * NB: some flags may be set/cleared together, in any combination.
+ */
static const struct peer_flag_action peer_af_flag_action_list[] =
{
- { PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
- { PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out },
- { PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out },
- { PEER_FLAG_SOFT_RECONFIG, 0, peer_change_reset_in },
- { PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
- { PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
- { PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out },
- { PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out },
- { PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out },
- { PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out },
- { PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in },
- { PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset },
- { PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset },
- { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out },
- { 0, 0, 0 }
+ { PEER_FLAG_NEXTHOP_SELF,
+ true, peer_change_reset_out, PEER_DOWN_NULL },
+ { PEER_FLAG_SEND_COMMUNITY
+ | PEER_FLAG_SEND_EXT_COMMUNITY,
+ true, peer_change_reset_out, PEER_DOWN_NULL },
+ { PEER_FLAG_SOFT_RECONFIG,
+ false, peer_change_reset_in, PEER_DOWN_CONFIG_CHANGE },
+ { PEER_FLAG_REFLECTOR_CLIENT,
+ true, peer_change_reset, PEER_DOWN_RR_CLIENT_CHANGE },
+ { PEER_FLAG_RSERVER_CLIENT,
+ true, peer_change_reset, PEER_DOWN_RS_CLIENT_CHANGE },
+ { PEER_FLAG_AS_PATH_UNCHANGED
+ | PEER_FLAG_NEXTHOP_UNCHANGED
+ | PEER_FLAG_MED_UNCHANGED,
+ true, peer_change_reset_out, PEER_DOWN_NULL },
+ { PEER_FLAG_REMOVE_PRIVATE_AS,
+ true, peer_change_reset_out, PEER_DOWN_NULL },
+ { PEER_FLAG_ALLOWAS_IN,
+ false, peer_change_reset_in, PEER_DOWN_ALLOWAS_IN_CHANGE },
+ { PEER_FLAG_ORF_PREFIX_SM
+ | PEER_FLAG_ORF_PREFIX_RM,
+ true, peer_change_reset, PEER_DOWN_CONFIG_CHANGE },
+ { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED,
+ false, peer_change_reset_out, PEER_DOWN_NULL },
+ { 0, false, peer_change_none, PEER_DOWN_NULL }
};
-/* Proper action set. */
-static int
-peer_flag_action_set (const struct peer_flag_action *action_list, int size,
- struct peer_flag_action *action, u_int32_t flag)
+/*------------------------------------------------------------------------------
+ * Look up action for given flags.
+ *
+ * Returns: address of required peer_flag_action structure,
+ * or: NULL if no action found for the given combination of flags.
+ *
+ * This mechanism is generally used when setting/clearing one flag at a time.
+ *
+ * The table may contain entries with more than one flag. In these cases,
+ * any combination of those flags may be set/cleared together -- any flags
+ * which are not mentioned are not affected.
+ *
+ * The given flags value must either exactly match a single flag entry, or be
+ * a subset of a multiple flag entry. The table is searched in the order
+ * given, and proceeds to the end before stopping.
+ */
+static const struct peer_flag_action*
+peer_flag_action_set (const struct peer_flag_action* action, uint32_t flag)
{
- int i;
- int found = 0;
- int reset_in = 0;
- int reset_out = 0;
- const struct peer_flag_action *match = NULL;
-
- /* Check peer's frag action. */
- for (i = 0; i < size; i++)
+ while (action->flag != 0)
{
- match = &action_list[i];
-
- if (match->flag == 0)
- break;
-
- if (match->flag & flag)
- {
- found = 1;
-
- if (match->type == peer_change_reset_in)
- reset_in = 1;
- if (match->type == peer_change_reset_out)
- reset_out = 1;
- if (match->type == peer_change_reset)
- {
- reset_in = 1;
- reset_out = 1;
- }
- if (match->not_for_member)
- action->not_for_member = 1;
- }
+ if ((action->flag & flag) == flag)
+ return action ;
+ action++ ;
}
- /* Set peer clear type. */
- if (reset_in && reset_out)
- action->type = peer_change_reset;
- else if (reset_in)
- action->type = peer_change_reset_in;
- else if (reset_out)
- action->type = peer_change_reset_out;
- else
- action->type = peer_change_none;
-
- return found;
+ return NULL ;
}
+/*------------------------------------------------------------------------------
+ * Having set or cleared something in peer->flags, make any implied changes.
+ *
+ * NB: Clearing PEER_FLAG_SHUTDOWN is a special case
+ *
+ * NB: Setting PEER_FLAG_SHUTDOWN -> PEER_DOWN_USER_SHUTDOWN, which is a
+ * special case in bgp_peer_down.
+ */
static void
-peer_flag_modify_action (struct peer *peer, u_int32_t flag)
+peer_flag_modify_action (struct peer *peer,
+ const struct peer_flag_action* action, bool set)
{
- if (flag == PEER_FLAG_SHUTDOWN)
- {
- if (CHECK_FLAG (peer->flags, flag))
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
+ if (action->type == peer_change_none)
+ return ;
- UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
- if (peer->t_pmax_restart)
- {
- BGP_TIMER_OFF (peer->t_pmax_restart);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s Maximum-prefix restart timer cancelled",
- peer->host);
- }
-#if 0 /* TODO: surely no need to peer_nsf_stop() twice ? */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
-#endif
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
- else
- {
- peer->v_start = BGP_INIT_START_TIMER;
- bgp_peer_enable(peer);
- }
- }
- else
+ assert(action->type == peer_change_reset) ;
+
+ if ((action->flag == PEER_FLAG_SHUTDOWN) && !set)
{
- if (flag == PEER_FLAG_DYNAMIC_CAPABILITY)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_PASSIVE)
- peer->last_reset = PEER_DOWN_PASSIVE_CHANGE;
- else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)
- peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE;
+ peer->v_start = BGP_INIT_START_TIMER;
+ bgp_peer_enable(peer);
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
-}
+ return ; /* Note */
+ } ;
-/* Change specified peer flag. */
+ bgp_peer_down(peer, action->peer_down) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Change specified peer->flags flag.
+ *
+ * See: peer_flag_action_list above.
+ */
static int
-peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
+peer_flag_modify (struct peer *peer, u_int32_t flag, bool set)
{
- int found;
- int size;
struct peer_group *group;
struct listnode *node, *nnode;
- struct peer_flag_action action;
+ const struct peer_flag_action* action;
- memset (&action, 0, sizeof (struct peer_flag_action));
- size = sizeof peer_flag_action_list / sizeof (struct peer_flag_action);
-
- found = peer_flag_action_set (peer_flag_action_list, size, &action, flag);
+ action = peer_flag_action_set (peer_flag_action_list, flag) ;
/* No flag action is found. */
- if (! found)
+ if (action == NULL)
return BGP_ERR_INVALID_FLAG;
/* Not for peer-group member. */
- if (action.not_for_member && peer_group_active (peer))
+ if (action->not_for_member && peer_group_active (peer))
return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
/* When unset the peer-group member's flag we have to check
@@ -2097,9 +2083,7 @@ peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (action.type == peer_change_reset)
- peer_flag_modify_action (peer, flag);
-
+ peer_flag_modify_action (peer, action, set);
return 0;
}
@@ -2119,22 +2103,27 @@ peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
else
UNSET_FLAG (peer->flags, flag);
- if (action.type == peer_change_reset)
- peer_flag_modify_action (peer, flag);
+ peer_flag_modify_action (peer, action, set);
}
return 0;
}
+/*------------------------------------------------------------------------------
+ * Set specified peer->flags flag.
+ */
int
peer_flag_set (struct peer *peer, u_int32_t flag)
{
- return peer_flag_modify (peer, flag, 1);
+ return peer_flag_modify (peer, flag, true);
}
+/*------------------------------------------------------------------------------
+ * Clear specified peer->flags flag.
+ */
int
peer_flag_unset (struct peer *peer, u_int32_t flag)
{
- return peer_flag_modify (peer, flag, 0);
+ return peer_flag_modify (peer, flag, false);
}
static int
@@ -2145,23 +2134,43 @@ peer_is_group_member (struct peer *peer, afi_t afi, safi_t safi)
return 0;
}
-static int
+/*------------------------------------------------------------------------------
+ * Having set or cleared something in peer->af_flags, make any implied changes.
+ *
+ * NB: clearing PEER_FLAG_SOFT_RECONFIG is a special case.
+ */
+static void
+peer_af_flag_modify_action (struct peer *peer, afi_t afi, safi_t safi,
+ const struct peer_flag_action* action, bool set)
+{
+ if ((action->flag == PEER_FLAG_SOFT_RECONFIG) && !set)
+ {
+ if (peer->state == bgp_peer_pEstablished)
+ bgp_clear_adj_in (peer, afi, safi);
+ }
+ else
+ {
+ peer_change_action (peer, afi, safi, action->type, action->peer_down) ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Change specified peer->af_flags flag.
+ *
+ * See: peer_af_flag_action_list above.
+ */
+int
peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
- int set)
+ bool set)
{
- int found;
- int size;
struct listnode *node, *nnode;
struct peer_group *group;
- struct peer_flag_action action;
-
- memset (&action, 0, sizeof (struct peer_flag_action));
- size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action);
+ const struct peer_flag_action* action;
- found = peer_flag_action_set (peer_af_flag_action_list, size, &action, flag);
+ action = peer_flag_action_set (peer_af_flag_action_list, flag);
/* No flag action is found. */
- if (! found)
+ if (action == NULL)
return BGP_ERR_INVALID_FLAG;
/* Adress family must be activated. */
@@ -2169,17 +2178,16 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
return BGP_ERR_PEER_INACTIVE;
/* Not for peer-group member. */
- if (action.not_for_member && peer_is_group_member (peer, afi, safi))
+ if (action->not_for_member && peer_is_group_member (peer, afi, safi))
return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
/* Spcecial check for reflector client. */
- if (flag & PEER_FLAG_REFLECTOR_CLIENT
- && peer_sort (peer) != BGP_PEER_IBGP)
+ if ((flag & PEER_FLAG_REFLECTOR_CLIENT) && (peer_sort(peer) != BGP_PEER_IBGP))
return BGP_ERR_NOT_INTERNAL_PEER;
/* Spcecial check for remove-private-AS. */
- if (flag & PEER_FLAG_REMOVE_PRIVATE_AS
- && peer_sort (peer) == BGP_PEER_IBGP)
+ if ((flag & PEER_FLAG_REMOVE_PRIVATE_AS)
+ && (peer_sort(peer) == BGP_PEER_IBGP))
return BGP_ERR_REMOVE_PRIVATE_AS;
/* When unset the peer-group member's flag we have to check
@@ -2191,7 +2199,7 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
/* When current flag configuration is same as requested one. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
+ if ( set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
return 0;
if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
return 0;
@@ -2202,82 +2210,54 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
else
UNSET_FLAG (peer->af_flags[afi][safi], flag);
- /* Execute action when peer is established. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && peer->state == bgp_peer_sEstablished)
+ /* Execute action. */
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
- bgp_clear_adj_in (peer, afi, safi);
- else
- {
- if (flag == PEER_FLAG_REFLECTOR_CLIENT)
- peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_RSERVER_CLIENT)
- peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_SM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_RM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
-
- peer_change_action (peer, afi, safi, action.type);
- }
-
- }
+ peer_af_flag_modify_action(peer, afi, safi, action, set) ;
+ return 0 ;
+ } ;
/* Peer group member updates. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ group = peer->group;
+
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
- group = peer->group;
+ if (! peer->af_group[afi][safi])
+ continue;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (! peer->af_group[afi][safi])
- continue;
+ if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
+ continue;
- if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
- continue;
+ if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
+ continue;
- if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
- continue;
+ if (set)
+ SET_FLAG (peer->af_flags[afi][safi], flag);
+ else
+ UNSET_FLAG (peer->af_flags[afi][safi], flag);
- if (set)
- SET_FLAG (peer->af_flags[afi][safi], flag);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], flag);
+ peer_af_flag_modify_action(peer, afi, safi, action, set) ;
+ } ;
- if (peer->state == bgp_peer_sEstablished)
- {
- if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
- bgp_clear_adj_in (peer, afi, safi);
- else
- {
- if (flag == PEER_FLAG_REFLECTOR_CLIENT)
- peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_RSERVER_CLIENT)
- peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_SM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_RM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
-
- peer_change_action (peer, afi, safi, action.type);
- }
- }
- }
- }
return 0;
}
+/*------------------------------------------------------------------------------
+ * Set specified peer->af_flags flag.
+ */
int
peer_af_flag_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
{
- return peer_af_flag_modify (peer, afi, safi, flag, 1);
+ return peer_af_flag_modify (peer, afi, safi, flag, true);
}
+/*------------------------------------------------------------------------------
+ * Clear specified peer->af_flags flag.
+ */
int
peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
{
- return peer_af_flag_modify (peer, afi, safi, flag, 0);
+ return peer_af_flag_modify (peer, afi, safi, flag, false);
}
/* EBGP multihop configuration. */
@@ -2405,9 +2385,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
return 0;
}
@@ -2432,9 +2410,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname)
peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname);
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
}
return 0;
}
@@ -2464,9 +2440,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
return 0;
}
@@ -2490,9 +2464,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
peer->update_source = sockunion_dup (su);
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
}
return 0;
}
@@ -2536,9 +2508,7 @@ peer_update_source_unset (struct peer *peer)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
return 0;
}
@@ -2561,9 +2531,7 @@ peer_update_source_unset (struct peer *peer)
peer->update_if = NULL;
}
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
}
return 0;
}
@@ -2600,7 +2568,7 @@ peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->state == bgp_peer_sEstablished && peer->afc_nego[afi][safi])
+ if (peer->state == bgp_peer_pEstablished && peer->afc_nego[afi][safi])
bgp_default_originate (peer, afi, safi, 0);
return 0;
}
@@ -2619,7 +2587,7 @@ peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap);
}
- if (peer->state == bgp_peer_sEstablished && peer->afc_nego[afi][safi])
+ if (peer->state == bgp_peer_pEstablished && peer->afc_nego[afi][safi])
bgp_default_originate (peer, afi, safi, 0);
}
return 0;
@@ -2651,7 +2619,7 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->state == bgp_peer_sEstablished && peer->afc_nego[afi][safi])
+ if (peer->state == bgp_peer_pEstablished && peer->afc_nego[afi][safi])
bgp_default_originate (peer, afi, safi, 1);
return 0;
}
@@ -2667,7 +2635,7 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
- if (peer->state == bgp_peer_sEstablished && peer->afc_nego[afi][safi])
+ if (peer->state == bgp_peer_pEstablished && peer->afc_nego[afi][safi])
bgp_default_originate (peer, afi, safi, 1);
}
return 0;
@@ -2908,7 +2876,8 @@ peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num)
{
peer->allowas_in[afi][safi] = allow_num;
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
- peer_change_action (peer, afi, safi, peer_change_reset_in);
+ peer_change_action (peer, afi, safi, peer_change_reset_in,
+ PEER_DOWN_ALLOWAS_IN_CHANGE) ;
}
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
@@ -2921,7 +2890,8 @@ peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num)
{
peer->allowas_in[afi][safi] = allow_num;
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
- peer_change_action (peer, afi, safi, peer_change_reset_in);
+ peer_change_action (peer, afi, safi, peer_change_reset_in,
+ PEER_DOWN_ALLOWAS_IN_CHANGE) ;
}
}
@@ -2985,10 +2955,8 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- return 0;
+ bgp_peer_down(peer, PEER_DOWN_LOCAL_AS_CHANGE) ;
+ return 0 ;
}
group = peer->group;
@@ -3000,9 +2968,7 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
else
UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_LOCAL_AS_CHANGE) ;
}
return 0;
@@ -3025,9 +2991,7 @@ peer_local_as_unset (struct peer *peer)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_LOCAL_AS_CHANGE) ;
return 0;
}
@@ -3037,9 +3001,7 @@ peer_local_as_unset (struct peer *peer)
peer->change_local_as = 0;
UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_LOCAL_AS_CHANGE) ;
}
return 0;
}
@@ -3066,8 +3028,7 @@ peer_password_set (struct peer *peer, const char *password)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_PASSWORD_CHANGE) ;
return BGP_SUCCESS;
}
@@ -3081,8 +3042,7 @@ peer_password_set (struct peer *peer, const char *password)
peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_PASSWORD_CHANGE) ;
}
return ret;
@@ -3104,13 +3064,14 @@ peer_password_unset (struct peer *peer)
&& strcmp (peer->group->conf->password, peer->password) == 0)
return BGP_ERR_PEER_GROUP_HAS_THE_FLAG;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
-
if (peer->password)
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
+ {
+ XFREE (MTYPE_PEER_PASSWORD, peer->password);
+ /* sets peer->password NULL */
+
+ bgp_peer_down(peer, PEER_DOWN_PASSWORD_CHANGE) ;
+ } ;
- peer->password = NULL;
return 0;
}
@@ -3122,11 +3083,9 @@ peer_password_unset (struct peer *peer)
if (!peer->password)
continue;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
-
XFREE (MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
+ /* sets peer->password NULL */
+ bgp_peer_down(peer, PEER_DOWN_PASSWORD_CHANGE) ;
}
return 0;
@@ -3840,30 +3799,14 @@ peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi)
int
peer_clear (struct peer *peer)
{
- if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
- {
- UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
- if (peer->t_pmax_restart)
- {
- BGP_TIMER_OFF (peer->t_pmax_restart);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s Maximum-prefix restart timer cancelled",
- peer->host);
- }
+ /* Overrides any Max Prefix issues. */
+ bgp_maximum_prefix_cancel_timer (peer) ;
- /* Beware we may still be clearing, if so the end of
- * clearing will enable the peer */
- bgp_peer_enable(peer);
+ /* Overrides any idle hold timer */
+ peer->v_start = BGP_INIT_START_TIMER;
- return 0;
- }
+ bgp_peer_down(peer, PEER_DOWN_USER_RESET) ;
- peer->v_start = BGP_INIT_START_TIMER;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_RESET);
- }
return 0;
}
@@ -3871,7 +3814,7 @@ int
peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
enum bgp_clear_type stype)
{
- if (peer->state == bgp_peer_sEstablished)
+ if (peer->state == bgp_peer_pEstablished)
return 0;
if (! peer->afc[afi][safi])
@@ -3922,7 +3865,8 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
}
}
- if (stype == BGP_CLEAR_SOFT_IN || stype == BGP_CLEAR_SOFT_BOTH
+ if ( stype == BGP_CLEAR_SOFT_IN
+ || stype == BGP_CLEAR_SOFT_BOTH
|| stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX)
{
/* If neighbor has soft reconfiguration inbound flag.
@@ -4446,11 +4390,8 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
{
if (peer->afc[afi][safi])
{
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- bgp_config_write_family_header (vty, afi, safi, &write);
- bgp_config_write_peer (vty, bgp, peer, afi, safi);
- }
+ bgp_config_write_family_header (vty, afi, safi, &write);
+ bgp_config_write_peer (vty, bgp, peer, afi, safi);
}
}
if (write)
@@ -4621,10 +4562,7 @@ bgp_config_write (struct vty *vty)
/* Normal neighbor configuration. */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
- }
+ bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
/* Distance configuration. */
bgp_config_write_distance (vty, bgp);
@@ -4657,11 +4595,18 @@ bgp_master_init (void)
bm = &bgp_master;
bm->bgp = list_new ();
- bm->port = BGP_PORT_DEFAULT;
bm->master = thread_master_create ();
+ bm->port = BGP_PORT_DEFAULT;
bm->start_time = time (NULL);
-}
+ /* Implicitly:
+ *
+ * address = NULL -- no special listen address
+ * options = 0 -- no options set
+ * as2_speaker = false -- as4 speaker by default
+ * peer_linger_count = 0 -- no peers lingering
+ */
+} ;
void
bgp_init (void)
@@ -4707,6 +4652,12 @@ bgp_init (void)
#endif /* HAVE_SNMP */
}
+/*------------------------------------------------------------------------------
+ * If not terminating, reset all peers now
+ *
+ * If
+ *
+ */
void
bgp_terminate (int terminating, int retain_mode)
{
@@ -4715,75 +4666,22 @@ bgp_terminate (int terminating, int retain_mode)
struct listnode *node, *nnode;
struct listnode *mnode, *mnnode;
- program_terminating = terminating;
-
- /* Disable all peers */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (retain_mode)
- bgp_peer_disable(peer, NULL);
- else if (terminating)
- {
- peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
- /* Belt and braces, probably redundant */
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
- else
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_RESET);
- }
-
- if (!retain_mode)
- bgp_cleanup_routes ();
-
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+ /* If we are retaining, then turn off changes to the FIB. */
+ if (retain_mode)
{
- if (bgp->process_main_queue)
- {
- work_queue_free (bgp->process_main_queue);
- bgp->process_main_queue = NULL;
- }
- if (bgp->process_rsclient_queue)
- {
- work_queue_free (bgp->process_rsclient_queue);
- bgp->process_rsclient_queue = NULL;
- }
- }
-
- /* if no sessions were enabled then need to check here */
- program_terminate_if_all_disabled();
-}
+ assert(terminating) ; /* Can only retain when terminating */
+ bgp_option_set(BGP_OPT_NO_FIB) ;
+ } ;
-/* If we are terminating the program, and all sessions are disabled
- * then terminate all threads
- */
-void
-program_terminate_if_all_disabled(void)
-{
- struct bgp *bgp;
- struct peer *peer;
- struct listnode *node, *nnode;
- struct listnode *mnode, *mnnode;
-
- if (!program_terminating)
- return;
-
- /* are there any active sessions remaining? */
+ /* For all bgp instances... */
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (bgp_session_is_active(peer->session))
- return;
-
- /* ask remaining pthreads to die */
- if (qpthreads_enabled && routing_nexus != NULL)
- qpn_terminate(routing_nexus);
-
- if (qpthreads_enabled && bgp_nexus != NULL)
- qpn_terminate(bgp_nexus);
-
- if (cli_nexus != NULL)
- qpn_terminate(cli_nexus);
-}
+ {
+ /* ...delete or down all peers. */
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if (terminating)
+ bgp_peer_delete(peer) ;
+ else
+ bgp_peer_down(peer, PEER_DOWN_USER_RESET) ;
+ } ;
+} ;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index cd92576a..7a53c511 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -35,19 +35,17 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* BGP master for system wide configurations and variables. */
struct bgp_master
{
- /* BGP instance list. */
+ /* BGP instance list. */
struct list *bgp;
- /* BGP thread master. */
+ /* BGP thread master. */
struct thread_master *master;
- /* BGP port number. */
- u_int16_t port;
-
- /* Listener address */
+ /* Listener address & port number */
char *address;
+ u_int16_t port;
- /* BGP start time. */
+ /* BGP start time. */
time_t start_time;
/* Various BGP global configuration. */
@@ -58,6 +56,9 @@ struct bgp_master
/* Do not announce AS4 */
bool as2_speaker ;
+
+ /* Peers lingering in pDeleting */
+ unsigned peer_linger_count ;
};
/* BGP instance structure. */
@@ -69,7 +70,7 @@ struct bgp
/* Name of this BGP instance. */
char *name;
- /* Reference count to allow peer_delete to finish after bgp_delete */
+ /* Reference count to allow bgp_peer_delete to finish after bgp_delete */
int lock;
/* Self peer. */
@@ -423,8 +424,6 @@ extern struct peer_group *peer_group_lookup (struct bgp *, const char *);
extern struct peer_group *peer_group_get (struct bgp *, const char *);
extern struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_addr *,
int *);
-extern struct peer *peer_lock (struct peer *);
-extern struct peer *peer_unlock (struct peer *);
extern int peer_sort (struct peer *peer);
extern int peer_active (struct peer *);
extern int peer_active_nego (struct peer *);
@@ -474,13 +473,15 @@ extern int peer_rsclient_active (struct peer *);
extern int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t);
extern int peer_group_remote_as (struct bgp *, const char *, as_t *);
-extern int peer_delete (struct peer *peer);
extern int peer_group_delete (struct peer_group *);
extern int peer_group_remote_as_delete (struct peer_group *);
extern int peer_activate (struct peer *, afi_t, safi_t);
extern int peer_deactivate (struct peer *, afi_t, safi_t);
+extern void peer_rsclient_unset(struct peer* peer, int afi, int safi,
+ bool keep_export) ;
+
extern int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *,
afi_t, safi_t, as_t *);
extern int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *,
@@ -491,6 +492,8 @@ extern int peer_flag_unset (struct peer *, u_int32_t);
extern int peer_af_flag_set (struct peer *, afi_t, safi_t, u_int32_t);
extern int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t);
+extern int peer_af_flag_modify (struct peer *, afi_t, safi_t, u_int32_t,
+ bool set) ;
extern int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t);
extern int peer_ebgp_multihop_set (struct peer *, int);
diff --git a/configure.ac b/configure.ac
index 85784080..3507a120 100755
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,7 @@
## $Id$
AC_PREREQ(2.53)
-AC_INIT(Quagga, 0.99.15ex01, [http://bugzilla.quagga.net])
+AC_INIT(Quagga, 0.99.15ex02, [http://bugzilla.quagga.net])
AC_CONFIG_SRCDIR(lib/zebra.h)
AC_CONFIG_MACRO_DIR([m4])
diff --git a/lib/plist.c b/lib/plist.c
index 41868e96..85ff35f8 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -700,18 +700,24 @@ prefix_list_entry_lookup_seq(struct prefix_list *plist, int seq, int* result)
*
* Returns index of an entry in the prefix_list or the dup_cache, and sets:
*
- * cache -- NULL if not using dup_cache for this prefix_list.
- * The index and result values refer to the main prefix_list.
+ * cache -- NULL if not using dup_cache for this prefix_list.
+ * The index and result values refer to the main prefix_list.
*
- * -- address of the cache (a vector).
- * The index and result values refer to the cache. << NB
+ * result < 0 -- not found. prefix list is empty, index == 0
+ * result == 0 -- found. index is of the prefix list entry
+ * result > 0 -- not found. prefix is not empty, index == last
*
- * result < 0 -- not found. index returned is of first entry in the
- * prefix list, and this sequence number comes
- * before it. (Or list is empty.)
- * result == 0 -- found. index is of the entry found.
- * result > 0 -- not found. index returned is of the entry with the largest
- * sequence number smaller than the given one.
+ * -- address of the cache (a vector).
+ * The index and result values refer to the *cache*. << NB
+ *
+ * result < 0 -- not found. index == 0, prefix value given is
+ * less than first entry in the *cache*
+ * result == 0 -- found. index is of the *cache* entry
+ * result > 0 -- not found. index is of entry in the *cache*
+ * with the largest prefix value less
+ * than the given prefix value.
+ *
+ * Note that the cache is never empty.
*/
static vector_index
prefix_list_entry_lookup_val(struct prefix_list *plist,
@@ -749,7 +755,9 @@ prefix_list_entry_lookup_val(struct prefix_list *plist,
if (plist->cmp(&pe, &temp) == 0)
return i ; /* Found ! */
} ;
- *result = 1 ; /* Not found. */
+
+ *result = (vector_end(&plist->list) == 0) ? -1 : +1 ;
+ /* Not found. */
return i ;
} ;
} ;
@@ -855,16 +863,21 @@ prefix_list_entry_insert(struct prefix_list *plist,
i = prefix_list_entry_lookup_seq(plist, temp->seq, &ret) ;
else
{
- int last_seq = 0 ;
+ int last_seq ;
i = vector_end(&plist->list) ;
- if (i != 0)
+ if (i == 0)
+ {
+ last_seq = 0 ; /* initial value for empty list */
+ ret = -1 ; /* insert before first item of empty list */
+ }
+ else
{
- --i ; /* step back to last entry */
+ --i ; /* step back to last entry */
pe = vector_get_item(&plist->list, i) ;
- last_seq = pe->seq ;
+ last_seq = pe->seq ;
+ ret = 1 ; /* insert after last entry */
} ;
temp->seq = (((last_seq + 5 - 1) / 5) * 5) + 5 ;
- ret = 1 ; /* insert after last entry (if any) */
} ;
/* If we found it with same sequence number, then replace entry,
diff --git a/lib/qpnexus.c b/lib/qpnexus.c
index 59dcc535..3b014be2 100644
--- a/lib/qpnexus.c
+++ b/lib/qpnexus.c
@@ -53,7 +53,7 @@ static void qpn_in_thread_init(qpn_nexus qpn);
* Returns the qpn_nexus.
*/
extern qpn_nexus
-qpn_init_new(qpn_nexus qpn, int main_thread)
+qpn_init_new(qpn_nexus qpn, bool main_thread)
{
if (qpn == NULL)
qpn = XCALLOC(MTYPE_QPN_NEXUS, sizeof(struct qpn_nexus)) ;
@@ -309,13 +309,19 @@ qpn_in_thread_init(qpn_nexus qpn)
}
/*------------------------------------------------------------------------------
- * Ask the thread to terminate itself quickly and cleanly
+ * Ask the thread to terminate itself quickly and cleanly.
+ *
+ * Does nothing if terminate already set.
*/
void
qpn_terminate(qpn_nexus qpn)
{
- qpn->terminate = 1;
- /* wake up any pselect */
- if (qpthreads_enabled)
- qpt_thread_signal(qpn->thread_id, SIGMQUEUE);
+ if (!qpn->terminate)
+ {
+ qpn->terminate = true ;
+
+ /* wake up any pselect */
+ if (qpthreads_enabled)
+ qpt_thread_signal(qpn->thread_id, SIGMQUEUE);
+ } ;
}
diff --git a/lib/qpnexus.h b/lib/qpnexus.h
index f4195a4d..0cf5a824 100644
--- a/lib/qpnexus.h
+++ b/lib/qpnexus.h
@@ -75,10 +75,10 @@ typedef struct qpn_nexus* qpn_nexus ;
struct qpn_nexus
{
/* set true to terminate the thread (eventually) */
- int terminate;
+ bool terminate;
/* true if this is the main thread */
- int main_thread;
+ bool main_thread;
/* thread ID */
qpt_thread_t thread_id;
@@ -146,7 +146,7 @@ struct qpn_nexus
* Functions
*/
-extern qpn_nexus qpn_init_new(qpn_nexus qpn, int main_thread);
+extern qpn_nexus qpn_init_new(qpn_nexus qpn, bool main_thread);
extern void qpn_add_hook_function(qpn_hook_list list, void* hook) ;
extern void qpn_exec(qpn_nexus qpn);
extern void qpn_terminate(qpn_nexus qpn);
diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c
index 8f265870..cae9a12d 100644
--- a/tests/bgp_capability_test.c
+++ b/tests/bgp_capability_test.c
@@ -664,7 +664,7 @@ main (void)
parse_test (peer, &opt_params[i++], OPT_PARAM);
SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
- peer->state = bgp_peer_sEstablished;
+ peer->state = bgp_peer_pEstablished;
i = 0;
while (dynamic_cap_msgs[i].name)