diff options
-rw-r--r-- | bgpd/bgp_common.h | 4 | ||||
-rw-r--r-- | bgpd/bgp_fsm.c | 9 | ||||
-rw-r--r-- | bgpd/bgp_peer.c | 75 | ||||
-rw-r--r-- | bgpd/bgp_session.c | 153 | ||||
-rw-r--r-- | bgpd/bgp_session.h | 11 |
5 files changed, 168 insertions, 84 deletions
diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h index 52d29998..bca64376 100644 --- a/bgpd/bgp_common.h +++ b/bgpd/bgp_common.h @@ -76,8 +76,8 @@ enum bgp_session_states bgp_session_sEnabled = 1, /* attempting to connect */ bgp_session_sEstablished = 2, - bgp_session_sStopping = 3, /* for whatever reason */ - bgp_session_sStopped = 4, /* for whatever reason */ + bgp_session_sLimping = 3, /* disable message sent */ + bgp_session_sDisabled = 4, /* disable message acknowledged */ bgp_session_max_state = 4 } ; diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 475d2cbf..a3d7f651 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1602,7 +1602,12 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event) if ((connection->except != bgp_session_null_event) && (session != NULL)) { - /* Some exceptions are not reported to the Routeing Engine */ + /* Some exceptions are not reported to the Routeing Engine + * + * In particular: eDiscard and eCollision -- so the only time the + * connection->state will be Stopping is when the session is being + * stopped. (eDiscard and eCollision go quietly to Stopping !) + */ if (connection->except <= bgp_session_max_event) bgp_session_event(session, connection->except, connection->notification, @@ -2457,8 +2462,6 @@ bgp_fsm_state_change(bgp_connection connection, bgp_fsm_state_t new_state) connection->session = NULL ; connection->p_mutex = NULL ; - session->state = bgp_session_sStopped ; - break ; default: diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c index 8f84a0ef..f9abb3c1 100644 --- a/bgpd/bgp_peer.c +++ b/bgpd/bgp_peer.c @@ -58,18 +58,14 @@ /* prototypes */ -static int -bgp_session_has_established(bgp_peer peer); -static int -bgp_session_has_stopped(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); +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 int bgp_peer_stop (struct 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. @@ -121,18 +117,21 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag) /* If now Established, then the BGP Engine has exchanged BGP Open */ /* messages, and received the KeepAlive that acknowledges our Open. */ case bgp_session_eEstablished: - session->state = bgp_session_sEstablished ; bgp_session_has_established(peer); break ; + /* If now Disabled, then the BGP Engine is acknowledging the a */ + /* session disable, and the session is now disabled. */ + case bgp_session_eDisabled: + bgp_session_has_disabled(peer); + break ; + default: /* If now Stopped, then for some reason the BGP Engine has either */ /* stopped trying to connect, or the session has been stopped. */ + /* TODO: stop from BGP Engine requires a Disable to be sent... */ if (args->stopped) - { - session->state = bgp_session_sStopped ; - bgp_session_has_stopped(peer); - } ; + bgp_session_has_stopped(peer); break ; } @@ -156,6 +155,12 @@ bgp_session_has_established(bgp_peer peer) safi_t safi; int nsf_af_count = 0; + bgp_session session = peer->session ; + + assert(session->state == bgp_session_sEnabled) ; + + session->state = bgp_session_sEstablished ; + /* update peer state from received open */ bgp_peer_open_state_receive(peer); @@ -255,12 +260,46 @@ bgp_session_has_established(bgp_peer peer) return 0; } -/* State change to stopped, session mutex locked */ +/*------------------------------------------------------------------------------ + * State change to sLimping, session mutex locked + * + * 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. + */ static int bgp_session_has_stopped(bgp_peer peer) { + bgp_session session = peer->session ; + + assert(bgp_session_is_active(session)) ; + + bgp_session_disable(peer, NULL) ; /* does nothing if already sLimping */ + + /* TODO: needs to kick off the process of withdrawing routes etc. */ + /* TODO: needs to deal with NOTIFICATION, if any ?? */ + /* TODO: needs to automatically re-enable the peering ?? */ + bgp_peer_stop(peer) ; + + return 0; +} + +/*------------------------------------------------------------------------------ + * State change to sDisabled, session mutex locked + * + * The BGP Engine has acknowledged the disable request. + */ +static int +bgp_session_has_disabled(bgp_peer peer) +{ bgp_session session = peer->session; + assert(session->state == bgp_session_sLimping) ; + + session->state = bgp_session_sDisabled ; + + /* TODO: here should revoke session in Peering Engine message queue */ + /* does the session need to be re-enabled? */ if (session->defer_enable) { diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c index 5ab0f3b8..6fa7479a 100644 --- a/bgpd/bgp_session.c +++ b/bgpd/bgp_session.c @@ -37,7 +37,7 @@ #include "lib/zassert.h" /* prototypes */ -static int bgp_session_defer_if_stopping(bgp_session session); +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); @@ -57,28 +57,34 @@ static void bgp_session_do_XON(mqueue_block mqb, mqb_flag_t flag); * is a mutex to coordinate access. * * A session is created some time before it is enabled, and may be destroyed - * when the peer is disabled, or once the session has stopped. + * once the session is disabled. * * A session may be in one of four states: * - * * bgp_session_Idle -- not doing anything - * * bgp_session_Enabled -- the BGP Engine is trying to connect - * * bgp_session_Established -- the BGP Engine is exchanging updates etc - * * bgp_session_Stopping -- the BGP Engine is stopping the session - * * bgp_session_Stopped -- a session has come to a dead stop + * * bgp_session_sIdle -- not doing anything + * * bgp_session_sEnabled -- the BGP Engine is trying to connect + * * bgp_session_sEstablished -- the BGP Engine is exchanging updates etc + * * bgp_session_sLimping -- in the process of being disabled + * * bgp_session_sDisabled -- completely disabled * - * NB: in Idle and Stopped states the BGP Engine has no interest in the session. - * These are known as the "inactive" states. + * NB: in sIdle and sDisabled states the BGP Engine has no interest in the + * session. These are known as the "inactive" states. * - * NB: in Enabled, Established and Stopping states the BGP Engine is running + * NB: in sEnabled, sEstablished and sLimping states the BGP Engine is running * connection(s) for the session. These are known as the "active" states. * * While the session is active the Routeing Engine should not attempt to * change any shared item in the session, except under the mutex. And * even then it may make no sense ! * + * NB: a session reaches eDisabled when the Peering Engine has sent a disable + * request to the BGP Engine, AND an eDisabled event has come back. + * + * While the Peering Engine is waiting for the eDisabled event, the session + * is in sLimping state. + * * The BGP Engine's primary interest is in its (private) bgp_connection - * structure(s), which (while a session is Enabled, Established or Stopping) + * structure(s), which (while a session is sEnabled, sEstablished or sLimping) * are pointed to by their associated session. */ @@ -94,7 +100,7 @@ static void bgp_session_do_XON(mqueue_block mqb, mqb_flag_t flag); * * Unsets everything else -- mostly by zeroising it. * - * NB: if not allocating, the existing session MUST be sIdle/sStopped OR never + * 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 session @@ -158,6 +164,7 @@ bgp_session_init_new(bgp_session session, bgp_peer peer) * su_remote -- NULL -- none * * connections[] -- NULL -- none + * active -- false, not yet active */ confirm(bgp_session_null_event == 0) ; @@ -193,12 +200,11 @@ bgp_session_free(bgp_session session) } /*============================================================================== - * Enable session for given peer -- allocate session if required. + * Peering Engine: enable session for given peer -- allocate if required. * * Sets up the session given the current state of the peer. If the state - * changes, then.... - * - * + * changes, then need to disable the session and re-enable it again with new + * parameters -- unless something more cunning is devised. */ extern void bgp_session_enable(bgp_peer peer) @@ -222,8 +228,8 @@ bgp_session_enable(bgp_peer peer) else { assert(session->peer == peer) ; - /* if session is stopping then defer the enable */ - if (bgp_session_defer_if_stopping(session)) + /* if session is limping then defer the enable */ + if (bgp_session_defer_if_limping(session)) return; assert(!bgp_session_is_active(session)) ; } ; @@ -295,6 +301,8 @@ bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag) BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ assert(session->state == bgp_session_sEnabled) ; + + session->active = 1 ; bgp_fsm_enable_session(session) ; BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ @@ -304,17 +312,17 @@ bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag) } ; /*============================================================================== - * Disable session for given peer -- if enabled (!). + * Peering Engine: disable session for given peer -- if enabled (!). * * Passes any bgp_notify to the BGP Engine, which will dispose of it in due * course. * * If no bgp_notify provided, will send Cease/Administrative Shutdown (2). * - * When session has been brought to a stop, BGP Engine will respond with an - * eDisabled event (unless session stopped of its own accord first). + * The BGP Engine will stop the session -- unless it is already stopped due to + * some event in the BGP Engine. In any case, the BGP Engine will respond with + * an eDisabled. */ - extern void bgp_session_disable(bgp_peer peer, bgp_notify notification) { @@ -325,7 +333,7 @@ bgp_session_disable(bgp_peer peer, bgp_notify notification) session = peer->session ; assert((session != NULL) && (session->peer == peer)) ; - /* Do nothing if session is not active, or is already stopping. */ + /* Do nothing if session is not active, or is already limping. */ if ( (session->state != bgp_session_sEnabled) && (session->state != bgp_session_sEstablished) ) ; @@ -334,22 +342,35 @@ bgp_session_disable(bgp_peer peer, bgp_notify notification) return ; } ; - /* Now change to stopping state */ - session->state = bgp_session_sStopping; + /* Now change to limping state */ + session->state = bgp_session_sLimping; /* Ask the BGP engine to disable the session. * - * NB: it is, of course, possible that the session will stop between - * issuing the disable and it being processed by the BGP Engine. + * NB: the session may already be stopped when the BGP Engine sees this + * message: + * + * * the disable is being issued in response to a stopped event from + * the BGP Engine. + * + * * the session is stopped, but the message to the Peering Engine is + * still in its message queue. * - * The BGP Engine quietly discards disable messages for sessions which - * are not active. + * * the session is stopped while the disable message is in the + * BGP Engine queue. + * + * in any case, the BGP Engine responds with an eDisabled message to + * acknowledge the disable request -- and the session will then be + * disabled. * * NB: The BGP Engine will discard any outstanding work for the session. * * The Peering Engine should discard all further messages for this - * session up to the event message that tells it the session has - * stopped. + * session up to the eDisabled, and must then discard any other + * messages for the session. + * + * NB: the Peering Engine MUST not issue any further messages until it sees + * the returned eDisabled event. */ mqb = mqb_init_new(NULL, bgp_session_do_disable, session) ; @@ -375,13 +396,16 @@ bgp_session_do_disable(mqueue_block mqb, mqb_flag_t flag) /* Get the FSM to send any notification and close connections */ bgp_fsm_disable_session(session, args->notification) ; + + /* Acknowledge the disable -- session is stopped. */ + bgp_session_event(session, bgp_session_eDisabled, NULL, 0, 0, 0) ; } ; mqb_free(mqb) ; } /*============================================================================== - * Send session event signal from BGP Engine to Routeing Engine + * BGP Engine: send session event signal to Routeing Engine */ extern void bgp_session_event(bgp_session session, bgp_session_event_t event, @@ -393,6 +417,9 @@ bgp_session_event(bgp_session session, bgp_session_event_t event, struct bgp_session_event_args* args ; mqueue_block mqb ; + if (stopped) + session->active = 0 ; /* ignore updates etc */ + mqb = mqb_init_new(NULL, bgp_session_do_event, session) ; args = mqb_get_args(mqb) ; @@ -407,14 +434,13 @@ bgp_session_event(bgp_session session, bgp_session_event_t event, } /*============================================================================== - * Dispatch update to peer -- Peering Engine -> BGP Engine + * Peering Engine: dispatch update to peer -> BGP Engine * * PRO TEM -- this is being passed the pre-packaged BGP message. * * The BGP Engine takes care of discarding the stream block once it's been * dealt with. */ - extern void bgp_session_update_send(bgp_session session, struct stream* upd) { @@ -435,7 +461,7 @@ bgp_session_update_send(bgp_session session, struct stream* upd) } ; /*------------------------------------------------------------------------------ - * BGP Engine -- mqb action function -- write given BGP update message. + * BGP Engine: write given BGP update message -- mqb action function. * * Each connection has a pending queue associated with it, onto which messages * are put if the connection's write buffer is unable to absorb any further @@ -474,12 +500,12 @@ static void bgp_session_do_update_send(mqueue_block mqb, mqb_flag_t flag) { struct bgp_session_update_args* args = mqb_get_args(mqb) ; + bgp_session session = mqb_get_arg0(mqb) ; - if (flag == mqb_action) + if ((flag == mqb_action) && session->active) { - bgp_session session = mqb_get_arg0(mqb) ; - bgp_connection connection = session->connections[bgp_connection_primary] ; + assert(connection != NULL) ; mqueue_block head = mqueue_local_head(&connection->pending_queue) ; @@ -531,7 +557,9 @@ bgp_session_do_update_send(mqueue_block mqb, mqb_flag_t flag) mqb_free(mqb) ; } ; -/* Are we in XON state ? */ +/*------------------------------------------------------------------------------ + * Peering Engine: are we in XON state ? + */ extern int bgp_session_is_XON(bgp_peer peer) { @@ -546,7 +574,7 @@ bgp_session_is_XON(bgp_peer peer) } ; /*============================================================================== - * Dispatch Route Refresh to peer -- Peering Engine -> BGP Engine + * Peering Engine: dispatch Route Refresh to peer -> BGP Engine * * The BGP Engine takes care of discarding the bgp_route_refresh once it's been * dealt with. @@ -567,7 +595,7 @@ bgp_session_route_refresh_send(bgp_session session, bgp_route_refresh rr) } ; /*------------------------------------------------------------------------------ - * BGP Engine -- mqb action function -- write given BGP route refresh message. + * BGP Engine: write given BGP route refresh message -- mqb action function. * * The logic here is the same as for bgp_session_do_update_send -- except that * there is no flow control (!). @@ -576,12 +604,12 @@ static void bgp_session_do_route_refresh_send(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) + if ((flag == mqb_action) && session->active) { - bgp_session session = mqb_get_arg0(mqb) ; - bgp_connection connection = session->connections[bgp_connection_primary] ; + assert(connection != NULL) ; mqueue_block head = mqueue_local_head(&connection->pending_queue) ; @@ -629,7 +657,7 @@ bgp_session_do_route_refresh_send(mqueue_block mqb, mqb_flag_t flag) } ; /*============================================================================== - * Dispatch End-of-RIB to peer -- Peering Engine -> BGP Engine + * Peering Engine: dispatch End-of-RIB to peer -> BGP Engine */ extern void bgp_session_end_of_rib_send(bgp_session session, qAFI_t afi, qSAFI_t safi) @@ -651,7 +679,7 @@ bgp_session_end_of_rib_send(bgp_session session, qAFI_t afi, qSAFI_t safi) } ; /*------------------------------------------------------------------------------ - * BGP Engine -- mqb action function -- write given BGP end-of-RIB message. + * BGP Engine: write given BGP end-of-RIB message -- mqb action function. * * The logic here is the same as for bgp_session_do_update_send -- except that * there is no flow control (!). @@ -660,12 +688,12 @@ static void bgp_session_do_end_of_rib_send(mqueue_block mqb, mqb_flag_t flag) { struct bgp_session_end_of_rib_args* args = mqb_get_args(mqb) ; + bgp_session session = mqb_get_arg0(mqb) ; - if (flag == mqb_action) + if ((flag == mqb_action) && session->active) { - bgp_session session = mqb_get_arg0(mqb) ; - bgp_connection connection = session->connections[bgp_connection_primary] ; + assert(connection != NULL) ; mqueue_block head = mqueue_local_head(&connection->pending_queue) ; @@ -712,15 +740,14 @@ bgp_session_do_end_of_rib_send(mqueue_block mqb, mqb_flag_t flag) } ; /*============================================================================== - * Forward incoming update -- BGP Engine -> Peering Engine + * BGP Engine: forward incoming update -> Peering Engine * * PRO TEM -- this is being passed the raw BGP message. * * The Peering Engine takes care of discarding the stream block once it's been * dealt with. */ - -void +extern void bgp_session_update_recv(bgp_session session, struct stream* buf, bgp_size_t size) { struct bgp_session_update_args* args ; @@ -735,6 +762,9 @@ bgp_session_update_recv(bgp_session session, struct stream* buf, bgp_size_t size bgp_to_peering_engine(mqb) ; } +/*------------------------------------------------------------------------------ + * Peering Engine: process incoming update message -- mqb action function. + */ static void bgp_session_do_update_recv(mqueue_block mqb, mqb_flag_t flag) { @@ -754,11 +784,10 @@ bgp_session_do_update_recv(mqueue_block mqb, mqb_flag_t flag) } /*============================================================================== - * XON -- BGP Engine -> Peering Engine + * BGP Engine: send XON message to Peering Engine * * Can be sent more packets now */ - static void bgp_session_XON(bgp_session session) { @@ -771,6 +800,9 @@ bgp_session_XON(bgp_session session) bgp_to_peering_engine(mqb) ; } +/*------------------------------------------------------------------------------ + * Peering Engine: process incoming XON message -- mqb action function. + */ static void bgp_session_do_XON(mqueue_block mqb, mqb_flag_t flag) { @@ -812,7 +844,7 @@ bgp_session_is_active(bgp_session session) { active = ( (session->state == bgp_session_sEnabled) || (session->state == bgp_session_sEstablished) - || (session->state == bgp_session_sStopping) ) ; + || (session->state == bgp_session_sLimping) ) ; if (!active) assert(session->index_entry->accept == NULL) ; @@ -824,13 +856,13 @@ bgp_session_is_active(bgp_session session) } ; /*------------------------------------------------------------------------------ - * If session is stopping we defer re-enabling the session until it has stopped. + * If session is limping we defer re-enabling the session until it is disabled. * - * returns 1 if stopping and defer - * returns 0 if not stopping + * returns 1 if limping and defer + * returns 0 if not limping */ static int -bgp_session_defer_if_stopping(bgp_session session) +bgp_session_defer_if_limping(bgp_session session) { int defer_enable = 0 ; @@ -839,7 +871,8 @@ bgp_session_defer_if_stopping(bgp_session session) BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - session->defer_enable = defer_enable = (session->state == bgp_session_sStopping); + session->defer_enable = + defer_enable = (session->state == bgp_session_sLimping); BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h index 8b30e0fe..2de8d931 100644 --- a/bgpd/bgp_session.h +++ b/bgpd/bgp_session.h @@ -183,9 +183,18 @@ struct bgp_session * touched by the Routeing Engine at any other time. * * Before stopping a session the BGP Engine unlinks any connections from - * the session. + * the session, and sets the stopped flag. + * + * The active flag is set when one or more connections are activated, and + * cleared when either the BGP Engine stops the session or the Peering + * Engine disables it. When not "active" all messages other than disable + * 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 Peering Engine acknowledging that (by disabling the session). */ bgp_connection connections[bgp_connection_count] ; + + flag_t active ; } ; /*============================================================================== |