diff options
author | Chris Hall <GMCH@hestia.halldom.com> | 2010-01-27 22:37:55 +0000 |
---|---|---|
committer | Chris Hall <GMCH@hestia.halldom.com> | 2010-01-27 22:37:55 +0000 |
commit | e29ed2adec0ef11ca1c84b40b2c98247f162f3df (patch) | |
tree | d0a65837f2a544c8e46f8ddda654e70686c531a1 | |
parent | e6d986058f23f350aa6aedac4da5fe9f3afda6e8 (diff) | |
download | quagga-e29ed2adec0ef11ca1c84b40b2c98247f162f3df.tar.bz2 quagga-e29ed2adec0ef11ca1c84b40b2c98247f162f3df.tar.xz |
Binding to interfaces and counting of messages.
Wired up message counters in bgp_session structure.
Added fields to session for neighbor interface and
neighbor update-source -- so that these can be set when connect()
is done. Peering Engine resolves any interface name to an address,
so that BGP Engine doesn't have to.
Reinstated as much code as necessary in bgp_network to bind to
specific interfaces, as set in the session.
Moved setting of bgp_nexthop_set() back into Routeing Engine.
Result is that only Peering Engine talks to Zebra or uses the
iflist.
Wired up setting of TTL.
Reworked connections locking of the session mutex so more robust
if/when connections are cut loose from the session.
Made peer_index entry point at connection, not session. Works
better in bgp_network that way.
modified: bgpd/bgp_connection.c
modified: bgpd/bgp_connection.h
modified: bgpd/bgp_fsm.c
modified: bgpd/bgp_msg_read.c
modified: bgpd/bgp_msg_write.c
modified: bgpd/bgp_network.c
modified: bgpd/bgp_network.h
modified: bgpd/bgp_peer.c
modified: bgpd/bgp_peer.h
modified: bgpd/bgp_peer_index.c
modified: bgpd/bgp_peer_index.h
modified: bgpd/bgp_session.c
modified: bgpd/bgp_session.h
modified: lib/prefix.h
modified: lib/sockunion.c
modified: lib/sockunion.h
-rw-r--r-- | bgpd/bgp_connection.c | 57 | ||||
-rw-r--r-- | bgpd/bgp_connection.h | 25 | ||||
-rw-r--r-- | bgpd/bgp_fsm.c | 38 | ||||
-rw-r--r-- | bgpd/bgp_msg_read.c | 29 | ||||
-rw-r--r-- | bgpd/bgp_msg_write.c | 20 | ||||
-rw-r--r-- | bgpd/bgp_network.c | 187 | ||||
-rw-r--r-- | bgpd/bgp_network.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_peer.c | 42 | ||||
-rw-r--r-- | bgpd/bgp_peer.h | 2 | ||||
-rw-r--r-- | bgpd/bgp_peer_index.c | 14 | ||||
-rw-r--r-- | bgpd/bgp_peer_index.h | 10 | ||||
-rw-r--r-- | bgpd/bgp_session.c | 59 | ||||
-rw-r--r-- | bgpd/bgp_session.h | 9 | ||||
-rw-r--r-- | lib/prefix.h | 8 | ||||
-rw-r--r-- | lib/sockunion.c | 33 | ||||
-rw-r--r-- | lib/sockunion.h | 4 |
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 1a1d95de..32de0fd9 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) ; |