summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Hall <GMCH@hestia.halldom.com>2010-01-08 00:51:19 +0000
committerChris Hall <GMCH@hestia.halldom.com>2010-01-08 00:51:19 +0000
commit6b5024b3c14b0acf5d4ec05f7ea78a7323c96d59 (patch)
tree89956e840ea5de81b5b564732032d93b95638af0
parent18874dc91124118a678984241b18953beb8bb9d9 (diff)
downloadquagga-6b5024b3c14b0acf5d4ec05f7ea78a7323c96d59.tar.bz2
quagga-6b5024b3c14b0acf5d4ec05f7ea78a7323c96d59.tar.xz
Continuing work-in-progress
modified: bgpd/Makefile.am modified: bgpd/bgp.h modified: bgpd/bgp_common.h modified: bgpd/bgp_connection.c modified: bgpd/bgp_connection.h modified: bgpd/bgp_engine.h modified: bgpd/bgp_fsm.c modified: bgpd/bgp_network.c modified: bgpd/bgp_network.h new file: bgpd/bgp_peer_index.c new file: bgpd/bgp_peer_index.h modified: bgpd/bgp_session.c modified: bgpd/bgp_session.h modified: lib/memtypes.c modified: lib/mqueue.h
-rw-r--r--bgpd/Makefile.am4
-rw-r--r--bgpd/bgp.h2
-rw-r--r--bgpd/bgp_common.h62
-rw-r--r--bgpd/bgp_connection.c31
-rw-r--r--bgpd/bgp_connection.h12
-rw-r--r--bgpd/bgp_engine.h19
-rw-r--r--bgpd/bgp_fsm.c353
-rw-r--r--bgpd/bgp_network.c78
-rw-r--r--bgpd/bgp_network.h7
-rw-r--r--bgpd/bgp_peer_index.c329
-rw-r--r--bgpd/bgp_peer_index.h89
-rw-r--r--bgpd/bgp_session.c298
-rw-r--r--bgpd/bgp_session.h172
-rw-r--r--lib/memtypes.c1
-rw-r--r--lib/mqueue.h2
15 files changed, 1191 insertions, 268 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index f1968c9c..f903c7ba 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -17,7 +17,7 @@ libbgp_a_SOURCES = \
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
bgp_peer.c bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c \
bgp_engine.c bgp_session.c bgp_connection.c \
- bgp_common.c bgp_notification.c
+ bgp_common.c bgp_notification.c bgp_peer_index.c
noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
@@ -26,7 +26,7 @@ noinst_HEADERS = \
bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_peer.h bgp_advertise.h bgp_snmp.h bgp_vty.h \
bgp_engine.h bgp_session.h bgp_connection.h \
- bgp_common.h bgp_notification.h bgp.h
+ bgp_common.h bgp_notification.h bgp_peer_index.h bgp.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp.h b/bgpd/bgp.h
index 7f0447bc..79415cd4 100644
--- a/bgpd/bgp.h
+++ b/bgpd/bgp.h
@@ -91,7 +91,7 @@
* RFC4264 BGP Wedgies
* RFC4098 Terminology for Benchmarking BGP Device Convergence in the
* Control Plane
- * RFC3822 Configuring BGP to BLock Denial-of-Service Attack
+ * RFC3822 Configuring BGP to Block Denial-of-Service Attack
* RFC3765 NOPEER Community
* RFC3392 ...see RFC5492 -- obsoletes RFC2842
* RFC3345 BGP Persistent Route Oscillation Condition
diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h
index b3b58cac..15fc026a 100644
--- a/bgpd/bgp_common.h
+++ b/bgpd/bgp_common.h
@@ -48,8 +48,9 @@ typedef struct bgp_connection* bgp_connection ;
typedef struct bgp_open_state* bgp_open_state ;
/*==============================================================================
- * Both session and connection require this.
+ * Both session and connection require these
*/
+
typedef enum bgp_connection_ordinal bgp_connection_ordinal_t ;
enum bgp_connection_ordinal
{
@@ -59,31 +60,54 @@ enum bgp_connection_ordinal
bgp_connection_count = 2
} ;
-/*==============================================================================
- * Both session and connection require this.
- */
-typedef enum bgp_stopped_causes bgp_stopped_cause_t ;
-enum bgp_stopped_causes
+typedef enum bgp_session_states bgp_session_state_t ;
+enum bgp_session_states
+{
+ bgp_session_min_state = 0,
+
+ bgp_session_sIdle = 0, /* session contents "unset" */
+
+ bgp_session_sEnabled = 1, /* attempting to connect */
+ bgp_session_sEstablished = 2,
+
+ bgp_session_sStopped = 3, /* for whatever reason */
+
+ bgp_session_max_state = 3
+} ;
+
+typedef enum bgp_session_events bgp_session_event_t ;
+enum bgp_session_events
{
- bgp_stopped_min_cause = 0,
+ bgp_session_min_event = 0,
+ bgp_session_null_event = 0,
+
+ bgp_session_eEnabled, /* enabled by Peering Engine */
+
+ bgp_session_eStart, /* coming out of fsm_Idle */
+ bgp_session_eRetry, /* loop round in Connect/Accept */
+
+ bgp_session_eTCP_connect, /* successful Connect/Accept */
+
+ bgp_session_eCollision, /* connection closed to resolve collision */
- bgp_stopped_not = 0, /* not stopped (yet) */
+ bgp_session_eOpen_accept, /* accepted an OPEN message */
+ bgp_session_eOpen_reject, /* had to reject an OPEN message */
+ bgp_session_eEstablished, /* session state -> sEstablished */
- bgp_stopped_admin = 1, /* Routeing Engine Stop */
- /* Sent Cease NOTIFICATION */
+ bgp_session_eInvalid_msg, /* BGP message invalid */
+ bgp_session_eFSM_error, /* unexpected BGP message received */
+ bgp_session_eNOM_recv, /* NOTIFICATION message received */
- bgp_stopped_collision = 2, /* Collision Resolution Stop */
- bgp_stopped_loser = 3, /* Loser in race to Established state */
+ bgp_session_eTCP_failed, /* TCP connection failed to come up */
+ bgp_session_eTCP_dropped, /* TCP connection dropped */
+ bgp_session_eTCP_error, /* some socket level error */
- bgp_stopped_error = 4, /* */
- bgp_stopped_recv_nom = 5, /* Received NOTIFICATION */
+ bgp_session_eExpired, /* HoldTime expired */
- bgp_stopped_connect_fail = 5,
- bgo_stopped_connect_drop = 6,
- bgp_stopped_fatal_error = 8,
- bgp_stopped_invalid = 9, /* some internal error */
+ bgp_session_eInvalid, /* invalid internal event */
+ bgp_session_eDisabled, /* disabled by Peering Engine */
- bgp_stopped_max_cause = 8
+ bgp_session_max_event = bgp_session_eDisabled
} ;
/*==============================================================================
diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c
index 8517ccc0..445d6d18 100644
--- a/bgpd/bgp_connection.c
+++ b/bgpd/bgp_connection.c
@@ -441,7 +441,7 @@ bgp_connection_open(bgp_connection connection, int fd)
/* If this is the secondary connection, do not accept any more. */
if (connection->ordinal == bgp_connection_secondary)
- session->accept = 0 ;
+ bgp_connection_disable_accept(connection) ;
/* Set the file going */
qps_add_file(p_bgp_engine->selection, &connection->qf, fd, connection) ;
@@ -465,6 +465,26 @@ bgp_connection_open(bgp_connection connection, int fd)
} ;
/*------------------------------------------------------------------------------
+ * Enable connection for accept()
+ *
+ */
+extern void
+bgp_connection_enable_accept(bgp_connection connection)
+{
+ connection->session->index_entry->accept = connection->session ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Disable connection for accept()
+ *
+ */
+extern void
+bgp_connection_disable_accept(bgp_connection connection)
+{
+ connection->session->index_entry->accept = NULL ;
+} ;
+
+/*------------------------------------------------------------------------------
* Close connection.
*
* * if there is an fd, close it
@@ -473,6 +493,7 @@ bgp_connection_open(bgp_connection connection, int fd)
* * unset any timers
* * reset all buffering to empty
* * empties the pending queue -- destroying all messages
+ * * for secondary connection: disable accept
*
* The following remain:
*
@@ -505,9 +526,13 @@ bgp_connection_close(bgp_connection connection)
if (fd != fd_undef)
shutdown(fd, SHUT_RDWR) ;
+ /* If this is the secondary connection, do not accept any more. */
+ if (connection->ordinal == bgp_connection_secondary)
+ bgp_connection_disable_accept(connection) ;
+
/* forget any addresses */
- sockunion_clear(&connection->su_local) ;
- sockunion_clear(&connection->su_remote) ;
+ sockunion_clear(connection->su_local) ;
+ sockunion_clear(connection->su_remote) ;
/* Unset all the timers */
qtimer_unset(&connection->hold_timer) ;
diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h
index d293f1e3..5e1ce349 100644
--- a/bgpd/bgp_connection.h
+++ b/bgpd/bgp_connection.h
@@ -131,13 +131,13 @@ struct bgp_connection
int fsm_active ; /* active in fsm count */
bgp_fsm_event_t post ; /* event raised within FSM */
- bgp_stopped_cause_t stopped ; /* why stopped */
- bgp_notify notification ; /* if any sent/received */
+ bgp_session_event_t except ; /* exception */
+ bgp_notify notification ; /* if any sent/received */
+ int err ; /* erno, if any */
bgp_open_state open_recv ; /* the open received. */
struct qps_file qf ; /* qpselect file structure */
- int err ; /* error number -- if any */
union sockunion* su_local ; /* address of the near end */
union sockunion* su_remote ; /* address of the far end */
@@ -179,6 +179,12 @@ bgp_connection_reset(bgp_connection connection, int free_structure) ;
extern void
bgp_connection_open(bgp_connection connection, int fd) ;
+extern void
+bgp_connection_enable_accept(bgp_connection connection) ;
+
+extern void
+bgp_connection_disable_accept(bgp_connection connection) ;
+
extern bgp_connection
bgp_connection_get_sibling(bgp_connection connection) ;
diff --git a/bgpd/bgp_engine.h b/bgpd/bgp_engine.h
index 9245d21a..57780dc5 100644
--- a/bgpd/bgp_engine.h
+++ b/bgpd/bgp_engine.h
@@ -46,5 +46,24 @@ bgp_engine_start(void) ;
+/*==============================================================================
+ *
+ */
+
+/* Send given message to the BGP Engine -- ordinary
+ */
+Inline void
+bgp_to_engine(mqueue_block mqb)
+{
+ mqueue_enqueue(p_bgp_engine->queue, mqb, 0) ;
+} ;
+
+/* Send given message to the BGP Engine -- priority
+ */
+Inline void
+bgp_to_engine_priority(mqueue_block mqb)
+{
+ mqueue_enqueue(p_bgp_engine->queue, mqb, 1) ;
+} ;
#endif /* QUAGGA_BGP_ENGINE_H */
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index f2b89576..bd2ef82a 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -158,10 +158,7 @@
* OPEN messages from a given remote end IP address MUST MATCH !
*
*------------------------------------------------------------------------------
- * Error Handling, NOTIFICATIONs and Collision Resolution.
- *
- * I/O and other operations may fail. The other end may close an open TCP
- * connection, with or without a NOTIFICATION message.
+ * Exception Handling.
*
* The FSM proceeds in three basic phases:
*
@@ -214,9 +211,9 @@
* 2) attempting to establish a BGP session: OpenSent/OpenConfirm
*
* If something goes wrong, or the other end closes the connection (with
- * or without notification) it will loop back to Idle state. Also, when
- * collision resolution closes one connection it too loops back to Idle
- * (see above).
+ * or without notification) the FSM will loop back to Idle state. Also,
+ * when collision resolution closes one connection it too loops back to
+ * Idle (see above).
*
* Both connections may reach OpenSent. Only one at once can reach
* OpenConfirm -- collision resolution sees to that.
@@ -231,10 +228,13 @@
*
* When things do go wrong, one of the following events is generated:
*
- * a. BGP_Stop
+ * a. BGP_Stop -- general exception
+ *
+ * The function bgp_fsm_exception() sets the reason for the exception and
+ * raises an BGP_Stop event.
*
- * The functions bgp_fsm_stop_connection() and bgp_fsm_stop_session()
- * set the cause of stop and generate a BGP_Stop event for one or both
+ * Within the FSM, bgp_fsm_set_exception() sets the reason for the
+ * exception and .....
* connections. These may be used, for example, to signal that an UPDATE
* message is invalid.
*
@@ -278,14 +278,16 @@
*
* The function bgp_fsm_io_fatal_error() will generate a TCP_fatal_error.
*
- * e.
+ * Things may also go wrong withing the FSM.
+ *
+ * The procedure for dealing with an exception
*
*------------------------------------------------------------------------------
* FSM errors
*
- * If the FSM receives an event that cannot be raised in the current state,
- * it will terminate the session, sending an FSM Error NOTIFICATION (if a
- * TCP connection is up). See bgp_fsm_invalid().
+ * Invalid events: if the FSM receives an event that cannot be raised in the
+ * current state, it will terminate the session, sending an FSM Error
+ * NOTIFICATION (if a TCP connection is up). See bgp_fsm_invalid().
*
* If the FSM receives a message type that is not expected in the current,
* state, it will close the connection (if OpenSent or OpenConfirm) or stop
@@ -345,6 +347,39 @@
*
* When the HoldTimer expires close the connection completely (whether or not
* the NOTIFICATION has cleared the write buffer).
+ *
+ *------------------------------------------------------------------------------
+ * Communication with the Routeing Engine
+ *
+ * The FSM sends the following messages to the Routeing Engine:
+ *
+ * * bgp_session_event messages
+ *
+ * These keep the Routeing Engine up to date with the progress and state of
+ * the FSM.
+ *
+ * In particular, these event messages tell the Routeing Engine when the
+ * session enters and leaves sEstablished -- which is what really matters
+ * to it !
+ *
+ * * bgp_session_update
+ *
+ * Each time an update message arrives from the peer, it is forwarded.
+ *
+ * TODO: flow control for incoming updates ??
+ *
+ * Three things bring the FSM to a dead stop, and stop the session:
+ *
+ * 1) administrative Stop -- ie the Routeing Engine disabling the session.
+ *
+ * 2) invalid events -- which are assumed to be bugs, really.
+ *
+ * 3) anything that stops the session while in Established state.
+ *
+ * This means that the FSM will plough on trying to establish connections with
+ * configured peers, even in circumstances when the likelihood of success
+ * appears slim to vanishing. However, the Routeing Engine and the operator
+ * are responsible for the decision to start and to stop trying to connect.
*/
/*==============================================================================
@@ -360,10 +395,8 @@ bgp_fsm_enable_connection(bgp_connection connection)
bgp_fsm_event(connection, bgp_fsm_BGP_Start) ;
} ;
-
-
/*=============================================================================
- * BGP_Stop Events
+ * Raising exceptions.
*
* Before generating a BGP_Stop event the cause of the stop MUST be set for
* the connection.
@@ -390,26 +423,11 @@ bgp_fsm_enable_connection(bgp_connection connection)
*/
static void
-bgp_fsm_set_stopping(bgp_connection connection, bgp_stopped_cause_t cause,
- bgp_notify notification, int both) ;
+bgp_fsm_throw_exception(bgp_connection connection, bgp_session_event_t except,
+ bgp_notify notification, int err, bgp_fsm_event_t event) ;
/*------------------------------------------------------------------------------
- * Bring given connection to a stop.
- *
- * If is the only connection for the session, then the session is stopped.
- *
- * Is given the reasons for the stop. This function looks after releasing the
- * notification once it is finished with it.
- *
- * Records the reasons for the stop, and then generates a BGP_Stop event.
- *
- * This may be used to stop:
- *
- * * as requested by Routeing Engine. The notification, if any, should be a
- * Cease.
- *
- * * because a problem with a BGP packet has arisen. The notification, if
- * any, will describe the problem.
+ * Raise a general exception -- not I/O related.
*
* Note that I/O problems are signalled by bgp_fsm_io_error().
*
@@ -418,49 +436,43 @@ bgp_fsm_set_stopping(bgp_connection connection, bgp_stopped_cause_t cause,
* NB: locks and unlocks the session.
*/
extern void
-bgp_fsm_stop_connection(bgp_connection connection, bgp_stopped_cause_t cause,
+bgp_fsm_raise_exception(bgp_connection connection, bgp_session_event_t except,
bgp_notify notification)
{
- bgp_fsm_set_stopping(connection, cause, notification, 0) ;
- bgp_fsm_event(connection, bgp_fsm_BGP_Stop) ;
+ bgp_fsm_throw_exception(connection, except, notification, 0,
+ bgp_fsm_BGP_Stop) ;
} ;
/*------------------------------------------------------------------------------
- * Bring given connection to a stop, and the other connection (if any), and
- * then the session.
+ * Raise a NOTIFICATION received exception
*
- * See bgp_fsm_stop_connection, above.
+ * NB: locks and unlocks the session.
*/
extern void
-bgp_fsm_stop_session(bgp_connection connection, bgp_stopped_cause_t cause,
+bgp_fsm_notification_exception(bgp_connection connection,
bgp_notify notification)
{
- bgp_fsm_set_stopping(connection, cause, notification, 1) ;
- bgp_fsm_event(connection, bgp_fsm_BGP_Stop) ;
+ bgp_fsm_throw_exception(connection, bgp_session_eNOM_recv, notification, 0,
+ bgp_fsm_Receive_NOTIFICATION_message) ;
} ;
-/*==============================================================================
- * Functions to signal I/O error(s) and connect()/accept() completion.
- */
-
/*------------------------------------------------------------------------------
- * Signal a fatal I/O error on the given connection.
+ * Raise a "fatal I/O error" exception on the given connection.
*
* Error to be reported as "TCP_fatal_error".
*/
extern void
bgp_fsm_io_fatal_error(bgp_connection connection, int err)
{
- connection->err = err ;
-
plog_err (connection->log, "%s [Error] bgp IO error: %s",
connection->host, safe_strerror(err)) ;
- bgp_fsm_event(connection, bgp_fsm_TCP_fatal_error) ;
+ bgp_fsm_throw_exception(connection, bgp_session_eTCP_error, NULL, err,
+ bgp_fsm_TCP_fatal_error) ;
} ;
/*------------------------------------------------------------------------------
- * Signal an I/O error on the given connection.
+ * Raise an "I/O error" exception on the given connection.
*
* This is used by read/write operations -- so not until the TCP connection
* is up (which implies OpenSent state or later).
@@ -479,8 +491,6 @@ bgp_fsm_io_fatal_error(bgp_connection connection, int err)
extern void
bgp_fsm_io_error(bgp_connection connection, int err)
{
- connection->err = err ;
-
if ( (err == 0)
|| (err == ECONNRESET)
|| (err == ENETDOWN)
@@ -501,7 +511,8 @@ bgp_fsm_io_error(bgp_connection connection, int err)
safe_strerror(err)) ;
} ;
- bgp_fsm_event(connection, bgp_fsm_TCP_connection_closed) ;
+ bgp_fsm_throw_exception(connection, bgp_session_eTCP_dropped, NULL, err,
+ bgp_fsm_TCP_connection_closed) ;
}
else
bgp_fsm_io_fatal_error(connection, err) ;
@@ -530,8 +541,6 @@ bgp_fsm_connect_completed(bgp_connection connection, int err,
union sockunion* su_local,
union sockunion* su_remote)
{
- connection->err = err ;
-
if (err == 0)
{
bgp_fsm_event(connection, bgp_fsm_TCP_connection_open) ;
@@ -543,11 +552,35 @@ bgp_fsm_connect_completed(bgp_connection connection, int err,
|| (err == ECONNRESET)
|| (err == EHOSTUNREACH)
|| (err == ETIMEDOUT) )
- bgp_fsm_event(connection, bgp_fsm_TCP_connection_open_failed) ;
+ bgp_fsm_throw_exception(connection, bgp_session_eTCP_failed, NULL, err,
+ bgp_fsm_TCP_connection_open_failed) ;
else
bgp_fsm_io_fatal_error(connection, err) ;
} ;
+/*------------------------------------------------------------------------------
+ * Post the given exception.
+ */
+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 ;
+ connection->err = err ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Post the given exception and raise the given event.
+ */
+static void
+bgp_fsm_throw_exception(bgp_connection connection, bgp_session_event_t except,
+ bgp_notify notification, int err, bgp_fsm_event_t event)
+{
+ bgp_fsm_post_exception(connection, except,notification, err) ;
+ bgp_fsm_event(connection, event) ;
+} ;
+
/*==============================================================================
* For debug...
*/
@@ -565,7 +598,8 @@ bgp_fsm_connect_completed(bgp_connection connection, int err,
typedef bgp_fsm_action(bgp_fsm_action_func) ;
-struct bgp_fsm {
+struct bgp_fsm
+{
bgp_fsm_action_func* action ;
bgp_fsm_state_t next_state ;
} ;
@@ -1413,7 +1447,16 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event)
session = connection->session ;
if (session != NULL)
- BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+ {
+ 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) ;
+ } ;
+ } ;
do
{
@@ -1459,6 +1502,11 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event)
} while (--connection->fsm_active != 0) ;
+ if (session->event != bgp_session_null_event)
+ {
+
+ }
+
if (session != NULL)
BGP_SESSION_UNLOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
} ;
@@ -1479,6 +1527,9 @@ 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.
*/
@@ -1497,6 +1548,11 @@ static bgp_fsm_action(bgp_fsm_null)
*/
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 ;
} ;
@@ -1520,41 +1576,6 @@ static bgp_fsm_action(bgp_fsm_enter)
*/
static bgp_fsm_action(bgp_fsm_stop)
{
- 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: can only be notification pending if TCP connection is up (OpenSent,
- * OpenConfirm or Established.
- *
- * If do send N
- *
- * 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:
- *
- * bgp_stopped_admin -- stopped by Routeing Engine
- * bgp_stopped_loser -- other connection won race to Established state
- * bgp_stopped_invalid -- invalid event or action
- *
- * then we force transition to Stopping state.
- */
-
- 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 */
-
return next_state ;
} ;
@@ -1573,10 +1594,10 @@ 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_set_stopping(connection, bgp_stopped_invalid,
- bgp_notify_new(BGP_NOMC_FSM, BGP_NOMS_UNSPECIFIC, 0), 1) ;
+ bgp_fsm_post_exception(connection, bgp_session_eInvalid,
+ bgp_notify_new(BGP_NOMC_FSM, BGP_NOMS_UNSPECIFIC, 0), 0) ;
- return bgp_fsm_Stopping ; /* unconditionally */
+ return bgp_fsm_catch_exception(connection, next_state) ;
} ;
/*------------------------------------------------------------------------------
@@ -1610,9 +1631,11 @@ static bgp_fsm_action(bgp_fsm_start)
else
{
next_state = bgp_fsm_Active ;
- connection->session->accept = 1 ;
+ bgp_connection_enable_accept(connection) ;
} ;
+ bgp_fsm_post_session_event(connection, bgp_session_eStart, NULL, 0) ;
+
return next_state ;
} ;
@@ -1644,15 +1667,18 @@ static bgp_fsm_action(bgp_fsm_send_open)
bgp_msg_send_open(connection, connection->session->open_send) ;
+ bgp_fsm_post_session_event(connection, bgp_session_eTCP_connect, NULL, 0) ;
+
return next_state ;
} ;
/*------------------------------------------------------------------------------
* TCP connection has failed to come up -- Connect/Active states.
*
- * Close the connection (doesn't do much if secondary connection).
+ * This is in response to TCP_connection_open_failed, which has posted the
+ * exception -- so now need to deal with it.
*
- * If secondary connection, disable accept.
+ * Close the connection -- if secondary connection, disable accept.
*
* Will stay in Connect/Active states.
*
@@ -1662,20 +1688,16 @@ static bgp_fsm_action(bgp_fsm_failed)
{
bgp_connection_close(connection) ;
- if (connection->ordinal == bgp_connection_secondary)
- connection->session->accept = 0 ;
-
- return next_state ;
+ return bgp_fsm_catch_exception(connection, next_state) ;
} ;
/*------------------------------------------------------------------------------
* Fatal I/O error -- any state (other than Idle and Stopping).
*
- * Close the connection (if any).
+ * Close the connection (if any) -- if secondary connection, disable accept.
*
- * If secondary connection, disable accept.
- *
- * If about to stop: set bgp_stopped_fatal_error
+ * 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.
*/
@@ -1683,13 +1705,7 @@ static bgp_fsm_action(bgp_fsm_fatal)
{
bgp_connection_close(connection) ;
- if (connection->ordinal == bgp_connection_secondary)
- connection->session->accept = 0 ;
-
- if (next_state == bgp_fsm_Stopping)
- connection->stopped = bgp_stopped_fatal_error ;
-
- return next_state ;
+ return bgp_fsm_catch_exception(connection, next_state) ;
} ;
/*------------------------------------------------------------------------------
@@ -1710,8 +1726,7 @@ static bgp_fsm_action(bgp_fsm_retry)
{
bgp_connection_close(connection) ;
- if (connection->ordinal == bgp_connection_secondary)
- connection->session->accept = 0 ;
+ bgp_fsm_post_session_event(connection, bgp_session_eRetry, NULL, 0) ;
return bgp_fsm_start(connection, next_state, event) ;
} ;
@@ -1719,7 +1734,8 @@ static bgp_fsm_action(bgp_fsm_retry)
/*------------------------------------------------------------------------------
* TCP connection has closed -- OpenSent/OpenConfirm/Established states
*
- * This is used when a TCP connection has come up, but has simply closed.
+ * 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.
*/
@@ -1727,10 +1743,7 @@ static bgp_fsm_action(bgp_fsm_closed)
{
bgp_connection_close(connection) ;
- if (connection->ordinal == bgp_connection_secondary)
- connection->session->accept = 0 ;
-
- return next_state ;
+ return bgp_fsm_catch_exception(connection, next_state) ;
} ;
/*------------------------------------------------------------------------------
@@ -1753,10 +1766,11 @@ static bgp_fsm_action(bgp_fsm_expire)
return next_state ;
} ;
- /* Otherwise: send NOTIFICATION */
- bgp_fsm_send_notification(connection,
- bgp_notify_new(BGP_NOMC_HOLD_EXP, BGP_NOMS_UNSPECIFIC, 0)) ;
- 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) ;
} ;
/*------------------------------------------------------------------------------
@@ -1818,6 +1832,8 @@ static bgp_fsm_action(bgp_fsm_recv_open)
/* If 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 ;
}
@@ -1838,31 +1854,27 @@ static bgp_fsm_action(bgp_fsm_recv_open)
*/
static bgp_fsm_action(bgp_fsm_error)
{
- bgp_fsm_send_notification(connection,
- bgp_notify_new(BGP_NOMC_FSM, BGP_NOMS_UNSPECIFIC, 0)) ;
- return next_state ;
+ 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) ;
} ;
/*------------------------------------------------------------------------------
* Receive NOTIFICATION from far end -- OpenSent/OpenConfirm/Established
*
- * For OpenSent/OpenConfirm will be going Idle.
+ * This is in response to Receive_NOTIFICATION_message, which has posted the
+ * exception -- so now need to deal with it.
*
- * For Established will be going Stopping -- bgp_stopped_recv_nom
- *
- * Next state will be same as current, except for Established, when will be
- * Stopping.
+ * Next state will be Idle, except for Established, when will be Stopping.
*
* NB: the session is locked.
*/
static bgp_fsm_action(bgp_fsm_recv_nom)
{
- if (next_state == bgp_fsm_Stopping)
- connection->stopped = bgp_stopped_recv_nom ;
-
bgp_connection_close(connection) ;
- return next_state ;
+ return bgp_fsm_catch_exception(connection, next_state) ;
} ;
/*------------------------------------------------------------------------------
@@ -1916,7 +1928,7 @@ static bgp_fsm_action(bgp_fsm_establish)
/* TODO: now would be a good time to withdraw the password from listener ? */
/* Set the session state -- tell the Routeing Engine the news */
- bgp_session_set_state(session, bgp_session_Established) ;
+ /*>>>>>>> signal event <<<<<*/
return next_state ;
} ;
@@ -1963,23 +1975,64 @@ static bgp_fsm_action(bgp_fsm_exit)
}
/*==============================================================================
- * The FSM stopping management.
+ * Catching FSM Exceptions.
+ *
+ * Throwing/Posting Exceptions sets:
+ *
+ * connection->except )
+ * connection->err ) which define the exception
+ * connection->notification )
+ *
+ * The FSM adds the expected next_state.
+ *
+ * From all the above...
+ *
*
- * There are many ways in which a connection may be required to stop.
+ */
+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: can only be notification pending if TCP connection is up (OpenSent,
+ * OpenConfirm or Established.
*
- * The stopping of one connection may mean that the entire session should be
- * stopped -- either because there is only one connection (eg when in
- * Established state), or because this is an administrative stop, or because
- * there has been a serious error, or because a notification received, or ...
+ * If do send N
*
+ * 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:
*
+ * bgp_stopped_admin -- stopped by Routeing Engine
+ * bgp_stopped_loser -- other connection won race to Established state
+ * bgp_stopped_invalid -- invalid event or action
*
+ * then we force transition to Stopping state.
*/
+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_stopping(bgp_connection connection, bgp_stopped_cause_t cause,
- bgp_notify notification, int both)
+bgp_fsm_set_exception(bgp_connection connection, bgp_session_event_t except,
+ bgp_notify notification, int err) ;
{
bgp_session session ;
bgp_connection sibling ;
@@ -2012,6 +2065,8 @@ bgp_fsm_set_stopping(bgp_connection connection, bgp_stopped_cause_t cause,
BGP_CONNECTION_SESSION_UNLOCK(connection) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
} ;
+} ;
+
/*==============================================================================
* The BGP connections timers handling.
*
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 1a10d8ae..3c1cf753 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -60,6 +60,9 @@ bgp_getsockname(int fd, union sockunion* su_local, union sockunion* su_remote) ;
static int
bgp_socket_set_common_options(int fd, union sockunion* su, int ttl,
const char* password) ;
+static int
+bgp_md5_set_listeners(union sockunion* su, const char* password) ;
+
/*==============================================================================
* Open and close the listeners.
*
@@ -334,16 +337,54 @@ bgp_init_listener(int sock, struct sockaddr *sa, socklen_t salen)
/*------------------------------------------------------------------------------
* Prepare to accept() connection
*
- * Sets session->accept true -- so accept() action will accept the connection.
+ * If the session has a password, then this is where the listener(s) for the
+ * appropriate address family are told about the password.
+ *
+ * This is done shortly before the session is first enabled for accept().
*
+ * The effect is (probably) that the peer's attempts to connect with MD5 signed
+ * packets will simply have been ignored up to this point. From this point
+ * forward they will be accepted, but closed until accept is enabled.
+ *
+ * NB: requires the session mutex LOCKED.
+ */
+extern void
+bgp_prepare_to_accept(bgp_connection connection)
+{
+ int ret ;
+
+ if (connection->session->password != NULL)
+ {
+ ret = bgp_md5_set_listeners(connection->session->su_peer,
+ connection->session->password) ;
+
+/* TODO: failure to set password in bgp_prepare_to_accept ? */
+ } ;
+
+ return ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * No longer prepared to accept() connection
*
+ * If the session has a password, then this is where it is withdrawn from the
+ * listener(s) for the appropriate address family.
*
* NB: requires the session mutex LOCKED.
*/
extern void
-bgp_open_accept(bgp_connection connection)
+bgp_not_prepared_to_accept(bgp_connection connection)
{
+ int ret ;
+
+ if (connection->session->password != NULL)
+ {
+ ret = bgp_md5_set_listeners(connection->session->su_peer, NULL) ;
+
+/* TODO: failure to clear password in bgp_not_prepared_to_accept ? */
+ } ;
+ return ;
} ;
/*------------------------------------------------------------------------------
@@ -420,7 +461,7 @@ bgp_accept_action(qps_file qf, void* file_info)
/* See if we are ready to accept connections from the connecting party */
session = bgp_session_lookup(&su_remote, &exists) ;
- if (bgp_session_is_accepting(session))
+ if (session != NULL)
{
if (BGP_DEBUG(events, EVENTS))
zlog_debug(exists
@@ -501,12 +542,12 @@ bgp_open_connect(bgp_connection connection)
/* Make socket for the connect connection. */
fd = sockunion_socket(su) ;
- if (fd < 0)
- return errno ; /* give up immediately if cannot create socket */
+ ret = (fd >= 0) ? 0 : errno ;
/* Set the common options. */
- ret = bgp_socket_set_common_options(fd, su, connection->session->ttl,
- connection->session->password) ;
+ if (ret == 0)
+ ret = bgp_socket_set_common_options(fd, su, connection->session->ttl,
+ connection->session->password) ;
/* Bind socket. */
if (ret == 0)
@@ -536,7 +577,8 @@ bgp_open_connect(bgp_connection connection)
if (ret != 0)
{
- close(fd) ;
+ if (fd >= 0)
+ close(fd) ;
bgp_fsm_connect_completed(connection, ret, NULL, NULL) ;
@@ -895,29 +937,28 @@ bgp_md5_set_socket(int fd, union sockunion *su, const char *password)
} ;
/*------------------------------------------------------------------------------
- * Set MD5 password for given peer in the listener(s) for the peer's address
- * family.
- *
- * NB: requires the session mutex LOCKED.
+ * Set (or clear) MD5 password for given peer in the listener(s) for the peer's
+ * address family.
*
* This allows system to accept MD5 "signed" incoming connections from the
* given address.
*
+ * NULL password clears the password for the given peer.
+ *
* Returns: 0 => OK
* otherwise: errno -- the first error encountered.
*
* NB: peer address must be AF_INET or (if supported) AF_INET6
*
- * NB: if there are no listeners in the required
+ * NB: does nothing and returns "OK" if there are no listeners in the
+ * address family -- wanting to set MD5 makes no difference to this !
*/
-extern int
-bgp_md5_set_listeners(bgp_connection connection)
+static int
+bgp_md5_set_listeners(union sockunion* su, const char* password)
{
bgp_listener listener ;
int ret ;
- union sockunion* su = connection->session->su_peer ;
-
#ifdef HAVE_IPV6
assert((su->sa.sa_family == AF_INET) || (su->sa.sa_family == AF_INET6)) ;
#else
@@ -928,8 +969,7 @@ bgp_md5_set_listeners(bgp_connection connection)
while (listener != NULL)
{
- ret = bgp_md5_set_socket(qps_file_fd(&listener->qf), su,
- connection->session->password) ;
+ ret = bgp_md5_set_socket(qps_file_fd(&listener->qf), su, password) ;
if (ret != 0)
return ret ;
} ;
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
index d9966d7d..1edc2e0e 100644
--- a/bgpd/bgp_network.h
+++ b/bgpd/bgp_network.h
@@ -33,7 +33,10 @@ bgp_close_listeners(void) ;
extern void
bgp_open_connect(bgp_connection connection) ;
-extern int
-bgp_md5_set_listeners(bgp_connection connection) ;
+extern void
+bgp_prepare_to_accept(bgp_connection connection) ;
+
+extern void
+bgp_not_prepared_to_accept(bgp_connection connection) ;
#endif /* _QUAGGA_BGP_NETWORK_H */
diff --git a/bgpd/bgp_peer_index.c b/bgpd/bgp_peer_index.c
new file mode 100644
index 00000000..2967d11f
--- /dev/null
+++ b/bgpd/bgp_peer_index.c
@@ -0,0 +1,329 @@
+/* BGP Peer Index -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "lib/zassert.h"
+
+#include "bgpd/bgp_peer_index.h"
+#include "bgpd/bgp_peer.h"
+#include "bgpd/bgp_session.h"
+
+#include "lib/symtab.h"
+#include "lib/qpthreads.h"
+#include "lib/sockunion.h"
+#include "lib/memory.h"
+
+/*==============================================================================
+ * BGP Peer Index
+ *
+ * When peers are created, they are registered in the bgp_peer_index. When
+ * they are destroyed, they are removed. This is done by the Routeing Engine.
+ *
+ * The peer index is used by the Routeing Engine to lookup peers either by
+ * name (IP address) or by peer_id.
+ *
+ * The BGP Engine needs to lookup sessions when a listening socket accepts a
+ * connection -- first, to decide whether to continue with the connection, and
+ * second, to tie the connection to the right session. It uses the peer index
+ * to do this.
+ *
+ * A mutex is used to coordinate access to the index.
+ */
+
+static struct symbol_table bgp_peer_index ;
+static qpt_mutex_t bgp_peer_index_mutex ;
+
+static bgp_peer_index_entry bgp_peer_id_table = NULL ;
+static bgp_peer_id_t bgp_peer_id_last = 0 ;
+
+CONFIRM(bgp_peer_id_null == 0) ;
+
+enum { bgp_peer_id_unit = 64 } ; /* allocate 64 at a time */
+
+inline static void BGP_PEER_INDEX_LOCK(void)
+{
+ qpt_mutex_lock(&bgp_peer_index_mutex) ;
+} ;
+
+inline static void BGP_PEER_INDEX_UNLOCK(void)
+{
+ qpt_mutex_unlock(&bgp_peer_index_mutex) ;
+} ;
+
+/* Uses the entry zero in the bgp_peer_id_table to point at head and tail of
+ * list of free bgp_peer_id's.
+ *
+ * Uses the peer pointer in free entries to point to then next free.
+ */
+#define bgp_peer_id_table_free_head bgp_peer_id_table->peer
+#define bgp_peer_id_table_free_tail bgp_peer_id_table->accept
+
+#define bgp_peer_id_table_free_next(entry) ((bgp_peer_index_entry)entry)->peer
+
+/* Forward references */
+static void bgp_peer_id_table_free_entry(bgp_peer_index_entry entry) ;
+static void bgp_peer_id_table_free_ids(bgp_peer_id_t f, bgp_peer_id_t l) ;
+static void bgp_peer_id_table_make_ids(void) ;
+
+/*------------------------------------------------------------------------------
+ * Initialise the bgp_peer_index.
+ *
+ * This must be done before any peers are configured !
+ */
+extern void
+bgp_peer_index_init(void* parent)
+{
+ symbol_table_init_new(
+ &bgp_peer_index,
+ parent,
+ 10, /* start ready for a few sessions */
+ 200, /* allow to be quite dense */
+ sockunion_symbol_hash, /* "name" is an IP Address */
+ NULL) ; /* no value change call-back */
+
+ bgp_peer_id_table = XCALLOC(MTYPE_BGP_PEER_ID_TABLE,
+ sizeof(struct bgp_peer_index_entry) * bgp_peer_id_unit) ;
+
+ bgp_peer_id_table_free_head = NULL ;
+
+ bgp_peer_id_last = bgp_peer_id_unit - 1 ;
+ bgp_peer_id_table_free_ids(1, bgp_peer_id_unit) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Initialise the bgp_peer_index_mutex.
+ *
+ * This must be done as soon as any qpthreads are enabled.
+ */
+extern void
+bgp_peer_index_mutex_init(void* parent)
+{
+ qpt_mutex_init(&bgp_peer_index_mutex, qpt_mutex_recursive) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Register a peer in the peer index.
+ *
+ * For use by the Routeing Engine.
+ *
+ * NB: it is a FATAL error to register a peer for an address which is already
+ * registered.
+ */
+extern void
+bgp_peer_index_register(bgp_peer peer, union sockunion* su)
+{
+ bgp_peer_index_entry entry ;
+
+ BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ /* First need an entry, which allocates a peer_id. May need to extend */
+ /* the bgp_peer_id_table -- so need to be locked for this. */
+
+ if (bgp_peer_id_table_free_head == NULL)
+ bgp_peer_id_table_make_ids() ;
+
+ entry = (void*)bgp_peer_id_table_free_head ;
+ bgp_peer_id_table_free_head = (void*)bgp_peer_id_table_free_next(entry) ;
+
+ /* Initialise the entry -- the id is already set */
+ entry->peer = peer ;
+ entry->accept = NULL ;
+ assert(entry->id == (entry - bgp_peer_id_table)) ;
+
+ /* Insert the new entry into the symbol table. */
+ entry = symbol_set_value(symbol_find(&bgp_peer_index, su), entry) ;
+
+ BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ passert(entry != NULL) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Deregister a peer from the peer index.
+ *
+ * For use by the Routeing Engine.
+ *
+ * NB: The peer MUST NOT be deregistered if any of the following apply:
+ *
+ * * there is an active session
+ *
+ * * the peer_id is still in use (anywhere at all)
+ *
+ * NB: it is a FATAL error to deregister a peer which is not registered.
+ */
+extern void
+bgp_peer_index_deregister(bgp_peer peer, union sockunion* su)
+{
+ bgp_peer_index_entry entry ;
+ symbol sym ;
+
+ BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ sym = symbol_seek(&bgp_peer_index, su) ;
+ passert(sym != NULL) ;
+
+ entry = symbol_delete(sym) ;
+
+ passert((entry != NULL) && (entry->peer == peer) && (entry->accept == NULL)) ;
+
+ bgp_peer_id_table_free_entry(entry) ;
+
+ BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+} ;
+
+/*------------------------------------------------------------------------------
+ * Lookup a peer -- do nothing if does not exist
+ *
+ * For use by the Routeing Engine.
+ *
+ * Returns the bgp_peer -- NULL if not found.
+ */
+extern bgp_peer
+bgp_peer_index_seek(union sockunion* su)
+{
+ bgp_peer_index_entry entry ;
+
+ /* Only the Routing Engine can add/delete entries -- so no lock required */
+
+ entry = bgp_peer_index_seek_entry(su) ;
+
+ return (entry != NULL) ? entry->peer : NULL ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Lookup a peer's peer index entry -- do nothing if does not exist
+ *
+ * For use by the Routeing Engine.
+ *
+ * Returns the bgp_peer_index_entry -- NULL if not found.
+ */
+extern bgp_peer_index_entry
+bgp_peer_index_seek_entry(union sockunion* su)
+{
+ /* Only the Routing Engine can add/delete entries -- so no lock required */
+
+ return symbol_get_value(symbol_seek(&bgp_peer_index, su)) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Lookup a session -- do nothing if does not exist
+ *
+ * For use by the BGP Engine.
+ *
+ * Returns: bgp_session if: peer with given address is configured
+ * and: the session is prepared to accept()
+ *
+ * or: NULL otherwise
+ *
+ * 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.
+ */
+extern bgp_session
+bgp_session_index_seek(union sockunion* su, int* p_found)
+{
+ bgp_session accept ;
+ bgp_peer_index_entry entry ;
+
+ BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ entry = symbol_get_value(symbol_seek(&bgp_peer_index, su)) ;
+
+ *p_found = (entry != NULL) ;
+ accept = *p_found ? entry->accept : NULL ;
+
+ BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ assert((accept == NULL) || (bgp_session_is_active(accept))) ;
+
+ return accept ;
+} ;
+
+/*==============================================================================
+ * Extending the bgp_peer_id_table and adding free entries to it.
+ */
+
+/*------------------------------------------------------------------------------
+ * Free the given peer index entry and release its peer_id.
+ */
+static void
+bgp_peer_id_table_free_entry(bgp_peer_index_entry entry)
+{
+ assert((entry - bgp_peer_id_table) == entry->id) ;
+
+ bgp_peer_id_table_free_ids(entry->id, entry->id) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Free a range of peer_ids -- may be just one (of course)
+ *
+ * Adds to end of the peer_id free list, in peer_id order.
+ *
+ * This means that when individual peers are deleted, the ids will be re-used
+ * in the order they were deleted (but after any pool of ids has been used up.
+ */
+static void
+bgp_peer_id_table_free_ids(bgp_peer_id_t f, bgp_peer_id_t l)
+{
+ bgp_peer_id_t id ;
+ bgp_peer_index_entry e ;
+
+ assert(l <= bgp_peer_id_last) ;
+
+ for (id = f ; id <= l ; ++id)
+ {
+ e = &bgp_peer_id_table[id] ;
+
+ e->peer = NULL ; /* being tidy */
+ e->accept = NULL ;
+ e->id = id ; /* for initial creation */
+
+ if (bgp_peer_id_table_free_head == NULL)
+ bgp_peer_id_table_free_head = (void*)e ;
+ else
+ bgp_peer_id_table_free_next(bgp_peer_id_table_free_tail) = (void*)e ;
+
+ bgp_peer_id_table_free_tail = (void*)e ;
+ bgp_peer_id_table_free_next(e) = NULL ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Make a new set of free bgp_peer_ids.
+ *
+ * NB: the bgp_peer_id_table may well move around in memory !
+ */
+static void
+bgp_peer_id_table_make_ids(void)
+{
+ bgp_peer_id_t id_new ;
+
+ id_new = bgp_peer_id_last + 1 ;
+ bgp_peer_id_last += bgp_peer_id_unit ;
+
+ bgp_peer_id_table = XREALLOC(MTYPE_BGP_PEER_ID_TABLE, bgp_peer_id_table,
+ sizeof(struct bgp_peer_index_entry) * (bgp_peer_id_last + 1)) ;
+
+ bgp_peer_id_table_free_ids(id_new, bgp_peer_id_last) ;
+} ;
+
+
diff --git a/bgpd/bgp_peer_index.h b/bgpd/bgp_peer_index.h
new file mode 100644
index 00000000..ae41de24
--- /dev/null
+++ b/bgpd/bgp_peer_index.h
@@ -0,0 +1,89 @@
+/* BGP Peer Index -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _QUAGGA_BGP_PEER_INDEX_H
+#define _QUAGGA_BGP_PEER_INDEX_H
+
+#include "bgpd/bgp_common.h"
+
+#include "lib/sockunion.h"
+
+/*==============================================================================
+ * The Peer Index maps:
+ *
+ * * IP address (name of peer)
+ * * peer_id (ordinal of peer)
+ *
+ * To the bgp_peer_index_entry.
+ */
+typedef struct bgp_peer_index_entry* bgp_peer_index_entry ;
+
+typedef unsigned bgp_peer_id_t ;
+
+struct bgp_peer_index_entry
+{
+ bgp_peer peer ; /* used by Peering Engine */
+
+ /* The accept pointer is used by the listening socket(s) to find the
+ * session when it is prepared to accept a connection.
+ *
+ * This pointer MUST be NULL when not sEnabled or sEstablished. It
+ * will be set by the BGP Engine when it decides to accept connections,
+ * and cleared by it otherwise (and when a session stops).
+ *
+ * An active session contains a pointer to the peer index entry to
+ * facilitate this.
+ */
+
+ bgp_session accept ; /* used by BGP Engine */
+
+ bgp_peer_id_t id ; /* maps IP address to peer_id */
+} ;
+
+enum { bgp_peer_id_null = 0 } ; /* no peer can have id == 0 */
+
+/*==============================================================================
+ *
+ */
+
+extern void
+bgp_peer_index_init(void* parent) ;
+
+extern void
+bgp_peer_index_mutex_init(void* parent) ;
+
+extern void
+bgp_peer_index_register(bgp_peer peer, union sockunion* su) ;
+
+extern void
+bgp_peer_index_deregister(bgp_peer peer, union sockunion* su) ;
+
+extern bgp_peer
+bgp_peer_index_seek(union sockunion* su) ;
+
+extern bgp_peer_index_entry
+bgp_peer_index_seek_entry(union sockunion* su) ;
+
+extern bgp_session
+bgp_session_index_seek(union sockunion* su, int* p_found) ;
+
+#endif /* _QUAGGA_BGP_PEER_INDEX_H */
+
diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c
index f21743ca..f77e9e34 100644
--- a/bgpd/bgp_session.c
+++ b/bgpd/bgp_session.c
@@ -21,6 +21,8 @@
#include "bgpd/bgp_session.h"
#include "bgpd/bgp_peer.h"
+#include "bgpd/bgp_engine.h"
+#include "bgpd/bgp_peer_index.h"
#include "lib/memory.h"
#include "lib/sockunion.h"
@@ -66,12 +68,25 @@
*
*/
-/* Initialise new session structure -- allocate if required.
+/*------------------------------------------------------------------------------
+ * Initialise new session structure -- allocate if required.
*
+ * Ties peer and session together. Sets session sIdle, initialises mutex.
+ *
+ * Unsets everything else -- mostly by zeroising it.
+ *
+ * NB: if not allocating, the existing session MUST be sIdle/sStopped OR never
+ * been kissed.
+ *
+ * NB: in any event, the peer's peer index entry MUST have a NULL session
+ * pointer.
*/
extern bgp_session
-bgp_session_init_new(bgp_session session)
+bgp_session_init_new(bgp_session session, bgp_peer peer)
{
+ assert(peer->session == NULL) ;
+ assert(peer->index_entry->session == NULL) ;
+
if (session == NULL)
session = XCALLOC(MTYPE_BGP_SESSION, sizeof(struct bgp_session)) ;
else
@@ -79,8 +94,50 @@ bgp_session_init_new(bgp_session session)
qpt_mutex_init_new(&session->mutex, qpt_mutex_recursive) ;
-
-
+ peer->session = session ;
+ session->peer = peer ;
+ session->state = bgp_session_sIdle ;
+
+ session->index_entry = peer->index_entry ;
+
+ /* Zeroising the structure has set:
+ *
+ * made -- false, not yet sEstablished
+ *
+ * event -- bgp_session_null_event
+ * notification -- NULL -- none
+ * err -- 0 -- none
+ *
+ * open_send -- NULL -- none
+ * open_recv -- NULL -- none
+ *
+ * connect -- unset, false
+ * listen -- unset, false
+ *
+ * ttl -- unset
+ * port -- unset
+ * su_peer -- NULL -- none
+ *
+ * log -- NULL -- none
+ * host -- NULL -- none
+ * password -- NULL -- none
+ *
+ * idle_hold_timer_interval )
+ * connect_retry_timer_interval )
+ * open_hold_timer_interval ) unset
+ * hold_timer_interval )
+ * keepalive_timer_interval )
+ *
+ * as4 -- unset, false
+ *
+ * su_local -- NULL -- none
+ * su_remote -- NULL -- none
+ *
+ * connections[] -- NULL -- none
+ */
+ confirm(bgp_session_null_event == 0) ;
+
+ return session ;
} ;
/* Look up session
@@ -91,35 +148,46 @@ bgp_session_lookup(union sockunion* su, int* exists) ;
-
-/* Enable session for given peer -- allocate session if required.
+/*==============================================================================
+ * Enable session for given peer -- allocate session if required.
*
* Sets up the session given the current state of the peer. If the state
* changes, then....
*
*
*/
+static void
+bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag) ;
-extern bgp_session
-bgp_session_enable(bgp_session session, bgp_peer peer)
+extern void
+bgp_session_enable(bgp_peer peer)
{
- if (session == NULL)
- session = bgp_session_init_new(session) ;
+ bgp_session session ;
+ mqueue_block mqb ;
+
+ /* Set up session if required. Check session if already exists.
+ *
+ * Only the Peering Engine creates sessions, so it is safe to pick up the
+ * peer->session pointer and test it.
+ *
+ * If session exists, it MUST be inactive.
+ *
+ * Peering Engine does not require the mutex while the session is inactive.
+ */
+ session = peer->session ;
- /* Tie back to peer and set state of session. */
-
- assert((session->peer == NULL) || (session->peer == peer)) ;
- assert((session->state != bgp_session_Enabled) &&
- (session->state != bgp_session_Established)) ;
-
- session->peer = peer ;
- session->state = bgp_session_Enabled ;
+ if (session == NULL)
+ session = bgp_session_init_new(NULL, peer) ;
+ else
+ {
+ assert(session->peer == peer) ;
+ assert(!bgp_session_is_active(session)) ;
+ } ;
/* Initialise what we need to make and run connections */
session->connect = (peer->flags & PEER_FLAG_PASSIVE) != 0 ;
session->listen = 1 ;
- session->accept = 0 ;
session->ttl = peer->ttl ;
session->port = peer->port ;
@@ -127,7 +195,7 @@ bgp_session_enable(bgp_session session, bgp_peer peer)
session->su_peer = sockunion_dup(&peer->su) ;
session->log = peer->log ;
- session->host = peer->host ;
+ session->host = peer->host ; /* TODO: duplicate string ? */
session->idle_hold_timer_interval = peer->v_start ;
session->connect_retry_timer_interval = peer->v_connect ;
@@ -140,51 +208,205 @@ bgp_session_enable(bgp_session session, bgp_peer peer)
/*....*/
+ /* Routeing Engine does the state change now. */
+ session->state = bgp_session_sEnabled ;
+
/* Now pass the session to the BGP Engine, which will set about */
/* making and running a connection to the peer. */
+ mqb = mqb_init_new(NULL, bgp_session_do_enable, session) ;
+ confirm(sizeof(struct bgp_session_enable_args) == 0) ;
+ bgp_to_engine(mqb) ;
} ;
+/*------------------------------------------------------------------------------
+ * BGP Engine: session enable message action
+ */
+static void
+bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag)
+{
+ if (flag == mqb_action)
+ {
+
+
+ } ;
+
+ mqb_free(mqb) ;
+} ;
/*==============================================================================
- * Session data access functions.
+ * 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).
*/
+static void
+bgp_session_do_disable(mqueue_block mqb, mqb_flag_t flag) ;
-extern int
-bgp_session_is_active(bgp_session session)
+extern void
+bgp_session_disable(bgp_peer peer, bgp_notify notification)
{
- int ret ;
+ bgp_session session ;
+ mqueue_block mqb ;
+
+ session = peer->session ;
+ assert((session != NULL) && (session->peer == peer)) ;
+
+ /* Should do nothing if session is not active. */
+
+ if (!bgp_session_is_active(session))
+ {
+ bgp_notify_free(notification) ; /* discard any bgp_notify */
+ return ;
+ } ;
+
+ /* Now 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.
+ *
+ * The BGP Engine quietly discards disable messages for sessions which
+ * are not active.
+ *
+ * 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.
+ */
+ mqb = mqb_init_new(NULL, bgp_session_do_disable, session) ;
+
+ confirm(sizeof(struct bgp_session_enable_args) == 0) ;
+
+ bgp_to_engine_priority(mqb) ;
+} ;
- if (session == NULL)
- return 0 ; /* NULL session is implicitly not active */
+/*------------------------------------------------------------------------------
+ * BGP Engine: session enable message action
+ */
+static void
+bgp_session_do_disable(mqueue_block mqb, mqb_flag_t flag)
+{
+ if (flag == mqb_action)
+ {
- BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- ret = ( (session->state == bgp_session_Enabled)
- || (session->state == bgp_session_Established) ) ;
+ } ;
- BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+ mqb_free(mqb) ;
+} ;
+
+/*==============================================================================
+ * Send session event signal from BGP Engine to Routeing Engine
+ *
+ *
+ */
+extern void
+bgp_session_event(bgp_session session, bgp_session_event_t event,
+ bgp_notify notification,
+ bgp_session_state_t state)
+{
+ struct bgp_session_event_args* args ;
+ mqueue_block mqb ;
+
+ mqb = mqb_init_new(NULL, bgp_session_do_event, session) ;
- return ret ;
+ args = mqb_get_args(mqb) ;
+
+ args->event = event ;
+ args->notification = notification ;
+ args->state = state ;
+
+ bgp_to_peering(mqb) ;
+}
+
+/*==============================================================================
+ * Dispatch update to peer -- Peering Engine -> 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)
+{
+ struct bgp_session_update_args* args ;
+ mqueue_block mqb ;
+
+ mqb = mqb_init_new(NULL, bgp_session_do_update_send, session) ;
+
+ args = mqb_get_args(mqb) ;
+
+ args->buf = upd ;
+
+ bgp_to_engine(mqb) ;
} ;
-extern int
-bgp_session_is_accepting(bgp_session session)
+/*==============================================================================
+ * Forward incoming update -- BGP Engine -> 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.
+ */
+extern void
+bgp_session_update_recv(bgp_session session, struct stream* upd)
{
- int ret ;
+ struct bgp_session_update_args* args ;
+ mqueue_block mqb ;
- if (session == NULL)
- return 0 ; /* NULL session is implicitly not accepting */
+ mqb = mqb_init_new(NULL, bgp_session_do_update_recv, session) ;
+
+ args = mqb_get_args(mqb) ;
+
+ args->buf = upd ;
+
+ bgp_to_peering(mqb) ;
+} ;
+
+
+
+/*==============================================================================
+ * Session data access functions.
+ *
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * See if session exists and is active.
+ *
+ * Ensure that if exists and is not active, that the peer index entry accept
+ * pointer is NULL -- this is largely paranoia, but it would be a grave
+ * mistake for the listening socket(s) to find a session which is not active !
+ */
+extern int
+bgp_session_is_active(bgp_session session)
+{
+ int active ;
BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- ret = session->accept ;
+ if (session == NULL)
+ active = 0 ;
+ else
+ {
+ active = ( (session->state == bgp_session_sEnabled)
+ || (session->state == bgp_session_sEstablished) ) ;
+
+ if (!active)
+ assert(session->index_entry->accept == NULL) ;
+ } ;
BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
- return ret ;
+ return active ;
} ;
diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h
index 7b8bcbd7..4b5f8ca7 100644
--- a/bgpd/bgp_session.h
+++ b/bgpd/bgp_session.h
@@ -28,10 +28,12 @@
#include "bgpd/bgp_engine.h"
#include "bgpd/bgp_connection.h"
#include "bgpd/bgp_notification.h"
+#include "bgpd/bgp_peer_index.h"
#include "lib/qtimers.h"
#include "lib/qpthreads.h"
#include "lib/sockunion.h"
+#include "lib/mqueue.h"
#ifndef Inline
#define Inline static inline
@@ -64,47 +66,84 @@
*
*/
-typedef enum bgp_session_states bgp_session_state_t ;
-enum bgp_session_states
-{
- bgp_session_min_state = 0,
-
- bgp_session_Idle = 0,
-
- bgp_session_Enabled = 1, /* attempting to connect */
- bgp_session_Established = 2,
-
- bgp_session_Stopped = 3, /* for whatever reason */
-
- bgp_session_max_state = 3
-} ;
struct bgp_session
{
bgp_peer peer ; /* peer whose session this is */
- qpt_mutex_t mutex ; /* for access to the rest */
+ bgp_peer_index_entry index_entry ; /* and its index entry */
- bgp_session_state_t state ; /* as above */
+ qpt_mutex_t mutex ; /* for access to the rest */
- bgp_stopped_cause_t stopped ; /* why stopped */
+ /* While sIdle and sStopped:
+ *
+ * the session belongs to the Peering Engine.
+ *
+ * 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:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * The Peering Engine may use this flag in sStopped state to see if the
+ * session was ever established.
+ */
+ bgp_session_state_t state ;
+ int made ; /* set when -> sEstablished */
+
+ /* The BGP Engine records the last event, NOTIFICATION and errno here.
+ *
+ * This is only really useful when the session -> sStopped.
+ */
+ bgp_session_event_t event ; /* last event */
bgp_notify notification ; /* if any sent/received */
-
+ int err ; /* errno, if any */
+
+ /* The Routeing Engine sets open_send and clears open_recv before enabling
+ * the session, and may not change them while sEnabled/sEstablished.
+ *
+ * The BGP Engine sets open_recv before setting the session sEstablished,
+ * and will not touch it thereafter.
+ *
+ * So: the Routeing Engine may use open_recv once the session is
+ * sEstablished.
+ */
bgp_open_state open_send ; /* how to open the session */
bgp_open_state open_recv ; /* set when session Established */
+ /* The following are set by the Routeing Engine before a session is
+ * enabled, and not changed at any other time by either engine.
+ */
int connect ; /* initiate connections */
int listen ; /* listen for connections */
- int accept ; /* accept connections */
-
int ttl ; /* TTL to set, if not zero */
unsigned short port ; /* destination port for peer */
union sockunion* su_peer ; /* Sockunion address of the peer */
- union sockunion* su_local ; /* set when session Established */
- union sockunion* su_remote ; /* set when session Established */
-
struct zlog* log ; /* where to log to */
char* host ; /* copy of printable peer's addr */
@@ -113,19 +152,73 @@ struct bgp_session
unsigned idle_hold_timer_interval ; /* in seconds */
unsigned connect_retry_timer_interval ;
unsigned open_hold_timer_interval ;
+
+ /* These are set by the Routeing Engine before a session is enabled,
+ * and may be changed by the BGP Engine when the session is established.
+ *
+ * The Routeing Engine may read these once sEstablished (under mutex).
+ *
+ * In sStopped state these reflect the last state of the session.
+ */
unsigned hold_timer_interval ; /* subject to negotiation */
unsigned keepalive_timer_interval ; /* subject to negotiation */
- /* NB: these values are private to the BGP Engine, which accesses them */
- /* *without* worrying about the mutex. */
- /* */
- /* The BGP Engine uses these while the session is Enabled or */
- /* Established -- so the session must not be freed in these states. */
+ int as4 ;
+
+ /* These are cleared by the Routeing Engine before a session is enabled,
+ * and set by the BGP Engine when the session is established.
+ *
+ * In sStopped state these reflect the last state of the session.
+ */
+ union sockunion* su_local ; /* set when session Established */
+ union sockunion* su_remote ; /* set when session Established */
+ /* These values are are private to the BGP Engine.
+ *
+ * They must be cleared before the session is enabled, but may not be
+ * touched by the Routeing Engine at any other time.
+ *
+ * Before stopping a session the BGP Engine unlinks any connections from
+ * the session.
+ */
bgp_connection connections[bgp_connection_count] ;
} ;
/*==============================================================================
+ * Mqueue messages related to sessions
+ *
+ * In all these messages arg0 is the session.
+ */
+
+struct bgp_session_enable_args /* to BGP Engine */
+{
+ /* no further arguments */
+} ;
+MQB_ARGS_SIZE_OK(bgp_session_enable_args) ;
+
+struct bgp_session_disable_args /* to BGP Engine */
+{
+ bgp_notify notification ; /* NOTIFICATION to send */
+} ;
+MQB_ARGS_SIZE_OK(bgp_session_enable_args) ;
+
+struct bgp_session_update_args /* to and from BGP Engine */
+{
+ struct stream* buf ;
+} ;
+MQB_ARGS_SIZE_OK(bgp_session_enable_args) ;
+
+struct bgp_session_event_args /* to Routeing Engine */
+{
+ bgp_session_event_t event ;
+ bgp_notify notification ; /* sent or received (if any) */
+ int err ; /* errno if any */
+
+ bgp_session_state_t state ; /* after the event */
+} ;
+MQB_ARGS_SIZE_OK(bgp_session_enable_args) ;
+
+/*==============================================================================
* Session mutex lock/unlock
*/
@@ -140,15 +233,32 @@ inline static void BGP_SESSION_UNLOCK(bgp_session session)
} ;
/*==============================================================================
- *
+ * Functions
*/
extern bgp_session
-bgp_session_init_new(bgp_session session) ;
+bgp_session_init_new(bgp_session session, bgp_peer peer) ;
extern bgp_session
bgp_session_lookup(union sockunion* su, int* exists) ;
+extern void
+bgp_session_enable(bgp_peer peer) ;
+
+extern void
+bgp_session_disable(bgp_peer peer, bgp_notify notification) ;
+
+extern void
+bgp_session_event(bgp_session session, bgp_session_event_t event,
+ bgp_notify notification,
+ bgp_session_state_t state) ;
+
+extern void
+bgp_session_update_send(bgp_session session, struct stream* upd) ;
+
+extern void
+bgp_session_update_recv(bgp_session session, struct stream* upd) ;
+
/*==============================================================================
* Session data access functions.
*
@@ -158,7 +268,5 @@ bgp_session_lookup(union sockunion* su, int* exists) ;
extern int
bgp_session_is_active(bgp_session session) ;
-extern int
-bgp_session_is_accepting(bgp_session session) ;
#endif /* QUAGGA_BGP_SESSION_H */
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 9479feb2..7c4c6f61 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -115,6 +115,7 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_PEER_GROUP, "Peer group" },
{ MTYPE_PEER_DESC, "Peer description" },
{ MTYPE_PEER_PASSWORD, "Peer password string" },
+ { MTYPE_BGP_PEER_ID_TABLE, "Peer ID table" },
{ MTYPE_BGP_SESSION, "BGP session" },
{ MTYPE_BGP_CONNECTION, "BGP connection" },
{ MTYPE_BGP_NOTIFY, "BGP notification" },
diff --git a/lib/mqueue.h b/lib/mqueue.h
index 32ac599e..b1332e68 100644
--- a/lib/mqueue.h
+++ b/lib/mqueue.h
@@ -96,6 +96,8 @@ struct args
char data[mqb_args_size_max] ; /* empty space */
} ;
+#define MQB_ARGS_SIZE_OK(s) CONFIRM(sizeof(struct s) <= mqb_args_size_max)
+
struct mqueue_block
{
struct args args ; /* user structure */