diff options
Diffstat (limited to 'bgpd/bgp_fsm.c')
-rw-r--r-- | bgpd/bgp_fsm.c | 434 |
1 files changed, 258 insertions, 176 deletions
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index bd2ef82a..a5e3c58e 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -383,16 +383,54 @@ */ /*============================================================================== - * Enable the given connection -- which must be newly initialised. + * Enable the given session -- which must be newly initialised. * * This is the first step in the FSM, and the connection advances to Idle. * + * Returns in something of a hurry if not enabled for connect() or for accept(). + * + * NB: requires the session LOCKED */ extern void -bgp_fsm_enable_connection(bgp_connection connection) +bgp_fsm_enable_session(bgp_session session) { - assert(connection->state == bgp_fsm_Initial) ; - bgp_fsm_event(connection, bgp_fsm_BGP_Start) ; + bgp_connection connection ; + + /* Proceed instantly to a dead stop if neither connect nor listen ! */ + if (!(session->connect || session->listen)) + { + session->event = bgp_session_eInvalid ; + session->state = bgp_session_sStopped ; + + bgp_session_event(session) ; + + return ; + } ; + + /* Primary connection -- if connect allowed + * + * NB: the start event for the primary connection is guaranteed to succeed, + * and nothing further will happen until the initial IdleHoldTimer + * expires -- always has a small, non-zero time. + * + * This ensures that the secondary connection can be started before + * there's any change of the session being torn down !! + */ + if (session->connect) + { + connection = bgp_connection_init_new(NULL, session, + bgp_connection_primary) ; + bgp_fsm_event(connection, bgp_fsm_BGP_Start) ; + } ; + + /* Secondary connection -- if listen allowed + */ + if (session->listen) + { + connection = bgp_connection_init_new(NULL, session, + bgp_connection_secondary) ; + bgp_fsm_event(connection, bgp_fsm_BGP_Start) ; + } ; } ; /*============================================================================= @@ -426,14 +464,35 @@ static void bgp_fsm_throw_exception(bgp_connection connection, bgp_session_event_t except, bgp_notify notification, int err, bgp_fsm_event_t event) ; +static bgp_fsm_state_t +bgp_fsm_catch(bgp_connection connection, bgp_fsm_state_t next_state) ; + +/*------------------------------------------------------------------------------ + * Ultimate exception -- disable the session + * + * NB: requires the session LOCKED + */ +extern void +bgp_fsm_disable_session(bgp_session session, bgp_notify notification) +{ + bgp_connection connection ; + + connection = session->connections[bgp_connection_primary] ; + if (connection == NULL) + connection = session->connections[bgp_connection_secondary] ; + if (connection == NULL) + return ; + + bgp_fsm_throw_exception(connection, bgp_session_eDisabled, notification, 0, + bgp_fsm_BGP_Stop) ; +} ; + /*------------------------------------------------------------------------------ * Raise a general exception -- not I/O related. * * Note that I/O problems are signalled by bgp_fsm_io_error(). * * NB: may NOT be used within the FSM. - * - * NB: locks and unlocks the session. */ extern void bgp_fsm_raise_exception(bgp_connection connection, bgp_session_event_t except, @@ -444,9 +503,29 @@ bgp_fsm_raise_exception(bgp_connection connection, bgp_session_event_t except, } ; /*------------------------------------------------------------------------------ - * Raise a NOTIFICATION received exception + * Raise a discard exception for sibling. + * + * A connection will discard any sibling if: + * + * * the session is being disabled (by the Peering Engine) + * + * * an invalid event is bringing down the session * - * NB: locks and unlocks the session. + * * it has reached Established state, and is snuffing out the sibling. + * + * + * + * NB: requires the session LOCKED + */ +static void +bgp_fsm_discard_sibling(bgp_connection sibling, bgp_notify notification) +{ + bgp_fsm_throw_exception(sibling, bgp_session_eDiscard, + notification, 0, bgp_fsm_BGP_Stop) ; +} ; + +/*------------------------------------------------------------------------------ + * Raise a NOTIFICATION received exception */ extern void bgp_fsm_notification_exception(bgp_connection connection, @@ -560,13 +639,23 @@ bgp_fsm_connect_completed(bgp_connection connection, int err, /*------------------------------------------------------------------------------ * Post the given exception. + * + * Forget the notification if not OpenSent/OpenConfirm/Established. Cannot + * send notification in any other state -- nor receive one. */ static void bgp_fsm_post_exception(bgp_connection connection, bgp_session_event_t except, bgp_notify notification, int err) { connection->except = except ; - connection->notification = notification ; + + if ( (connection->state != bgp_fsm_OpenSent) + && (connection->state != bgp_fsm_OpenConfirm) + && (connection->state != bgp_fsm_Established) ) + bgp_notify_free(¬ification) ; + + bgp_notify_set(&connection->notification, notification) ; + connection->err = err ; } ; @@ -581,6 +670,21 @@ bgp_fsm_throw_exception(bgp_connection connection, bgp_session_event_t except, bgp_fsm_event(connection, event) ; } ; +/*------------------------------------------------------------------------------ + * Post and immediately catch a non-I/O exception. + * + * For use WITHIN the FSM. + * + * NB: requires the session LOCKED + */ +static bgp_fsm_state_t +bgp_fsm_post_catch(bgp_connection connection, bgp_session_event_t except, + bgp_notify notification, bgp_fsm_state_t next_state) +{ + bgp_fsm_post_exception(connection, except, notification, 0) ; + return bgp_fsm_catch(connection, next_state) ; +} ; + /*============================================================================== * For debug... */ @@ -1447,16 +1551,7 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event) session = connection->session ; if (session != NULL) - { - BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - if (session->event != bgp_session_null_event) - { - session->event = bgp_session_null_event ; - session->err = 0 ; - if (session->notification != NULL) - bgp_notify_free(session->notification) ; - } ; - } ; + BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ do { @@ -1502,9 +1597,26 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event) } while (--connection->fsm_active != 0) ; - if (session->event != bgp_session_null_event) + /* If required, post session event. */ + + if ((connection->except != bgp_session_null_event) && (session != NULL)) { + /* Some exceptions are no reported to the Routeing Engine */ + if (connection->except <= bgp_session_max_event) + { + session->event = connection->except ; + bgp_notify_set_mov(&session->notification, &connection->notification); + session->err = connection->err ; + session->ordinal = connection->ordinal ; + bgp_session_event(session) ; + } + else + bgp_notify_free(&connection->notification) ; /* if any */ + + /* Tidy up -- notification already cleared */ + connection->except = bgp_session_null_event ; + connection->err = 0 ; } if (session != NULL) @@ -1521,15 +1633,9 @@ bgp_hold_timer_set(bgp_connection connection, unsigned secs) ; static void bgp_hold_timer_recharge(bgp_connection connection) ; -static bgp_connection -bgp_fsm_get_sibling(bgp_connection connection) ; - static bgp_fsm_state_t bgp_fsm_send_notification(bgp_connection connection, bgp_notify notification) ; -static bgp_fsm_state_t -bgp_fsm_catch_exception(bgp_connection connection, bgp_fsm_state_t next_state) ; - /*------------------------------------------------------------------------------ * Null action -- do nothing at all. */ @@ -1542,7 +1648,10 @@ static bgp_fsm_action(bgp_fsm_null) * Entry point to FSM. * * This is the first thing to happen to the FSM, and takes it from Initial - * state to Idle, with Idle Hold Timer running. + * state to Idle, with IdleHoldTimer running. + * + * NB: the IdleHoldTimer is always a finite time. So the start up event for + * the primary connection *cannot* fail. * * NB: the session is locked. */ @@ -1551,32 +1660,29 @@ static bgp_fsm_action(bgp_fsm_enter) if (connection->ordinal == bgp_connection_secondary) bgp_prepare_to_accept(connection) ; - bgp_fsm_post_session_event(connection, bgp_session_eEnabled, NULL, 0) ; - return next_state ; } ; /*------------------------------------------------------------------------------ - * Stop BGP Connection - * - * The reason should already have been set: bgp_fsm_set_stopping(). + * Stop BGP Connection -- general exception event. * - * If no reason set => treat as invalid. + * An exception should have been raised, treat as invalid if not. * - * NB: the default new_state is used unless: + * If is eDisabled, set next_state == Stopping. + * If is eDiscard, set next_state == Stopping. * - * * the current state is Established -- all stops -> Stopping - * - * * there is a NOTIFICATION to send (in OpenSent or OpenConfirm) -- stays - * in the current state while dealing with the NOTIFICATION. - * - * * the stop reason => must -> Stopping - * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_stop) { - return next_state ; + if (connection->except == bgp_session_null_event) + return bgp_fsm_invalid(connection, bgp_fsm_Stopping, event) ; + + if ( (connection->except == bgp_session_eDisabled) + || (connection->except == bgp_session_eDiscard) ) + next_state = bgp_fsm_Stopping ; + + return bgp_fsm_catch(connection, next_state) ; } ; /*------------------------------------------------------------------------------ @@ -1586,7 +1692,9 @@ static bgp_fsm_action(bgp_fsm_stop) * * Forces transition to Stopping state for this connection and any sibling. * - * NB: the session is locked. + * If already in Stopping state, force exit. + * + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_invalid) { @@ -1594,10 +1702,12 @@ static bgp_fsm_action(bgp_fsm_invalid) plog_debug(connection->log, "%s [FSM] invalid event %d in state %d", connection->host, event, connection->state) ; - bgp_fsm_post_exception(connection, bgp_session_eInvalid, - bgp_notify_new(BGP_NOMC_FSM, BGP_NOMS_UNSPECIFIC, 0), 0) ; - - return bgp_fsm_catch_exception(connection, next_state) ; + if (connection->state != bgp_fsm_Stopping) + return bgp_fsm_post_catch(connection, bgp_session_eInvalid, + bgp_notify_new(BGP_NOMC_FSM, BGP_NOMS_UNSPECIFIC, 0), + bgp_fsm_Stopping) ; + else + return bgp_fsm_exit(connection, bgp_fsm_Stopping, event) ; } ; /*------------------------------------------------------------------------------ @@ -1619,7 +1729,7 @@ static bgp_fsm_action(bgp_fsm_invalid) * * If this is the secondary connection, enables the session for accept(). * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_start) { @@ -1634,8 +1744,6 @@ static bgp_fsm_action(bgp_fsm_start) bgp_connection_enable_accept(connection) ; } ; - bgp_fsm_post_session_event(connection, bgp_session_eStart, NULL, 0) ; - return next_state ; } ; @@ -1644,7 +1752,7 @@ static bgp_fsm_action(bgp_fsm_start) * * Send BGP Open Message to peer. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_send_open) { @@ -1665,9 +1773,9 @@ static bgp_fsm_action(bgp_fsm_send_open) sockunion2str(connection->su_local, buf_l, SU_ADDRSTRLEN)) ; } ; - bgp_msg_send_open(connection, connection->session->open_send) ; + bgp_connection_read_enable(connection) ; - bgp_fsm_post_session_event(connection, bgp_session_eTCP_connect, NULL, 0) ; + bgp_msg_send_open(connection, connection->session->open_send) ; return next_state ; } ; @@ -1682,13 +1790,11 @@ static bgp_fsm_action(bgp_fsm_send_open) * * Will stay in Connect/Active states. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_failed) { - bgp_connection_close(connection) ; - - return bgp_fsm_catch_exception(connection, next_state) ; + return bgp_fsm_catch(connection, next_state) ; } ; /*------------------------------------------------------------------------------ @@ -1699,13 +1805,11 @@ static bgp_fsm_action(bgp_fsm_failed) * This is in response to TCP_fatal_error, which has posted the * exception -- so now need to deal with it. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_fatal) { - bgp_connection_close(connection) ; - - return bgp_fsm_catch_exception(connection, next_state) ; + return bgp_fsm_catch(connection, next_state) ; } ; /*------------------------------------------------------------------------------ @@ -1721,12 +1825,13 @@ static bgp_fsm_action(bgp_fsm_fatal) * * close the existing connection (easy, 'cos never opened !) * * re-enable accept (if has been cleared) and wait for same * + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_retry) { bgp_connection_close(connection) ; - bgp_fsm_post_session_event(connection, bgp_session_eRetry, NULL, 0) ; + bgp_fsm_post_exception(connection, bgp_session_eRetry, NULL, 0) ; return bgp_fsm_start(connection, next_state, event) ; } ; @@ -1737,13 +1842,11 @@ static bgp_fsm_action(bgp_fsm_retry) * This is in response to TCP_connection_closed, which has posted the * exception -- so now need to deal with it. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_closed) { - bgp_connection_close(connection) ; - - return bgp_fsm_catch_exception(connection, next_state) ; + return bgp_fsm_catch(connection, next_state) ; } ; /*------------------------------------------------------------------------------ @@ -1754,7 +1857,7 @@ static bgp_fsm_action(bgp_fsm_closed) * * or: can wait no longer for something from the other end. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_expire) { @@ -1766,11 +1869,10 @@ static bgp_fsm_action(bgp_fsm_expire) return next_state ; } ; - /* Otherwise: raise exception */ - bgp_fsm_post_exception(connection, bgp_session_eExpired, - bgp_notify_new(BGP_NOMC_HOLD_EXP, BGP_NOMS_UNSPECIFIC, 0), 0) ; - - return bgp_fsm_catch_exception(connection, next_state) ; + /* Otherwise: post and immediately catch exception. */ + return bgp_fsm_post_catch(connection, bgp_session_eExpired, + bgp_notify_new(BGP_NOMC_HOLD_EXP, BGP_NOMS_UNSPECIFIC, 0), + next_state) ; } ; /*------------------------------------------------------------------------------ @@ -1796,12 +1898,12 @@ static bgp_fsm_action(bgp_fsm_expire) * If makes it past Collision Resolution, respond with a KEEPALIVE (to "ack" * the OPEN message). * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_recv_open) { bgp_session session = connection->session ; - bgp_connection sibling = bgp_fsm_get_sibling(connection) ; + bgp_connection sibling = bgp_connection_get_sibling(connection) ; assert(session != NULL) ; @@ -1818,22 +1920,20 @@ static bgp_fsm_action(bgp_fsm_recv_open) : sibling ; /* Set reason for stopping */ - bgp_fsm_set_stopping(loser, bgp_stopped_collision, + bgp_fsm_post_exception(loser, bgp_session_eCollision, bgp_notify_new(BGP_NOMC_CEASE, BGP_NOMS_C_COLLISION, 0), 0) ; /* If self is the loser, treat this as a BGP_Stop event ! */ /* Otherwise, issue BGP_Stop event for sibling. */ if (loser == connection) - return bgp_fsm_stop(connection, connection->state, event) ; + return bgp_fsm_catch(connection, next_state) ; else bgp_fsm_event(sibling, bgp_fsm_BGP_Stop) ; } ; - /* If all is well, send a KEEPALIVE message to acknowledge the OPEN */ + /* All is well: send a KEEPALIVE message to acknowledge the OPEN */ bgp_msg_send_keepalive(connection) ; - bgp_fsm_post_session_event(connection, bgp_session_eOpen_accept, NULL, 0) ; - /* Transition to OpenConfirm state */ return next_state ; } @@ -1850,14 +1950,13 @@ static bgp_fsm_action(bgp_fsm_recv_open) * Next state will be same as current, except for Established, when will be * Stopping. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_error) { - bgp_fsm_post_exception(connection, bgp_session_eFSM_error, - bgp_notify_new(BGP_NOMC_FSM, BGP_NOMS_UNSPECIFIC, 0), 0) ; - - return bgp_fsm_catch_exception(connection, next_state) ; + return bgp_fsm_post_catch(connection, bgp_session_eFSM_error, + bgp_notify_new(BGP_NOMC_FSM, BGP_NOMS_UNSPECIFIC, 0), + next_state) ; } ; /*------------------------------------------------------------------------------ @@ -1868,13 +1967,11 @@ static bgp_fsm_action(bgp_fsm_error) * * Next state will be Idle, except for Established, when will be Stopping. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_recv_nom) { - bgp_connection_close(connection) ; - - return bgp_fsm_catch_exception(connection, next_state) ; + return bgp_fsm_catch(connection, next_state) ; } ; /*------------------------------------------------------------------------------ @@ -1883,7 +1980,7 @@ static bgp_fsm_action(bgp_fsm_recv_nom) * * Set the "courtesy" HoldTimer. Expect to stay in current state. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_sent_nom) { @@ -1894,7 +1991,7 @@ static bgp_fsm_action(bgp_fsm_sent_nom) /*------------------------------------------------------------------------------ * Seed Keepalive to peer. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_send_kal) { @@ -1908,27 +2005,30 @@ static bgp_fsm_action(bgp_fsm_send_kal) * If there is another connection, that is now snuffed out and this connection * becomes the primary. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_establish) { bgp_session session = connection->session ; - bgp_connection sibling = bgp_fsm_get_sibling(connection) ; + bgp_connection sibling = bgp_connection_get_sibling(connection) ; assert(session != NULL) ; - /* The first thing to do is to snuff off any sibling */ + /* The first thing to do is to snuff out any sibling */ if (sibling != NULL) - bgp_fsm_stop_connection(sibling, bgp_stopped_loser, + bgp_fsm_discard_sibling(sibling, bgp_notify_new(BGP_NOMC_CEASE, BGP_NOMS_C_COLLISION, 0)) ; /* Establish self as primary and copy state up to session */ bgp_connection_make_primary(connection) ; - /* TODO: now would be a good time to withdraw the password from listener ? */ + /* Change the session state and post event */ + assert(session->state == bgp_session_sEnabled) ; - /* Set the session state -- tell the Routeing Engine the news */ - /*>>>>>>> signal event <<<<<*/ + session->state = bgp_session_sEstablished ; + bgp_fsm_post_exception(connection, bgp_session_eEstablished, NULL, 0) ; + + /* TODO: now would be a good time to withdraw the password from listener ? */ return next_state ; } ; @@ -1936,7 +2036,7 @@ static bgp_fsm_action(bgp_fsm_establish) /*------------------------------------------------------------------------------ * Keepalive packet is received -- OpenConfirm/Established * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_recv_kal) { @@ -1950,7 +2050,7 @@ static bgp_fsm_action(bgp_fsm_recv_kal) /*------------------------------------------------------------------------------ * Update packet is received. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_update) { @@ -1958,21 +2058,21 @@ static bgp_fsm_action(bgp_fsm_update) return next_state ; } - - - /*------------------------------------------------------------------------------ * Connection exit * * Ring down the curtain. Connection structure will be freed by the BGP Engine. * - * NB: the session is locked. + * NB: requires the session LOCKED */ static bgp_fsm_action(bgp_fsm_exit) { + assert(connection->state == bgp_fsm_Stopping) ; + bgp_connection_exit(connection) ; - return next_state ; -} + + return bgp_fsm_Stopping ; +} ; /*============================================================================== * Catching FSM Exceptions. @@ -1983,88 +2083,68 @@ static bgp_fsm_action(bgp_fsm_exit) * connection->err ) which define the exception * connection->notification ) * - * The FSM adds the expected next_state. + * An event has been raised, and the FSM has a (default next_state). * - * From all the above... + * 1a) notification & not eNOM_recv * + * Start sending the NOTIFICATION message. * - */ -static bgp_fsm_state_t -bgp_fsm_catch_exception(bgp_connection connection, bgp_fsm_state_t next_state) -{ - -if (connection->stopped == bgp_stopped_not) - return bgp_fsm_invalid(connection, next_state, event) ; - -/* If there is a NOTIFICATION to send, now is the time to do that. + * NB: won't be a notification unless OpenSent/OpenConfirm/Established. * - * NB: can only be notification pending if TCP connection is up (OpenSent, - * OpenConfirm or Established. + * For OpenSent/OpenConfirm, override the next_state to stay where it is + * until NOTIFICATION process completes. * - * If do send N + * Sending NOTIFICATION closes the connection for reading. * - * Otherwise, close the connection. - */ -if (connection->notification_pending) - next_state = bgp_fsm_send_notification(connection, - connection->notification) ; -else - bgp_connection_close(connection) ; - -/* If current state is Established, or if are stopped because of any of: + * 1b) otherwise: close the connection. + * + * 2) if next state is Stopping, and not eDiscard + * + * This means we bring down the session, so discard any sibling. * - * bgp_stopped_admin -- stopped by Routeing Engine - * bgp_stopped_loser -- other connection won race to Established state - * bgp_stopped_invalid -- invalid event or action + * The sibling will send any notification, and proceed immediately to + * Stopping. * - * then we force transition to Stopping state. + * (The sibling will be eDiscard -- so no deadly embrace here.) + * + * The state machine takes care of the rest: + * + * * complete entry to new state (for Stopping will cut connection loose). + * + * * send message to Routeing Engine + * + * NB: requires the session LOCKED */ - -if ( (connection->state == bgp_fsm_Established) - || (connection->stopped == bgp_stopped_admin) - || (connection->stopped == bgp_stopped_loser) - || (connection->stopped == bgp_stopped_invalid) ) - next_state = bgp_fsm_Stopping ; /* force transition */ - -/* Done */ - - - -static void -bgp_fsm_set_exception(bgp_connection connection, bgp_session_event_t except, - bgp_notify notification, int err) ; +static bgp_fsm_state_t +bgp_fsm_catch(bgp_connection connection, bgp_fsm_state_t next_state) { - bgp_session session ; - bgp_connection sibling ; - - /* If not connected to session, then already stopping and can do no more. */ - session = connection->session ; - if (session == NULL) - return ; - - BGP_CONNECTION_SESSION_LOCK(connection) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - - /* Get "sibling" and set stopping same as us, if required. */ - /* Won't be there if one-time sibling is already stopping/stopped. */ - if (both && ((sibling = bgp_fsm_get_sibling(connection)) != NULL)) - bgp_fsm_stop_connection(sibling, cause, bgp_notify_dup(notification)) ; - - /* If have been passed a notification, then that should be sent to */ - /* the other end, and reported with the session stop cause. */ - - connection->notification_pending = (notification != NULL) ; - - if (connection->notification_pending) - bgp_notify_set(&connection->notification, notification) ; + /* If there is a NOTIFICATION to send, now is the time to do that. + * Otherwise, close the connection. + */ + if ( (connection->notification != NULL) + && (connection->except != bgp_session_eNOM_recv) ) + { + next_state = bgp_fsm_send_notification(connection, + connection->notification) ; + } + else + bgp_connection_close(connection) ; - /* Set the session stopping cause and copy the notification there */ + /* If stopping and not eDiscard, do in any sibling */ + if ( (next_state == bgp_fsm_Stopping) + && (connection->except != bgp_session_eDiscard) ) + { + bgp_connection sibling ; - session->stopped = cause ; - bgp_notify_set_dup(&session->notification, connection->notification) ; + sibling = bgp_connection_get_sibling(connection) ; /* ... if any */ - BGP_CONNECTION_SESSION_UNLOCK(connection) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ -} ; + if (sibling != NULL) + bgp_fsm_discard_sibling(sibling, + bgp_notify_dup(connection->notification)) ; + } ; + /* Return the (possibly adjusted) next_state */ + return next_state ; } ; /*============================================================================== @@ -2161,7 +2241,7 @@ static qtimer_action bgp_keepalive_timer_action ; * Set and unset all the connection timers as required by the new state of * the connection -- which may depend on the current state. * - * NB: requires the session to be LOCKED. + * NB: requires the session LOCKED */ static void bgp_fsm_state_change(bgp_connection connection, bgp_fsm_state_t new_state) @@ -2304,7 +2384,7 @@ bgp_fsm_state_change(bgp_connection connection, bgp_fsm_state_t new_state) * * If not sending a NOTIFICATION then stop HoldTimer now. * - * Connections which are Stopping are no longer linked to a session. + * Unlink connection from session. */ case bgp_fsm_Stopping: if (!connection->notification_pending) @@ -2316,6 +2396,8 @@ 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: |