summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_network.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_network.c')
-rw-r--r--bgpd/bgp_network.c139
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);