/* This function is the first starting point of all BGP connection. It try to connect to remote peer with non-blocking IO. */ int bgp_start (struct peer *peer) { int status; /* If the peer is passive mode, force to move to Active mode. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) { BGP_EVENT_ADD (peer, TCP_connection_open_failed); return 0; } status = bgp_connect (peer); switch (status) { case connect_error: if (BGP_DEBUG (fsm, FSM)) plog_info (peer->log, "%s [FSM] Connect error", peer->host); BGP_EVENT_ADD (peer, TCP_connection_open_failed); break; case connect_success: if (BGP_DEBUG (fsm, FSM)) plog_info (peer->log, "%s [FSM] Connect immediately success", peer->host); BGP_EVENT_ADD (peer, TCP_connection_open); break; case connect_in_progress: /* To check nonblocking connect, we wait until socket is readable or writable. */ if (BGP_DEBUG (fsm, FSM)) plog_info (peer->log, "%s [FSM] Non blocking connect waiting result", peer->host); if (peer->fd < 0) { zlog_err ("bgp_start peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); break; } return 0; }
static int bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct interface *ifp; struct connected *c; struct listnode *node, *nnode; s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (! ifp) return 0; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra rcvd: interface %s down", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_delete (c); /* Fast external-failover (Currently IPv4 only) */ { struct listnode *mnode; struct bgp *bgp; struct peer *peer; struct interface *peer_if; for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp)) { if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) continue; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->ttl != 1) continue; if (peer->su.sa.sa_family == AF_INET) peer_if = if_lookup_by_ipv4 (&peer->su.sin.sin_addr); else continue; if (ifp == peer_if) BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; }
static int bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct interface *ifp; struct connected *c; struct listnode *node, *nnode; s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (! ifp) return 0; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra rcvd: interface %s down", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_delete (c); /* Fast external-failover */ { struct listnode *mnode; struct bgp *bgp; struct peer *peer; for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp)) { if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) continue; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if ((peer->ttl != 1) && (peer->gtsm_hops != 1)) continue; if (ifp == peer->nexthop.ifp) BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; }
/* Called after event occured, this function change status and reset read/write and timer thread. */ void bgp_fsm_change_status (struct peer *peer, int status) { bgp_dump_state (peer, peer->status, status); /* Transition into Clearing or Deleted must /always/ clear all routes.. * (and must do so before actually changing into Deleted.. */ if (status >= Clearing) { bgp_clear_route_all (peer); /* If no route was queued for the clear-node processing, generate the * completion event here. This is needed because if there are no routes * to trigger the background clear-node thread, the event won't get * generated and the peer would be stuck in Clearing. Note that this * event is for the peer and helps the peer transition out of Clearing * state; it should not be generated per (AFI,SAFI). The event is * directly posted here without calling clear_node_complete() as we * shouldn't do an extra unlock. This event will get processed after * the state change that happens below, so peer will be in Clearing * (or Deleted). */ if (!work_queue_is_scheduled (peer->clear_node_queue)) BGP_EVENT_ADD (peer, Clearing_Completed); } /* Preserve old status and change into new status. */ peer->ostatus = peer->status; peer->status = status; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s went from %s to %s", peer->host, LOOKUP (bgp_status_msg, peer->ostatus), LOOKUP (bgp_status_msg, peer->status)); }
/* Accept bgp connection. */ static int bgp_accept (struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct bgp_listener *listener = THREAD_ARG(thread); struct peer *peer; struct peer *peer1; char buf[SU_ADDRSTRLEN]; /* Register accept thread. */ accept_sock = THREAD_FD (thread); if (accept_sock < 0) { zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock); /* Accept client connection. */ bgp_sock = sockunion_accept (accept_sock, &su); if (bgp_sock < 0) { zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno)); return -1; } set_nonblocking (bgp_sock); /* 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 (BGP_DEBUG (events, EVENTS)) { 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)); } close (bgp_sock); return -1; } 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"); { char buf[SU_ADDRSTRLEN]; 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; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); } BGP_EVENT_ADD (peer, TCP_connection_open); return 0; }
/* Accept bgp connection. */ static int bgp_accept (struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct peer *peer; struct peer *peer1; struct bgp *bgp; char buf[SU_ADDRSTRLEN]; /* Regiser accept thread. */ accept_sock = THREAD_FD (thread); bgp = THREAD_ARG (thread); if (accept_sock < 0) { zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } thread_add_read (master, bgp_accept, bgp, accept_sock); /* Accept client connection. */ bgp_sock = sockunion_accept (accept_sock, &su); if (bgp_sock < 0) { zlog_err ("[Error] BGP socket accept failed (%s)", strerror (errno)); return -1; } if (BGP_DEBUG (events, EVENTS)) zlog_info ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); /* Check remote IP address */ peer1 = peer_lookup (bgp, &su); if (! peer1 || peer1->status == Idle) { if (BGP_DEBUG (events, EVENTS)) { if (! peer1) zlog_info ("[Event] BGP connection IP address %s is not configured", inet_sutop (&su, buf)); else zlog_info ("[Event] BGP connection IP address %s is Idle state", inet_sutop (&su, buf)); } close (bgp_sock); return -1; } /* In case of peer is EBGP, we should set TTL for this connection. */ if (peer_sort (peer1) == BGP_PEER_EBGP) sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); if (! bgp) bgp = peer1->bgp; /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) zlog_info ("[Event] Make dummy peer structure until read Open packet"); { char buf[SU_ADDRSTRLEN + 1]; peer = peer_create_accept (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; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = strdup (buf); } BGP_EVENT_ADD (peer, TCP_connection_open); return 0; }
/* Accept bgp connection. */ static int bgp_accept(struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct bgp_listener *listener = THREAD_ARG(thread); struct peer *peer; struct peer *peer1; char buf[SU_ADDRSTRLEN]; struct bgp *bgp = NULL; sockunion_init(&su); /* Register accept thread. */ accept_sock = THREAD_FD(thread); if (accept_sock < 0) { flog_err_sys(EC_LIB_SOCKET, "accept_sock is nevative value %d", accept_sock); return -1; } listener->thread = NULL; thread_add_read(bm->master, bgp_accept, listener, accept_sock, &listener->thread); /* Accept client connection. */ bgp_sock = sockunion_accept(accept_sock, &su); if (bgp_sock < 0) { flog_err_sys(EC_LIB_SOCKET, "[Error] BGP socket accept failed (%s)", safe_strerror(errno)); return -1; } set_nonblocking(bgp_sock); /* Obtain BGP instance this connection is meant for. * - if it is a VRF netns sock, then BGP is in listener structure * - otherwise, the bgp instance need to be demultiplexed */ if (listener->bgp) bgp = listener->bgp; else if (bgp_get_instance_for_inc_conn(bgp_sock, &bgp)) { if (bgp_debug_neighbor_events(NULL)) zlog_debug( "[Event] Could not get instance for incoming conn from %s", inet_sutop(&su, buf)); close(bgp_sock); return -1; } /* Set socket send buffer size */ setsockopt_so_sendbuf(bgp_sock, BGP_SOCKET_SNDBUF_SIZE); /* Check remote IP address */ peer1 = peer_lookup(bgp, &su); if (!peer1) { peer1 = peer_lookup_dynamic_neighbor(bgp, &su); if (peer1) { /* Dynamic neighbor has been created, let it proceed */ peer1->fd = bgp_sock; bgp_fsm_change_status(peer1, Active); BGP_TIMER_OFF( peer1->t_start); /* created in peer_create() */ if (peer_active(peer1)) BGP_EVENT_ADD(peer1, TCP_connection_open); return 0; } } if (!peer1) { if (bgp_debug_neighbor_events(NULL)) { zlog_debug( "[Event] %s connection rejected - not configured" " and not valid for dynamic", 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; } /* Check that at least one AF is activated for the peer. */ if (!peer_active(peer1)) { if (bgp_debug_neighbor_events(peer1)) zlog_debug( "%s - incoming conn rejected - no AF activated for peer", peer1->host); close(bgp_sock); return -1; } if (bgp_debug_neighbor_events(peer1)) zlog_debug("[Event] BGP connection from host %s fd %d", inet_sutop(&su, buf), bgp_sock); 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); } if (bgp_set_socket_ttl(peer1, bgp_sock) < 0) if (bgp_debug_neighbor_events(peer1)) zlog_debug( "[Event] Unable to set min/max TTL on peer %s, Continuing", peer1->host); peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as, peer1->as, peer1->as_type, 0, 0, NULL); hash_release(peer->bgp->peerhash, peer); hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); peer_xfer_config(peer, peer1); UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); peer->doppelganger = peer1; peer1->doppelganger = peer; peer->fd = bgp_sock; vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer)); bgp_fsm_change_status(peer, Active); BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */ SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); /* 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; }
/* This function is the first starting point of all BGP connection. It try to connect to remote peer with non-blocking IO. */ int bgp_start (struct peer *peer) { int status; if (BGP_PEER_START_SUPPRESSED (peer)) { if (BGP_DEBUG (fsm, FSM)) plog_err (peer->log, "%s [FSM] Trying to start suppressed peer" " - this is never supposed to happen!", peer->host); return -1; } /* Scrub some information that might be left over from a previous, * session */ /* Connection information. */ if (peer->su_local) { sockunion_free (peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { sockunion_free (peer->su_remote); peer->su_remote = NULL; } /* Clear remote router-id. */ peer->remote_id.s_addr = 0; /* Clear peer capability flag. */ peer->cap = 0; /* If the peer is passive mode, force to move to Active mode. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) { BGP_EVENT_ADD (peer, TCP_connection_open_failed); return 0; } status = bgp_connect (peer); switch (status) { case connect_error: if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Connect error", peer->host); BGP_EVENT_ADD (peer, TCP_connection_open_failed); break; case connect_success: if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Connect immediately success", peer->host); BGP_EVENT_ADD (peer, TCP_connection_open); break; case connect_in_progress: /* To check nonblocking connect, we wait until socket is readable or writable. */ if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Non blocking connect waiting result", peer->host); if (peer->fd < 0) { zlog_err ("bgp_start peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); break; } return 0; }
/* Accept bgp connection. */ static int bgp_accept (struct thread *thread) { int bgp_sock; //socket used for BGP connection int accept_sock; union sockunion su; struct bgp_listener *listener = THREAD_ARG(thread); struct peer *peer; struct peer *peer1; char buf[SU_ADDRSTRLEN]; /* Register accept thread to accept connections from a client */ accept_sock = THREAD_FD (thread); if (accept_sock < 0) { zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } /*creating a new reading thread*/ listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock); /* -------------------------------------------------- * - BGP ACCEPT - * -------------------------------------------------- * */ printf("\n BGP ACCEPT: About to initialise SSL \n"); ssl_init(); //initialise the library, method, contact of ssl session, returns nothing printf("\n BGP ACCEPT: About to do socket call \n"); bgp_sock = sockunion_accept (accept_sock, &su); SSL_accept(BGPoTLS->ssl); if (bgp_sock < 0) { zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno)); return -1; } set_nonblocking (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 (BGP_DEBUG (events, EVENTS)) { 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)); } close (bgp_sock); return -1; } /* In case of peer is EBGP, we should set TTL for this connection. */ if (peer1->sort == BGP_PEER_EBGP) { sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); if (peer1->gtsm_hops) sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops); } /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] Make dummy peer structure until read Open packet"); { char buf[SU_ADDRSTRLEN]; 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; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); } BGP_EVENT_ADD (peer, TCP_connection_open); return 0; }