summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_connection.c57
-rw-r--r--bgpd/bgp_connection.h25
-rw-r--r--bgpd/bgp_fsm.c38
-rw-r--r--bgpd/bgp_msg_read.c29
-rw-r--r--bgpd/bgp_msg_write.c20
-rw-r--r--bgpd/bgp_network.c187
-rw-r--r--bgpd/bgp_network.h3
-rw-r--r--bgpd/bgp_peer.c42
-rw-r--r--bgpd/bgp_peer.h2
-rw-r--r--bgpd/bgp_peer_index.c14
-rw-r--r--bgpd/bgp_peer_index.h10
-rw-r--r--bgpd/bgp_session.c59
-rw-r--r--bgpd/bgp_session.h9
-rw-r--r--lib/prefix.h8
-rw-r--r--lib/sockunion.c33
-rw-r--r--lib/sockunion.h4
16 files changed, 353 insertions, 187 deletions
diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c
index c7935cf3..ba75a509 100644
--- a/bgpd/bgp_connection.c
+++ b/bgpd/bgp_connection.c
@@ -34,6 +34,7 @@
#include "lib/mqueue.h"
#include "lib/symtab.h"
#include "lib/stream.h"
+#include "lib/sockunion.h"
/*==============================================================================
* BGP Connections.
@@ -143,8 +144,11 @@ bgp_connection_init_new(bgp_connection connection, bgp_session session,
bgp_write_buffer_full_threshold ;
/* Link back to session, point at its mutex and point session here */
- connection->session = session ;
- connection->p_mutex = &session->mutex ;
+ connection->session = session ;
+ connection->p_mutex = &session->mutex ;
+ connection->lock_count = 0 ; /* no question about it */
+
+ connection->paf = sockunion_family(session->su_peer) ;
connection->ordinal = ordinal ;
connection->accepted = (ordinal == bgp_connection_secondary) ;
@@ -177,6 +181,32 @@ bgp_connection_init_new(bgp_connection connection, bgp_session session,
} ;
/*------------------------------------------------------------------------------
+ * Cut connection free from session.
+ *
+ * NB: will release any lock on the session. The bumps the lock count up
+ * so that will neither lock nor unlock the session again.
+ *
+ * It's only necessary to bump the count by 1, because all locks must be
+ * exactly balanced by unlocks. However, adding a big number makes this
+ * stand out.
+ */
+extern void
+BGP_CONNECTION_SESSION_CUT_LOOSE(bgp_connection connection)
+{
+ if (connection->session != NULL)
+ {
+ if (connection->lock_count != 0)
+ qpt_mutex_unlock(connection->p_mutex) ;
+
+ connection->lock_count += 10000 ;
+
+ connection->session->connections[connection->ordinal] = NULL ;
+ connection->session = NULL ;
+ connection->p_mutex = NULL ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
* Set the host field for the connection to session->host + given tag.
*
* NB: requires the session to be LOCKED.
@@ -186,6 +216,8 @@ bgp_connection_init_host(bgp_connection connection, const char* tag)
{
const char* host = connection->session->host ;
+ if (connection->host != NULL)
+ XFREE(MTYPE_BGP_PEER_HOST, connection->host) ;
connection->host = XMALLOC(MTYPE_BGP_PEER_HOST, strlen(host)
+ strlen(tag) + 1) ;
strcpy(connection->host, host) ;
@@ -241,7 +273,8 @@ bgp_connection_make_primary(bgp_connection connection)
*/
bgp_open_state_set_mov(&session->open_recv, &connection->open_recv) ;
- XFREE(MTYPE_BGP_PEER_HOST, connection->host) ;
+ if (connection->host != NULL)
+ XFREE(MTYPE_BGP_PEER_HOST, connection->host) ;
bgp_connection_init_host(connection, "") ;
session->hold_timer_interval = connection->hold_timer_interval ;
@@ -516,7 +549,7 @@ bgp_connection_open(bgp_connection connection, int fd)
extern void
bgp_connection_enable_accept(bgp_connection connection)
{
- connection->session->index_entry->accept = connection->session ;
+ connection->session->index_entry->accept = connection ;
} ;
/*------------------------------------------------------------------------------
@@ -881,6 +914,7 @@ static void
bgp_connection_read_action(qps_file qf, void* file_info)
{
bgp_connection connection = file_info ;
+
int want ;
int ret ;
@@ -934,11 +968,22 @@ bgp_connection_read_action(qps_file qf, void* file_info)
/* Deal with the BGP message. MUST remove from ibuf before returns !
*
+ * NB: if the session pointer is NULL, that means the connection has been
+ * cut from the session, so no point dealing with the message.
+ *
+ * NB: if something goes wrong while processing the message,
+ *
* NB: size passed is the size of the *body* of the message.
*/
- connection->msg_func(connection, connection->msg_body_size) ;
+ if (connection->session != NULL) /* don't bother if session gone ! */
+ {
+ BGP_CONNECTION_SESSION_LOCK(connection) ; /*<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ connection->msg_func(connection, connection->msg_body_size) ;
+
+ BGP_CONNECTION_SESSION_UNLOCK(connection) ; /*>>>>>>>>>>>>>>>>>>>>>>>>*/
+ } ;
/* Ready to read another message */
connection->read_pending = 0 ;
} ;
-
diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h
index d38be299..e4c183b8 100644
--- a/bgpd/bgp_connection.h
+++ b/bgpd/bgp_connection.h
@@ -131,6 +131,7 @@ struct bgp_connection
/* NULL if connection stopping */
qpt_mutex p_mutex ; /* session mutex* */
/* (avoids incomplete type issue) */
+ unsigned lock_count ; /* session lock count */
bgp_connection_ord_t ordinal ; /* primary/secondary connection */
int accepted ; /* came via accept() */
@@ -151,6 +152,7 @@ struct bgp_connection
bgp_open_state open_recv ; /* the open received. */
struct qps_file qf ; /* qpselect file structure */
+ pAF_t paf ; /* address family */
union sockunion* su_local ; /* address of the near end */
union sockunion* su_remote ; /* address of the far end */
@@ -292,19 +294,38 @@ bgp_connection_write_empty(bgp_connection connection)
*
*/
+/*==============================================================================
+ * Locking the session associated with the connection.
+ *
+ * This is slightly complicated by the fact that when the connection is in
+ * sStopping, it is no longer attached to the session.
+ *
+ * To facilitate that, the connection maintains its own "recursive" count, so
+ * that when the connection is cut loose from the session, the session's mutex
+ * can be released.
+ *
+ * Further -- when the connection is cut loose, a big number is added to the
+ * count, so when the session is "unlocked" nothing will happen !
+ *
+ * Also -- this mechanism means that the session lock can be called even after
+ * the connection has been cut loose, without requiring any other tests.
+ */
+
Inline void
BGP_CONNECTION_SESSION_LOCK(bgp_connection connection)
{
- if (connection->session != NULL)
+ if (connection->lock_count++ == 0)
qpt_mutex_lock(connection->p_mutex) ;
} ;
Inline void
BGP_CONNECTION_SESSION_UNLOCK(bgp_connection connection)
{
- if (connection->session != NULL)
+ if (--connection->lock_count == 0)
qpt_mutex_unlock(connection->p_mutex) ;
} ;
+extern void
+BGP_CONNECTION_SESSION_CUT_LOOSE(bgp_connection connection) ;
#endif /* QUAGGA_BGP_CONNECTION_H */
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index e4152f80..cfa6561c 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -629,6 +629,8 @@ bgp_fsm_connect_completed(bgp_connection connection, int err,
sockunion_set_dup(&connection->su_local, su_local) ;
sockunion_set_dup(&connection->su_remote, su_remote) ;
+
+ connection->paf = sockunion_family(connection->su_local) ;
}
else if ( (err == ECONNREFUSED)
|| (err == ECONNRESET)
@@ -1559,7 +1561,6 @@ bgp_fsm_state_change(bgp_connection connection, bgp_fsm_state_t new_state) ;
extern void
bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event)
{
- bgp_session session ;
bgp_fsm_state_t next_state ;
const struct bgp_fsm* fsm ;
@@ -1584,10 +1585,8 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event)
*
* The session lock does nothing if no session is attached.
*/
- session = connection->session ;
- if (session != NULL)
- BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+ BGP_CONNECTION_SESSION_LOCK(connection) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
do
{
@@ -1639,30 +1638,34 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event)
} while (--connection->fsm_active != 0) ;
/* If required, post session event. */
-
- if ((connection->except != bgp_session_null_event) && (session != NULL))
+ if (connection->except != bgp_session_null_event)
{
+ int stopped = (connection->state == bgp_fsm_sStopping) ;
+ int has_session = (connection->session != NULL) ;
+
/* 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,
+ if ((connection->except <= bgp_session_max_event) && has_session)
+ bgp_session_event(connection->session, connection->except,
bgp_notify_take(&connection->notification),
connection->err,
connection->ordinal,
- (connection->state == bgp_fsm_sStopping)) ;
+ stopped) ;
/* Tidy up -- notification already cleared */
connection->except = bgp_session_null_event ;
connection->err = 0 ;
bgp_notify_unset(&connection->notification) ; /* if any */
- }
- if (session != NULL)
- BGP_SESSION_UNLOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+ if (stopped && has_session)
+ BGP_CONNECTION_SESSION_CUT_LOOSE(connection) ;
+ } ;
+
+ BGP_CONNECTION_SESSION_UNLOCK(connection) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
} ;
/*==============================================================================
@@ -2095,9 +2098,6 @@ static bgp_fsm_action(bgp_fsm_establish)
*/
static bgp_fsm_action(bgp_fsm_recv_kal)
{
- /* peer count update */
-//peer->keepalive_in++;
-
bgp_hold_timer_recharge(connection) ;
return next_state ;
} ;
@@ -2168,7 +2168,7 @@ static bgp_fsm_action(bgp_fsm_exit)
*
* * send message to Routeing Engine
*
- * NB: requires the session LOCKED
+ * NB: requires the session LOCKED -- connection-wise
*/
static bgp_fsm_state_t
bgp_fsm_catch(bgp_connection connection, bgp_fsm_state_t next_state)
@@ -2218,6 +2218,8 @@ bgp_fsm_catch(bgp_connection connection, bgp_fsm_state_t next_state)
* When get Sent_NOTIFICATION_message, will set final "courtesy" timer, so
* unless I/O fails, final end of process is HoldTimer expired (with
*
+ * NB: requires the session to be locked -- connection-wise.
+ *
* NB: leaves the notification sitting in the connection.
*/
static bgp_fsm_state_t
@@ -2513,10 +2515,6 @@ bgp_fsm_state_change(bgp_connection connection, bgp_fsm_state_t new_state)
qtimer_unset(&connection->keepalive_timer) ;
- session->connections[connection->ordinal] = NULL ;
- connection->session = NULL ;
- connection->p_mutex = NULL ;
-
break ;
default:
diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c
index 7b56e9de..7b7b1130 100644
--- a/bgpd/bgp_msg_read.c
+++ b/bgpd/bgp_msg_read.c
@@ -20,6 +20,7 @@
*/
#include <zebra.h>
+#include <time.h>
#include "bgpd/bgp_common.h"
#include "bgpd/bgp_msg_read.h"
@@ -304,6 +305,7 @@ bgp_msg_open_invalid(bgp_notify notification) ;
/*------------------------------------------------------------------------------
* Receive BGP open packet and parse it into the connection's open_recv
*
+ * NB: requires the session to be locked (connection-wise) and not NULL.
*/
static void
bgp_msg_open_receive (bgp_connection connection, bgp_size_t body_size)
@@ -317,6 +319,8 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t body_size)
struct sucker ssr ;
unsigned holdtime ;
+ ++connection->session->stats.open_in ;
+
/* Start with an unspecific OPEN notification */
bgp_notify notification = bgp_notify_new(BGP_NOMC_OPEN,
BGP_NOMS_UNSPECIFIC, 0) ;
@@ -1343,6 +1347,8 @@ bgp_msg_capability_as4 (bgp_connection connection, sucker sr)
/*==============================================================================
* BGP UPDATE message
+ *
+ * NB: requires the session to be locked (connection-wise) and not NULL.
*/
static void
bgp_msg_update_receive (bgp_connection connection, bgp_size_t body_size)
@@ -1354,7 +1360,10 @@ bgp_msg_update_receive (bgp_connection connection, bgp_size_t body_size)
"%s [Error] Update message received while in %s State",
connection->host, LOOKUP(bgp_status_msg, connection->state)) ;
return ;
- }
+ } ;
+
+ ++connection->session->stats.update_in ;
+ connection->session->stats.update_time = time(NULL) ;
/* PRO TEM: pass raw update message across to Peering Engine */
/* TODO: decode update messages in the BGP Engine. */
@@ -1363,10 +1372,14 @@ bgp_msg_update_receive (bgp_connection connection, bgp_size_t body_size)
/*==============================================================================
* BGP KEEPALIVE message
+ *
+ * NB: requires the session to be locked (connection-wise) and not NULL.
*/
static void
bgp_msg_keepalive_receive (bgp_connection connection, bgp_size_t body_size)
{
+ ++connection->session->stats.keepalive_in ;
+
if (BGP_DEBUG (keepalive, KEEPALIVE))
zlog_debug ("%s KEEPALIVE rcvd", connection->host);
@@ -1378,6 +1391,8 @@ bgp_msg_keepalive_receive (bgp_connection connection, bgp_size_t body_size)
/*==============================================================================
* BGP NOTIFICATION message
+ *
+ * NB: requires the session to be locked (connection-wise) and not NULL.
*/
static void
bgp_msg_notify_receive (bgp_connection connection, bgp_size_t body_size)
@@ -1385,6 +1400,8 @@ bgp_msg_notify_receive (bgp_connection connection, bgp_size_t body_size)
bgp_nom_code_t code = stream_getc (connection->ibuf);
bgp_nom_subcode_t subcode = stream_getc (connection->ibuf);
+ ++connection->session->stats.notify_in ;
+
bgp_fsm_notification_exception(connection,
bgp_notify_new_with_data(code, subcode,
stream_pnt(connection->ibuf), body_size - 2)) ;
@@ -1392,6 +1409,8 @@ bgp_msg_notify_receive (bgp_connection connection, bgp_size_t body_size)
/*==============================================================================
* BGP ROUTE-REFRESH message
+ *
+ * NB: requires the session to be locked (connection-wise) and not NULL.
*/
static int
bgp_msg_orf_recv(bgp_connection connection, bgp_route_refresh rr,
@@ -1414,6 +1433,8 @@ bgp_msg_route_refresh_receive(bgp_connection connection, bgp_size_t body_size)
unsigned form ;
int ret ;
+ ++connection->session->stats.refresh_in ;
+
/* If peer does not have the capability, treat as bad message type */
switch (connection->msg_type)
@@ -1684,7 +1705,7 @@ bgp_msg_orf_prefix_recv(orf_prefix orfpe, qafx_bit_t qb, sucker sr)
memset(&orfpe->p, 0, sizeof(struct prefix)) ;
- blen = blen = (plen + 7) / 8 ;
+ blen = (plen + 7) / 8 ;
if ((left -= blen) >= 0)
{
orfpe->p.family = paf ;
@@ -1704,9 +1725,13 @@ bgp_msg_orf_prefix_recv(orf_prefix orfpe, qafx_bit_t qb, sucker sr)
/*==============================================================================
* BGP CAPABILITY message -- Dynamic Capabilities
+ *
+ * NB: requires the session to be locked (connection-wise) and not NULL.
*/
static void bgp_msg_capability_receive(bgp_connection connection,
bgp_size_t body_size)
{
+ ++connection->session->stats.dynamic_cap_in ;
+
return ;
} ;
diff --git a/bgpd/bgp_msg_write.c b/bgpd/bgp_msg_write.c
index c0769578..c7b18bfe 100644
--- a/bgpd/bgp_msg_write.c
+++ b/bgpd/bgp_msg_write.c
@@ -78,6 +78,8 @@
* 1 => written to wbuff -- waiting for socket
* 0 => nothing written -- insufficient space in wbuff
* -1 => failed -- error event generated
+ *
+ * NB: requires the session LOCKED -- connection-wise
*/
extern int
bgp_msg_write_notification(bgp_connection connection, bgp_notify notification)
@@ -85,6 +87,8 @@ bgp_msg_write_notification(bgp_connection connection, bgp_notify notification)
struct stream *s = connection->obuf ;
int length;
+ ++connection->session->stats.notify_out ;
+
assert(notification != NULL) ;
/* Make NOTIFY message header */
@@ -156,6 +160,8 @@ bgp_msg_write_notification(bgp_connection connection, bgp_notify notification)
* 1 => written to wbuff -- waiting for socket
* 0 => nothing written -- insufficient space in wbuff
* -1 => failed -- error event generated
+ *
+ * NB: requires the session LOCKED -- connection-wise
*/
extern int
bgp_msg_send_keepalive(bgp_connection connection)
@@ -166,6 +172,8 @@ bgp_msg_send_keepalive(bgp_connection connection)
if (!bgp_connection_write_empty(connection))
return 0 ;
+ ++connection->session->stats.keepalive_out ;
+
/* Make KEEPALIVE message -- comprises header only */
bgp_packet_set_marker(s, BGP_MSG_KEEPALIVE);
length = bgp_packet_set_size(s);
@@ -204,6 +212,8 @@ bgp_open_capability_orf (struct stream *s, iAFI_t afi, iSAFI_t safi,
* 1 => written to wbuff -- waiting for socket
* 0 => nothing written -- wbuff was too full !!!
* -1 => failed -- error event generated
+ *
+ * NB: requires the session LOCKED -- connection-wise
*/
extern int
bgp_msg_send_open(bgp_connection connection, bgp_open_state open_state)
@@ -213,6 +223,8 @@ bgp_msg_send_open(bgp_connection connection, bgp_open_state open_state)
assert(bgp_connection_write_empty(connection)) ;
+ ++connection->session->stats.open_out ;
+
/* Make OPEN message header */
bgp_packet_set_marker(s, BGP_MSG_OPEN) ;
@@ -479,6 +491,8 @@ bgp_msg_orf_prefix(struct stream* s, uint8_t common,
* Returns: > 0 => all written
* 0 => unable to write everything
* < 0 => failed -- error event generated
+ *
+ * NB: requires the session LOCKED -- connection-wise
*/
extern int
bgp_msg_send_route_refresh(bgp_connection connection, bgp_route_refresh rr)
@@ -489,6 +503,8 @@ bgp_msg_send_route_refresh(bgp_connection connection, bgp_route_refresh rr)
bgp_size_t msg_len ;
int ret ;
+ ++connection->session->stats.refresh_out ;
+
msg_type = (connection->route_refresh == bgp_form_pre)
? BGP_MT_ROUTE_REFRESH_pre
: BGP_MT_ROUTE_REFRESH ;
@@ -767,6 +783,8 @@ bgp_msg_orf_prefix(struct stream* s, uint8_t common,
* 1 => written to wbuff -- waiting for socket
* 0 => nothing written -- insufficient space in wbuff
* -1 => failed -- error event generated
+ *
+ * NB: requires the session LOCKED -- connection-wise
*/
extern int
bgp_msg_send_update(bgp_connection connection, struct stream* s)
@@ -774,6 +792,8 @@ bgp_msg_send_update(bgp_connection connection, struct stream* s)
if (bgp_connection_write_full(connection))
return 0 ;
+ ++connection->session->stats.update_out ;
+
return bgp_connection_write(connection, s) ;
} ;
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index b5d66679..0c1072c9 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -27,13 +27,13 @@
#include "log.h"
#include "if.h"
#include "prefix.h"
-//#include "command.h"
#include "privs.h"
+#include "qpselect.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_peer_index.h"
-#include "bgpd/bgp_engine.h"
#include "bgpd/bgp_session.h"
#include "bgpd/bgp_connection.h"
#include "bgpd/bgp_fsm.h"
@@ -437,7 +437,6 @@ static void
bgp_accept_action(qps_file qf, void* file_info)
{
bgp_connection connection ;
- bgp_session session ;
union sockunion su_remote ;
union sockunion su_local ;
int exists ;
@@ -460,8 +459,8 @@ bgp_accept_action(qps_file qf, void* file_info)
inet_sutop(&su_remote, buf)) ;
/* See if we are ready to accept connections from the connecting party */
- session = bgp_session_index_seek(&su_remote, &exists) ;
- if (session != NULL)
+ connection = bgp_peer_index_seek_accept(&su_remote, &exists) ;
+ if (connection != NULL)
{
if (BGP_DEBUG(events, EVENTS))
zlog_debug(exists
@@ -484,7 +483,7 @@ bgp_accept_action(qps_file qf, void* file_info)
* except under the mutex, and will not destroy the session.
*/
- BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+ BGP_CONNECTION_SESSION_LOCK(connection) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
/* Set the common socket options.
* Does not set password -- that is inherited from the listener.
@@ -497,16 +496,15 @@ bgp_accept_action(qps_file qf, void* file_info)
ret = bgp_getsockname(fd, &su_local, &su_remote) ;
if (ret != 0)
- ret = bgp_socket_set_common_options(fd, &su_remote, session->ttl, NULL) ;
-
- connection = session->connections[bgp_connection_secondary] ;
+ ret = bgp_socket_set_common_options(fd, &su_remote,
+ connection->session->ttl, NULL) ;
if (ret == 0)
bgp_connection_open(connection, fd) ;
else
close(fd) ;
- BGP_SESSION_UNLOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+ BGP_CONNECTION_SESSION_UNLOCK(connection) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
/* Now kick the FSM in an appropriate fashion */
bgp_fsm_connect_completed(connection, ret, &su_local, &su_remote) ;
@@ -516,8 +514,8 @@ bgp_accept_action(qps_file qf, void* file_info)
* Open BGP Connection -- connect() to the other end
*/
-static int bgp_bind(bgp_connection connection) ;
-static int bgp_update_source (bgp_connection connection) ;
+static int bgp_bind_ifname(bgp_connection connection, int fd) ;
+static int bgp_bind_ifaddress(bgp_connection connection, int fd) ;
/*------------------------------------------------------------------------------
* Open BGP Connection -- connect() to the other end
@@ -534,7 +532,6 @@ static int bgp_update_source (bgp_connection connection) ;
extern void
bgp_open_connect(bgp_connection connection)
{
- unsigned int ifindex = 0 ;
int fd ;
int ret ;
union sockunion* su = connection->session->su_peer ;
@@ -550,18 +547,11 @@ bgp_open_connect(bgp_connection connection)
/* Bind socket. */
if (ret == 0)
- ret = bgp_bind(connection) ;
+ ret = bgp_bind_ifname(connection, fd) ;
/* Update source bind. */
if (ret == 0)
- ret = bgp_update_source(connection) ;
-
-#if 0 /* TODO: worry about peer->ifname and sessions ! */
-#ifdef HAVE_IPV6
- if (peer->ifname)
- ifindex = if_nametoindex(peer->ifname);
-#endif /* HAVE_IPV6 */
-#endif
+ ret = bgp_bind_ifaddress(connection, fd) ;
if (BGP_DEBUG(events, EVENTS))
plog_debug(connection->log, "%s [Event] Connect start to %s fd %d",
@@ -569,7 +559,8 @@ bgp_open_connect(bgp_connection connection)
/* Connect to the remote peer. */
if (ret == 0)
- ret = sockunion_connect(fd, su, connection->session->port, ifindex) ;
+ ret = sockunion_connect(fd, su, connection->session->port,
+ connection->session->ifindex) ;
/* does not report EINPROGRESS as an error. */
/* If not OK now, close the fd and signal the error */
@@ -669,6 +660,25 @@ bgp_connect_action(qps_file qf, void* file_info)
} ;
/*==============================================================================
+ * Set the TTL for the given connection (if any), if there is an fd.
+ */
+extern void
+bgp_set_ttl(bgp_connection connection, int ttl)
+{
+ int fd ;
+
+ if (connection == NULL)
+ return ;
+
+ fd = qps_file_fd(&connection->qf) ;
+ if (fd < 0)
+ return ;
+
+ if (ttl != 0)
+ sockopt_ttl(connection->paf, fd, ttl) ;
+} ;
+
+/*==============================================================================
* Get local and remote address and port for connection.
*/
static int
@@ -679,10 +689,6 @@ bgp_getsockname(int fd, union sockunion* su_local, union sockunion* su_remote)
ret_l = sockunion_getsockname(fd, su_local) ;
ret_r = sockunion_getpeername(fd, su_remote) ;
-#if 0 /* TODO: restore setting of peer->nexthop */
- bgp_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop, peer);
-#endif
-
return (ret_l != 0) ? ret_l : ret_r ;
} ;
@@ -691,9 +697,6 @@ bgp_getsockname(int fd, union sockunion* su_local, union sockunion* su_remote)
*
*/
-static struct in_addr* bgp_update_address (struct interface *ifp) ;
-static int bgp_bind_address (int sock, struct in_addr *addr) ;
-
/*------------------------------------------------------------------------------
* BGP socket bind.
*
@@ -705,34 +708,41 @@ static int bgp_bind_address (int sock, struct in_addr *addr) ;
* != 0 : error number (from errno or otherwise)
*/
static int
-bgp_bind(bgp_connection connection)
+bgp_bind_ifname(bgp_connection connection, int fd)
{
-#if 0 /* TODO: restore binding to specific interfaces */
#ifdef SO_BINDTODEVICE
- int ret;
+ int ret, retp ;
struct ifreq ifreq;
- if (! peer->ifname)
+ if (connection->session->ifname == NULL)
return 0;
- strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name));
+ strncpy ((char *)&ifreq.ifr_name, connection->session->ifname,
+ sizeof (ifreq.ifr_name));
- if ( bgpd_privs.change (ZPRIVS_RAISE) )
- zlog_err ("bgp_bind: could not raise privs");
+ ret = 0 ;
+ retp = 0 ;
+ if (bgpd_privs.change (ZPRIVS_RAISE))
+ {
+ zlog_err ("bgp_bind: could not raise privs");
+ retp = -1 ;
+ } ;
- ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE,
- &ifreq, sizeof (ifreq));
+ ret = setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof (ifreq));
if (bgpd_privs.change (ZPRIVS_LOWER) )
- zlog_err ("bgp_bind: could not lower privs");
+ {
+ zlog_err ("bgp_bind: could not lower privs");
+ retp = -1 ;
+ } ;
- if (ret < 0)
+ if ((ret < 0) || (retp < 0))
{
- zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname);
- return ret;
+ zlog (connection->log, LOG_INFO, "bind to interface %s failed",
+ connection->session->ifname);
+ return -1 ;
}
#endif /* SO_BINDTODEVICE */
-#endif
return 0;
} ;
@@ -743,93 +753,16 @@ bgp_bind(bgp_connection connection)
* != 0 : error number (from errno or otherwise)
*/
static int
-bgp_update_source (bgp_connection connection)
+bgp_bind_ifaddress(bgp_connection connection, int fd)
{
-#if 0 /* TODO: restore update-source handling */
- struct interface *ifp;
- struct in_addr *addr;
-
- /* Source is specified with interface name. */
- if (peer->update_if)
+ if (connection->session->ifaddress != NULL)
{
- ifp = if_lookup_by_name (peer->update_if);
- if (! ifp)
- return;
-
- addr = bgp_update_address (ifp);
- if (! addr)
- return;
-
- bgp_bind_address (peer->fd, addr);
- }
-
- /* Source is specified with IP address. */
- if (peer->update_source)
- sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source);
-#else
- return bgp_bind_address(0, bgp_update_address (NULL)) ;
- /* returns 0 -- avoid warnings */
-#endif
-} ;
-
-/*------------------------------------------------------------------------------
- * Bind given socket to given address... ???
- *
- */
-static int
-bgp_bind_address (int sock, struct in_addr *addr)
-{
-#if 0 /* TODO: restore update-source handling */
-
- int ret;
- struct sockaddr_in local;
-
- memset (&local, 0, sizeof (struct sockaddr_in));
- local.sin_family = AF_INET;
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- local.sin_len = sizeof(struct sockaddr_in);
-#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- memcpy (&local.sin_addr, addr, sizeof (struct in_addr));
-
- if ( bgpd_privs.change (ZPRIVS_RAISE) )
- zlog_err ("bgp_bind_address: could not raise privs");
-
- ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in));
- if (ret < 0)
- ;
-
- if (bgpd_privs.change (ZPRIVS_LOWER) )
- zlog_err ("bgp_bind_address: could not lower privs");
-
-#endif
- return 0;
+ union sockunion su = *(connection->session->ifaddress) ;
+ return sockunion_bind (fd, &su, 0, &su) ;
+ } ;
+ return 0 ;
} ;
-/*------------------------------------------------------------------------------
- * Update address.... ???
- *
- * Returns: address of IPv4 prefix
- * or: NULL
- */
-static struct in_addr *
-bgp_update_address (struct interface *ifp)
-{
-#if 0 /* TODO: restore update-source handling */
- struct prefix_ipv4 *p;
- struct connected *connected;
- struct listnode *node;
-
- for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
- {
- p = (struct prefix_ipv4 *) connected->address;
-
- if (p->family == AF_INET)
- return &p->prefix;
- }
-#endif
- return NULL;
-}
-
/*==============================================================================
* BGP Socket Option handling
*/
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
index 1edc2e0e..30ec3b19 100644
--- a/bgpd/bgp_network.h
+++ b/bgpd/bgp_network.h
@@ -39,4 +39,7 @@ bgp_prepare_to_accept(bgp_connection connection) ;
extern void
bgp_not_prepared_to_accept(bgp_connection connection) ;
+extern void
+bgp_set_ttl(bgp_connection connection, int ttl) ;
+
#endif /* _QUAGGA_BGP_NETWORK_H */
diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c
index dea87a74..dca9054d 100644
--- a/bgpd/bgp_peer.c
+++ b/bgpd/bgp_peer.c
@@ -51,6 +51,7 @@
#include "plist.h"
#include "mqueue.h"
#include "workqueue.h"
+#include "if.c"
#ifdef HAVE_SNMP
#include "bgpd/bgp_snmp.h"
@@ -164,6 +165,12 @@ bgp_session_has_established(bgp_peer peer)
/* update peer state from received open */
bgp_peer_open_state_receive(peer);
+ /* get the local and remote addresses, and set the nexthop. */
+
+ sockunion_set_dup(&peer->su_local, session->su_local) ;
+ sockunion_set_dup(&peer->su_remote, session->su_remote) ;
+ bgp_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop, peer) ;
+
/* Reset capability open status flag. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
@@ -1021,3 +1028,38 @@ peer_change_status (bgp_peer peer, int status)
LOOKUP (bgp_peer_status_msg, peer->ostate),
LOOKUP (bgp_peer_status_msg, peer->state));
}
+
+/*==============================================================================
+ * For the given interface name, get a suitable address so can bind() before
+ * connect() so that we use the required interface.
+ *
+ *
+ *
+ */
+extern sockunion
+bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, pAF_t paf)
+{
+ struct interface* ifp ;
+ struct connected* connected;
+ struct listnode* node;
+
+ if (ifname == NULL)
+ return NULL ;
+
+ ifp = if_lookup_by_name (peer->update_if) ;
+ if (ifp == NULL)
+ {
+ zlog_err("Peer %s interface %s is not known", peer->host, ifname) ;
+ return NULL ;
+ } ;
+
+ for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
+ {
+ if (connected->address->family == paf)
+ return sockunion_new(connected->address) ;
+ } ;
+
+ zlog_err("Peer %s interface %ss has no suitable address", peer->host, ifname);
+
+ return NULL ;
+} ;
diff --git a/bgpd/bgp_peer.h b/bgpd/bgp_peer.h
index 39a90a4e..d16de92d 100644
--- a/bgpd/bgp_peer.h
+++ b/bgpd/bgp_peer.h
@@ -480,5 +480,7 @@ peer_free (struct peer *peer);
extern void
peer_nsf_stop (struct peer *peer);
+extern sockunion
+bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, pAF_t paf) ;
#endif /* _QUAGGA_BGP_PEER_H */
diff --git a/bgpd/bgp_peer_index.c b/bgpd/bgp_peer_index.c
index 39b4f69e..72d3b17d 100644
--- a/bgpd/bgp_peer_index.c
+++ b/bgpd/bgp_peer_index.c
@@ -283,20 +283,20 @@ bgp_peer_index_seek_entry(union sockunion* su)
*
* For use by the BGP Engine.
*
- * Returns: bgp_session if: peer with given address is configured
- * and: the session is prepared to accept()
+ * Returns: bgp_connection 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 sets/clears the pointer to the session. The pointer is
- * initialised NULL when the index entry is created.
+ * NB: the BGP Engine sets/clears the pointer to the connection. The pointer
+ * is initialised NULL when the index entry is created.
*/
-extern bgp_session
-bgp_session_index_seek(union sockunion* su, int* p_found)
+extern bgp_connection
+bgp_peer_index_seek_accept(union sockunion* su, int* p_found)
{
- bgp_session accept ;
+ bgp_connection accept ;
bgp_peer_index_entry entry ;
BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
diff --git a/bgpd/bgp_peer_index.h b/bgpd/bgp_peer_index.h
index a77eab59..38d70907 100644
--- a/bgpd/bgp_peer_index.h
+++ b/bgpd/bgp_peer_index.h
@@ -53,7 +53,7 @@ struct bgp_peer_index_entry
* facilitate this.
*/
- bgp_session accept ; /* used by BGP Engine */
+ bgp_connection accept ; /* used by BGP Engine */
bgp_peer_id_t id ; /* maps IP address to peer_id */
} ;
@@ -83,13 +83,13 @@ extern void
bgp_peer_index_deregister(bgp_peer peer, union sockunion* su) ;
extern bgp_peer
-bgp_peer_index_seek(union sockunion* su) ;
+bgp_peer_index_seek(sockunion su) ;
extern bgp_peer_index_entry
-bgp_peer_index_seek_entry(union sockunion* su) ;
+bgp_peer_index_seek_entry(sockunion su) ;
-extern bgp_session
-bgp_session_index_seek(union sockunion* su, int* p_found) ;
+extern bgp_connection
+bgp_peer_index_seek_accept(sockunion su, int* p_found) ;
#endif /* _QUAGGA_BGP_PEER_INDEX_H */
diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c
index dcc338bf..936857c0 100644
--- a/bgpd/bgp_session.c
+++ b/bgpd/bgp_session.c
@@ -28,6 +28,7 @@
#include "bgpd/bgp_open_state.h"
#include "bgpd/bgp_route_refresh.h"
#include "bgpd/bgp_msg_write.h"
+#include "bgpd/bgp_network.h"
#include "bgpd/bgp_packet.h"
@@ -150,6 +151,10 @@ bgp_session_init_new(bgp_session session, bgp_peer peer)
* as_peer -- unset
* su_peer -- NULL -- none
*
+ * ifname -- NULL -- none
+ * ifindex -- 0 -- none
+ * ifaddress -- NULL -- none
+ *
* log -- NULL -- none
* host -- NULL -- none
* password -- NULL -- none
@@ -190,10 +195,16 @@ bgp_session_free(bgp_session session)
bgp_notify_free(session->notification);
bgp_open_state_free(session->open_send);
bgp_open_state_free(session->open_recv);
+ if (session->ifname != NULL)
+ free(session->ifname) ;
+ sockunion_unset(&session->ifaddress) ;
+ sockunion_unset(&session->su_peer) ;
if (session->host != NULL)
- XFREE(MTYPE_BGP_SESSION, session->host);
+ XFREE(MTYPE_BGP_PEER_HOST, session->host);
if (session->password != NULL)
- XFREE(MTYPE_BGP_SESSION, session->password);
+ XFREE(MTYPE_PEER_PASSWORD, session->password);
+ sockunion_unset(&session->su_local) ;
+ sockunion_unset(&session->su_remote) ;
/* Zeroize to catch dangling references asap */
memset(session, 0, sizeof(struct bgp_session)) ;
@@ -256,20 +267,38 @@ bgp_session_enable(bgp_peer peer)
session->ttl = peer->ttl ;
session->port = peer->port ;
+ if (session->ifname != NULL)
+ free(session->ifname) ;
+ session->ifindex = 0 ;
+
+ if (peer->ifname != NULL)
+ {
+ session->ifname = strdup(peer->ifname) ;
+ session->ifindex = if_nametoindex(peer->ifname) ;
+ } ;
+
+ sockunion_unset(&session->ifaddress) ;
+ if (peer->update_source != NULL)
+ session->ifaddress = sockunion_dup(peer->update_source) ;
+ else if (peer->update_if != NULL)
+ session->ifaddress = bgp_peer_get_ifaddress(peer, peer->update_if,
+ peer->su.sa.sa_family) ;
+
session->as_peer = peer->as ;
- session->su_peer = sockunion_dup(&peer->su) ;
+ sockunion_set_dup(&session->su_peer, &peer->su) ;
session->log = peer->log ;
/* take copies of host and password */
- XFREE(MTYPE_BGP_SESSION, session->host);
+ if (session->host != NULL)
+ XFREE(MTYPE_BGP_PEER_HOST, session->host);
session->host = (peer->host != NULL)
- ? XSTRDUP(MTYPE_BGP_SESSION, peer->host)
+ ? XSTRDUP(MTYPE_BGP_PEER_HOST, peer->host)
: NULL;
-
- XFREE(MTYPE_BGP_SESSION, session->password);
+ if (session->password != NULL)
+ XFREE(MTYPE_PEER_PASSWORD, session->password);
session->password = (peer->password != NULL)
- ? XSTRDUP(MTYPE_BGP_SESSION, peer->password)
+ ? XSTRDUP(MTYPE_PEER_PASSWORD, peer->password)
: NULL;
session->idle_hold_timer_interval = peer->v_start ;
@@ -890,9 +919,17 @@ bgp_session_do_set_ttl(mqueue_block mqb, mqb_flag_t flag)
if (flag == mqb_action)
{
- bgp_session session = mqb_get_arg0(mqb);
- struct bgp_session_ttl_args *args = mqb_get_args(mqb);
- /* TODO ttl */
+ bgp_session session = mqb_get_arg0(mqb) ;
+ struct bgp_session_ttl_args *args = mqb_get_args(mqb) ;
+
+ BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ session->ttl = args->ttl ;
+
+ bgp_set_ttl(session->connections[bgp_connection_primary], session->ttl) ;
+ bgp_set_ttl(session->connections[bgp_connection_secondary], session->ttl);
+
+ BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
}
mqb_free(mqb) ;
diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h
index e19b68b2..2813b454 100644
--- a/bgpd/bgp_session.h
+++ b/bgpd/bgp_session.h
@@ -74,7 +74,7 @@ struct bgp_session_stats
u_int32_t open_out; /* Open message output count */
u_int32_t update_in; /* Update message input count */
u_int32_t update_out; /* Update message ouput count */
- time_t update_time; /* Update message received time. */
+ time_t update_time; /* Update message received time. */
u_int32_t keepalive_in; /* Keepalive input count */
u_int32_t keepalive_out; /* Keepalive output count */
u_int32_t notify_in; /* Notify input count */
@@ -85,7 +85,6 @@ struct bgp_session_stats
u_int32_t dynamic_cap_out; /* Dynamic Capability output count. */
};
-
struct bgp_session
{
bgp_peer peer ; /* peer whose session this is */
@@ -164,6 +163,10 @@ struct bgp_session
int ttl ; /* TTL to set, if not zero */
unsigned short port ; /* destination port for peer */
+ char* ifname ; /* interface to bind to, if any */
+ unsigned ifindex ; /* and its index, if any */
+ union sockunion* ifaddress ; /* address to bind to, if any */
+
as_t as_peer ; /* ASN of the peer */
union sockunion* su_peer ; /* Sockunion address of the peer */
@@ -194,7 +197,7 @@ struct bgp_session
union sockunion* su_local ; /* set when session Established */
union sockunion* su_remote ; /* set when session Established */
- /* Statistics */
+ /* Statistics */
struct bgp_session_stats stats;
/* These values are are private to the BGP Engine.
diff --git a/lib/prefix.h b/lib/prefix.h
index 1ccd4dd6..9fd02ea6 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -29,6 +29,8 @@
#define Inline static inline
#endif
+typedef const union sockunion* const_sockunion ;
+
/*
* A struct prefix contains an address family, a prefix length, and an
* address. This can represent either a 'network prefix' as defined
@@ -163,9 +165,9 @@ extern int prefix_cmp (const struct prefix *, const struct prefix *);
extern void prefix_copy (struct prefix *dest, const struct prefix *src);
extern void apply_mask (struct prefix *);
-extern struct prefix *sockunion2prefix (const union sockunion *dest,
- const union sockunion *mask);
-extern struct prefix *sockunion2hostprefix (const union sockunion *);
+extern struct prefix *sockunion2prefix (const_sockunion dest,
+ const_sockunion mask);
+extern struct prefix *sockunion2hostprefix (const_sockunion src);
extern struct prefix_ipv4 *prefix_ipv4_new (void);
extern void prefix_ipv4_free (struct prefix_ipv4 *);
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 700d539f..bfcadc96 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -735,6 +735,37 @@ sockunion_free (union sockunion *su)
* Sockunion reference utilities
*/
+extern sockunion
+sockunion_new(struct prefix* p)
+{
+ sockunion nsu = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)) ;
+
+ if (p == NULL)
+ return NULL ;
+
+ switch (p->family)
+ {
+ case AF_INET:
+ nsu->sin.sin_family = AF_INET ;
+ nsu->sin.sin_port = 0 ;
+ nsu->sin.sin_addr = p->u.prefix4 ;
+ break ;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ nsu->sin6.sin6_family = AF_INET ;
+ nsu->sin6.sin6_port = 0 ;
+ nsu->sin6.sin6_addr = p->u.prefix6 ;
+ break ;
+#endif
+
+ default:
+ break ;
+ } ;
+
+ return nsu ;
+} ;
+
/*------------------------------------------------------------------------------
* Unset pointer to sockunion -- free any sockunion referenced
*
@@ -744,7 +775,7 @@ extern void
sockunion_unset(sockunion* p_su)
{
if (*p_su != NULL)
- XFREE(MTYPE_BGP_NOTIFY, *p_su) ; /* sets *p_su NULL */
+ XFREE(MTYPE_SOCKUNION, *p_su) ; /* sets *p_su NULL */
} ;
/*------------------------------------------------------------------------------
diff --git a/lib/sockunion.h b/lib/sockunion.h
index c00c02e4..ea76a955 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -25,6 +25,7 @@
#include "zebra.h"
#include "symtab.h"
+#include "prefix.h"
#if 0
union sockunion {
@@ -41,6 +42,8 @@ union sockunion {
#define su_port su_si.si_port
#endif /* 0 */
+typedef struct prefix* prefix ;
+
typedef union sockunion* sockunion ;
union sockunion
{
@@ -120,6 +123,7 @@ extern int sockunion_getpeername (int, union sockunion*);
extern union sockunion *sockunion_dup (union sockunion *);
extern void sockunion_free (union sockunion *);
+extern sockunion sockunion_new(prefix p) ;
extern void sockunion_unset(sockunion* p_su) ;
extern void sockunion_set(sockunion* p_dst, sockunion su) ;
extern void sockunion_set_dup(sockunion* p_dst, sockunion su) ;