summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_common.h4
-rw-r--r--bgpd/bgp_fsm.c9
-rw-r--r--bgpd/bgp_peer.c75
-rw-r--r--bgpd/bgp_session.c153
-rw-r--r--bgpd/bgp_session.h11
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 ;
} ;
/*==============================================================================