diff options
Diffstat (limited to 'bgpd/bgp_network.c')
-rw-r--r-- | bgpd/bgp_network.c | 139 |
1 files changed, 97 insertions, 42 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 51a6f602..283fa344 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "filter.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_open.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" @@ -67,8 +68,7 @@ bgp_md5_set_socket (int socket, union sockunion *su, const char *password) #endif /* HAVE_TCP_MD5SIG */ if (ret < 0) - zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s", - socket, safe_strerror (en)); + zlog_warn ("can't set TCP_MD5SIG option on socket %d: %s", socket, safe_strerror (en)); return ret; } @@ -150,7 +150,7 @@ static void bgp_set_socket_ttl (struct peer *peer, int bgp_sock) { char buf[INET_ADDRSTRLEN]; - int ret; + int ret = 0; /* In case of peer is EBGP, we should set TTL for this connection. */ if (!peer->gtsm_hops && (peer_sort (peer) == BGP_PEER_EBGP)) @@ -222,50 +222,90 @@ bgp_accept (struct thread *thread) /* Set socket send buffer size */ bgp_update_sock_send_buffer_size(bgp_sock); - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); - /* Check remote IP address */ peer1 = peer_lookup (NULL, &su); - if (! peer1 || peer1->status == Idle) + if (! peer1) { - if (BGP_DEBUG (events, EVENTS)) + if (bgp_debug_neighbor_events(NULL)) { - if (! peer1) - zlog_debug ("[Event] BGP connection IP address %s is not configured", - inet_sutop (&su, buf)); - else - zlog_debug ("[Event] BGP connection IP address %s is Idle state", - inet_sutop (&su, buf)); + zlog_debug ("[Event] BGP connection IP address %s is not configured", + inet_sutop (&su, buf)); } close (bgp_sock); return -1; } + if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN)) + { + if (bgp_debug_neighbor_events(peer1)) + zlog_debug ("[Event] connection from %s rejected due to admin shutdown", + inet_sutop (&su, buf)); + close (bgp_sock); + return -1; + } + + /* + * Do not accept incoming connections in Clearing state. This can result + * in incorect state transitions - e.g., the connection goes back to + * Established and then the Clearing_Completed event is generated. Also, + * block incoming connection in Deleted state. + */ + if (peer1->status == Clearing || peer1->status == Deleted) + { + if (bgp_debug_neighbor_events(peer1)) + zlog_debug("[Event] Closing incoming conn for %s (%p) state %d", + peer1->host, peer1, peer1->status); + close (bgp_sock); + return -1; + } + + if (bgp_debug_neighbor_events(peer1)) + zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); + + if (peer1->doppelganger) + { + /* We have an existing connection. Kill the existing one and run + with this one. + */ + if (bgp_debug_neighbor_events(peer1)) + zlog_debug ("[Event] New active connection from peer %s, Killing" + " previous active connection", peer1->host); + peer_delete(peer1->doppelganger); + } + bgp_set_socket_ttl (peer1, bgp_sock); - /* Make dummy peer until read Open packet. */ - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("[Event] Make dummy peer structure until read Open packet"); + peer = peer_create (&su, peer1->conf_if, peer1->bgp, peer1->local_as, + peer1->as, 0, 0); - { - char buf[SU_ADDRSTRLEN]; + peer_xfer_config(peer, peer1); + UNSET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE); - peer = peer_create_accept (peer1->bgp); - SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); - peer->su = su; - peer->fd = bgp_sock; - peer->status = Active; - peer->local_id = peer1->local_id; - peer->v_holdtime = peer1->v_holdtime; - peer->v_keepalive = peer1->v_keepalive; + peer->doppelganger = peer1; + peer1->doppelganger = peer; + peer->fd = bgp_sock; + bgp_fsm_change_status(peer, Active); + BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */ - /* Make peer's address string. */ - sockunion2str (&su, buf, SU_ADDRSTRLEN); - peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); - } + SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); - BGP_EVENT_ADD (peer, TCP_connection_open); + /* Make dummy peer until read Open packet. */ + if (peer1->status == Established && + CHECK_FLAG (peer1->sflags, PEER_STATUS_NSF_MODE)) + { + /* If we have an existing established connection with graceful restart + * capability announced with one or more address families, then drop + * existing established connection and move state to connect. + */ + peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; + SET_FLAG (peer1->sflags, PEER_STATUS_NSF_WAIT); + bgp_event_update(peer1, TCP_connection_closed); + } + + if (peer_active (peer)) + { + BGP_EVENT_ADD (peer, TCP_connection_open); + } return 0; } @@ -278,11 +318,14 @@ bgp_bind (struct peer *peer) int ret; struct ifreq ifreq; int myerrno; + char *name; - if (! peer->ifname) + if (! peer->ifname && !peer->conf_if) return 0; - strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name)); + name = (peer->conf_if ? peer->conf_if : peer->ifname); + + strncpy ((char *)&ifreq.ifr_name, name, sizeof (ifreq.ifr_name)); if ( bgpd_privs.change (ZPRIVS_RAISE) ) zlog_err ("bgp_bind: could not raise privs"); @@ -296,8 +339,8 @@ bgp_bind (struct peer *peer) if (ret < 0) { - zlog (peer->log, LOG_INFO, "bind to interface %s failed, errno=%d", - peer->ifname, myerrno); + zlog_info ("bind to interface %s failed, errno=%d", + name, myerrno); return ret; } #endif /* SO_BINDTODEVICE */ @@ -367,6 +410,11 @@ bgp_connect (struct peer *peer) { ifindex_t ifindex = 0; + if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer)) + { + zlog_debug("Peer address not learnt: Returning from connect"); + return 0; + } /* Make socket for the peer. */ peer->fd = sockunion_socket (&peer->su); if (peer->fd < 0) @@ -402,19 +450,19 @@ bgp_connect (struct peer *peer) /* Update source bind. */ bgp_update_source (peer); - if (peer->ifname) - ifindex = ifname2ifindex (peer->ifname); + if (peer->conf_if || peer->ifname) + ifindex = ifname2ifindex (peer->conf_if ? peer->conf_if : peer->ifname); - if (BGP_DEBUG (events, EVENTS)) - plog_debug (peer->log, "%s [Event] Connect start to %s fd %d", - peer->host, peer->host, peer->fd); + if (bgp_debug_neighbor_events(peer)) + zlog_debug ("%s [Event] Connect start to %s fd %d", + peer->host, peer->host, peer->fd); /* Connect to the remote peer. */ return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex); } /* After TCP connection is established. Get local address and port. */ -void +int bgp_getsockname (struct peer *peer) { if (peer->su_local) @@ -430,9 +478,13 @@ bgp_getsockname (struct peer *peer) } peer->su_local = sockunion_getsockname (peer->fd); + if (!peer->su_local) return -1; peer->su_remote = sockunion_getpeername (peer->fd); + if (!peer->su_remote) return -1; bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer); + + return 0; } @@ -548,6 +600,9 @@ bgp_close (void) struct listnode *node, *next; struct bgp_listener *listener; + if (bm->listen_sockets == NULL) + return; + for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener)) { thread_cancel (listener->thread); |