diff options
-rw-r--r-- | bgpd/bgp_connection.c | 1 | ||||
-rw-r--r-- | bgpd/bgp_fsm.c | 40 | ||||
-rw-r--r-- | bgpd/bgp_msg_read.c | 8 | ||||
-rw-r--r-- | bgpd/bgp_msg_read.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_peer.c | 19 | ||||
-rw-r--r-- | bgpd/bgp_peer_index.c | 11 | ||||
-rw-r--r-- | bgpd/bgp_session.c | 55 | ||||
-rw-r--r-- | bgpd/bgp_session.h | 37 |
8 files changed, 90 insertions, 84 deletions
diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c index 9ce0df67..10a6e21f 100644 --- a/bgpd/bgp_connection.c +++ b/bgpd/bgp_connection.c @@ -28,6 +28,7 @@ #include "bgpd/bgp_session.h" #include "bgpd/bgp_connection.h" #include "bgpd/bgp_notification.h" +#include "bgpd/bgp_msg_read.h" #include "lib/memory.h" #include "lib/mqueue.h" diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index ccc16a7c..8db13c3e 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -394,11 +394,7 @@ bgp_fsm_enable_session(bgp_session session) /* 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) ; - + bgp_session_event(session, bgp_session_eInvalid, NULL, 0, 0, 1) ; return ; } ; @@ -465,6 +461,11 @@ bgp_fsm_catch(bgp_connection connection, bgp_fsm_state_t next_state) ; /*------------------------------------------------------------------------------ * Ultimate exception -- disable the session * + * Does nothing if neither connection exists (which implies the session has + * already been disabled, or never got off the ground). + * + * NB: takes responsibility for the notification structure. + * * NB: requires the session LOCKED */ extern void @@ -475,11 +476,12 @@ bgp_fsm_disable_session(bgp_session session, bgp_notify notification) 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, + if (connection != NULL) + bgp_fsm_throw_exception(connection, bgp_session_eDisabled, notification, 0, bgp_fsm_BGP_Stop) ; + else + bgp_notify_free(¬ification) ; } ; /*------------------------------------------------------------------------------ @@ -637,6 +639,8 @@ bgp_fsm_connect_completed(bgp_connection connection, int err, * * Forget the notification if not OpenSent/OpenConfirm/Established. Cannot * send notification in any other state -- nor receive one. + * + * NB: takes responsibility for the notification structure. */ static void bgp_fsm_post_exception(bgp_connection connection, bgp_session_event_t except, @@ -656,6 +660,8 @@ bgp_fsm_post_exception(bgp_connection connection, bgp_session_event_t except, /*------------------------------------------------------------------------------ * Post the given exception and raise the given event. + * + * NB: takes responsibility for the notification structure. */ static void bgp_fsm_throw_exception(bgp_connection connection, bgp_session_event_t except, @@ -1596,22 +1602,18 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event) if ((connection->except != bgp_session_null_event) && (session != NULL)) { - /* Some exceptions are no reported to the Routeing Engine */ + /* Some exceptions are not 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 */ + bgp_session_event(session, connection->except, + connection->notification, + connection->err, + connection->ordinal, + (connection->state == bgp_fsm_Stopping)) ; /* Tidy up -- notification already cleared */ connection->except = bgp_session_null_event ; connection->err = 0 ; + bgp_notify_free(&connection->notification) ; /* if any */ } if (session != NULL) diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c index 98b21d23..4c94c999 100644 --- a/bgpd/bgp_msg_read.c +++ b/bgpd/bgp_msg_read.c @@ -64,6 +64,14 @@ static void bgp_msg_notify_send_with_data (bgp_connection connection, bgp_session_event_t except, bgp_nom_code_t code, bgp_nom_subcode_t sub_code, u_char *data, size_t datalen); + +/* Get BGP message length, given a pointer to the start of a message */ +extern bgp_size_t +bgp_msg_get_mlen(uint8_t* p) +{ + return (*(p + BGP_MARKER_SIZE)) + (*(p + BGP_MARKER_SIZE + 1) << 8) ; +} ; + /* read and validate header. * return >= 0 number of bytes still to read * return -1 error diff --git a/bgpd/bgp_msg_read.h b/bgpd/bgp_msg_read.h index cc1272e8..f846453f 100644 --- a/bgpd/bgp_msg_read.h +++ b/bgpd/bgp_msg_read.h @@ -25,6 +25,9 @@ #include "bgpd/bgp_common.h" +extern bgp_size_t +bgp_msg_get_mlen(uint8_t* p) ; + extern int bgp_msg_check_header(bgp_connection connection); diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c index d154fa26..f2728438 100644 --- a/bgpd/bgp_peer.c +++ b/bgpd/bgp_peer.c @@ -99,16 +99,10 @@ bgp_graceful_stale_timer_expire (struct thread *thread); /*============================================================================== * Deal with change in session state -- mqueue_action function. * - * Receives notifications from the BGP Engine when a BGP Session state changes, - * which may be: - * - * Enabled -> Established -- connection up and Opens exchanged - * Enabled -> Stopped -- stopped trying to connect (for some reason) - * Established -> Stopped -- for some reason + * Receives notifications from the BGP Engine a session event occurs. * * -- arg0 = session * args = bgp_session_event_args - * */ void bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag) @@ -127,15 +121,18 @@ 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: - if (args->state == bgp_session_sEstablished) - bgp_session_has_established(peer); + session->state = bgp_session_sEstablished ; + bgp_session_has_established(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. */ - if (args->state == bgp_session_sStopped) - bgp_session_has_stopped(peer); + if (args->stopped) + { + session->state = bgp_session_sStopped ; + bgp_session_has_stopped(peer); + } ; break ; } diff --git a/bgpd/bgp_peer_index.c b/bgpd/bgp_peer_index.c index bad95d95..6bcb3be2 100644 --- a/bgpd/bgp_peer_index.c +++ b/bgpd/bgp_peer_index.c @@ -223,7 +223,9 @@ bgp_peer_index_seek_entry(union sockunion* su) } ; /*------------------------------------------------------------------------------ - * Lookup a session -- do nothing if does not exist + * Lookup a peer by its address. + * + * Return a pointer to its session iff it is prepared to accept() a connection. * * For use by the BGP Engine. * @@ -234,9 +236,8 @@ bgp_peer_index_seek_entry(union sockunion* su) * * Sets *p_found <=> a peer with the given address is configured. * - * NB: the BGP Engine may not access the bgp_session structure if it is not - * active (sEnabled or sEstablished), so the accept pointer in the peer - * index entry will be NULL under those conditions. + * NB: the BGP Engine sets/clears the pointer to the session. The pointer is + * initialised NULL when the index entry is created. */ extern bgp_session bgp_session_index_seek(union sockunion* su, int* p_found) @@ -253,8 +254,6 @@ bgp_session_index_seek(union sockunion* su, int* p_found) BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - assert((accept == NULL) || (bgp_session_is_active(accept))) ; - return accept ; } ; diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c index 25615f99..fdba5fd7 100644 --- a/bgpd/bgp_session.c +++ b/bgpd/bgp_session.c @@ -41,10 +41,7 @@ bgp_session_defer_if_stopping(bgp_session session); * A session is shared by the Routeing Engine and the BGP Engine -- so there * is a mutex to coordinate access. * - * NB: to avoid deadlock, do NOT attempt to lookup a peer or session while - * a session mutex ! - * - * A session is created when the bgp peer is first enabled, and may be destroyed + * 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. * * A session may be in one of four states: @@ -52,21 +49,22 @@ bgp_session_defer_if_stopping(bgp_session session); * * 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 * * NB: in Idle and Stopped states the BGP Engine has no interest in the session. * These are known as the "inactive" states. * - * NB: in Enabled and Established states the Routeing Engine it may be too late - * to change items in the session ! These are known as the "active" states. + * NB: in Enabled, Established and Stopping states the BGP Engine is running + * connection(s) for the session. These are known as the "active" states. * - * NB: once a session is enabled the BGP_Engine looks after the state, up to - * and including setting the Stopped state. + * 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 ! * * The BGP Engine's primary interest is in its (private) bgp_connection - * structure(s), which (while a session is Enabled or Established) are pointed - * to by their associated session. - * + * structure(s), which (while a session is Enabled, Established or Stopping) + * are pointed to by their associated session. */ /*============================================================================== @@ -313,15 +311,19 @@ bgp_session_disable(bgp_peer peer, bgp_notify notification) session = peer->session ; assert((session != NULL) && (session->peer == peer)) ; - /* Should do nothing if session is not active. */ + /* Do nothing if session is not active, or is already stopping. */ - if (!bgp_session_is_active(session)) + if ( (session->state != bgp_session_sEnabled) && + (session->state != bgp_session_sEstablished) ) ; { bgp_notify_free(¬ification) ; /* discard any bgp_notify */ return ; } ; - /* Now ask the BGP engine to disable the session. + /* Now change to stopping state */ + session->state = bgp_session_sStopping; + + /* 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. @@ -354,10 +356,8 @@ bgp_session_do_disable(mqueue_block mqb, mqb_flag_t flag) bgp_session session = mqb_get_arg0(mqb) ; struct bgp_session_disable_args* args = mqb_get_args(mqb) ; - session->state = bgp_session_sStopping; /* TODO: disable session */ - - bgp_notify_free(&args->notification) ; /* discard any bgp_notify */ + bgp_fsm_disable_session(session, args->notification) ; } ; mqb_free(mqb) ; @@ -365,12 +365,13 @@ bgp_session_do_disable(mqueue_block mqb, mqb_flag_t flag) /*============================================================================== * Send session event signal from BGP Engine to Routeing Engine - * - * The event has been posted to the session, and now is dispatched to the - * Routeing Engine. */ extern void -bgp_session_event(bgp_session session) +bgp_session_event(bgp_session session, bgp_session_event_t event, + bgp_notify notification, + int err, + bgp_connection_ord_t ordinal, + int stopped) { struct bgp_session_event_args* args ; mqueue_block mqb ; @@ -379,10 +380,11 @@ bgp_session_event(bgp_session session) args = mqb_get_args(mqb) ; - args->event = session->event ; - args->notification = bgp_notify_dup(session->notification) ; - args->state = session->state ; - args->ordinal = session->ordinal ; + args->event = event ; + args->notification = bgp_notify_dup(notification) ; + args->err = err ; + args->ordinal = ordinal ; + args->stopped = stopped, bgp_to_peering_engine(mqb) ; } @@ -468,7 +470,8 @@ bgp_session_is_active(bgp_session session) else { active = ( (session->state == bgp_session_sEnabled) - || (session->state == bgp_session_sEstablished) ) ; + || (session->state == bgp_session_sEstablished) + || (session->state == bgp_session_sStopping) ) ; if (!active) assert(session->index_entry->accept == NULL) ; diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h index 193e1936..b54c1be4 100644 --- a/bgpd/bgp_session.h +++ b/bgpd/bgp_session.h @@ -82,28 +82,18 @@ struct bgp_session * The BGP Engine will not touch a session in these states and the * Peering Engine may do what it likes with it. * - * The Peering Engine may change the state: - * - * sIdle -> sEnabled - * sStopped -> sEnabled - * sStopped -> sIdle - * - * While sEnabled and sEstablished: + * While sEnabled, sEstablished and sStopping: * * the session belongs to the BGP Engine. * * A (very) few items in the session may be accessed by the Peering Engine, * as noted below. (Subject to the mutex.) * - * The BGP Engine may change the state: - * - * sEnabled -> sEstablished - * sEnabled -> sStopped - * sEstablished -> sStopped - * * Only the Peering Engine creates and destroys sessions. The BGP Engine - * assumes that a session will not be destroyed while it is sEnabled or - * sEstablished. + * assumes that a session will not be destroyed while it is sEnabled, + * sEstablished or sStopping. + * + * Only the Peering Engine touches the state and defer_enable items. * * The made flag is cleared by the Peering Engine before enabling a session, * and is set by the BGP Engine when the session becomes sEstablished. @@ -112,12 +102,12 @@ struct bgp_session * session was ever established. */ bgp_session_state_t state ; + int defer_enable ; /* set when waiting for stop */ + flag_t made ; /* set when -> sEstablished */ - int defer_enable ; /* set when waiting for stop */ - /* The BGP Engine records the last event, NOTIFICATION and errno here. - * - * This is only really useful when the session -> sStopped. + /* These belong to the Peering Engine, and may be set when a session + * event message is received from the BGP Engine. */ bgp_session_event_t event ; /* last event */ bgp_notify notification ; /* if any sent/received */ @@ -220,8 +210,7 @@ struct bgp_session_event_args /* to Routeing Engine */ bgp_notify notification ; /* sent or received (if any) */ int err ; /* errno if any */ bgp_connection_ord_t ordinal ; /* primary/secondary connection */ - - bgp_session_state_t state ; /* after the event */ + int stopped ; /* session has stopped */ } ; MQB_ARGS_SIZE_OK(bgp_session_enable_args) ; @@ -256,7 +245,11 @@ extern void bgp_session_disable(bgp_peer peer, bgp_notify notification) ; extern void -bgp_session_event(bgp_session session) ; +bgp_session_event(bgp_session session, bgp_session_event_t event, + bgp_notify notification, + int err, + bgp_connection_ord_t ordinal, + int stopped) ; extern void bgp_session_update_send(bgp_session session, struct stream* upd) ; |