summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_connection.c1
-rw-r--r--bgpd/bgp_fsm.c40
-rw-r--r--bgpd/bgp_msg_read.c8
-rw-r--r--bgpd/bgp_msg_read.h3
-rw-r--r--bgpd/bgp_peer.c19
-rw-r--r--bgpd/bgp_peer_index.c11
-rw-r--r--bgpd/bgp_session.c55
-rw-r--r--bgpd/bgp_session.h37
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(&notification) ;
} ;
/*------------------------------------------------------------------------------
@@ -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(&notification) ; /* 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) ;