diff options
Diffstat (limited to 'bgpd')
-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 |
13 files changed, 312 insertions, 183 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. |