/* Execute event process. */ int bgp_event (struct thread *thread) { int ret; int event; int next; struct peer *peer; peer = THREAD_ARG (thread); event = THREAD_VAL (thread); /* Logging this event. */ next = FSM [peer->status -1][event - 1].next_state; if (BGP_DEBUG (fsm, FSM)) plog_info (peer->log, "%s [FSM] %s (%s->%s)", peer->host, bgp_event_str[event], LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next)); if (BGP_DEBUG (normal, NORMAL) && strcmp (LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next))) zlog_info ("%s went from %s to %s", peer->host, LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next)); /* Call function. */ ret = (*(FSM [peer->status - 1][event - 1].func))(peer); /* When function do not want proceed next job return -1. */ if (ret < 0) return ret; /* If status is changed. */ if (next != peer->status) bgp_fsm_change_status (peer, next); /* Make sure timer is set. */ bgp_timer_set (peer); return 0; }
/* Execute event process. */ int bgp_event (struct thread *thread) { int ret = 0; int event; int next; struct peer *peer; peer = THREAD_ARG (thread); event = THREAD_VAL (thread); /* Logging this event. */ next = FSM [peer->status -1][event - 1].next_state; if (BGP_DEBUG (fsm, FSM) && peer->status != next) plog_debug (peer->log, "%s [FSM] %s (%s->%s)", peer->host, bgp_event_str[event], LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next)); /* Call function. */ if (FSM [peer->status -1][event - 1].func) ret = (*(FSM [peer->status - 1][event - 1].func))(peer); /* When function do not want proceed next job return -1. */ if (ret >= 0) { /* If status is changed. */ if (next != peer->status) bgp_fsm_change_status (peer, next); /* Make sure timer is set. */ bgp_timer_set (peer); } return ret; }
/* 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; }
/* Status goes to Established. Send keepalive packet then make first update information. */ static int bgp_establish (struct peer *peer) { struct bgp_notify *notify; afi_t afi; safi_t safi; int nsf_af_count = 0; /* Reset capability open status flag. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)) SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); /* Clear last notification data. */ notify = &peer->notify; if (notify->data) XFREE (MTYPE_TMP, notify->data); memset (notify, 0, sizeof (struct bgp_notify)); /* Clear start timer value to default. */ peer->v_start = BGP_INIT_START_TIMER; /* Increment established count. */ peer->established++; bgp_fsm_change_status (peer, Established); /* bgp log-neighbor-changes of neighbor Up */ if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host); /* graceful restart */ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) { if (peer->afc_nego[afi][safi] && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV) && CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV)) { if (peer->nsf[afi][safi] && ! CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV)) bgp_clear_stale_route (peer, afi, safi); peer->nsf[afi][safi] = 1; nsf_af_count++; } else { if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); peer->nsf[afi][safi] = 0; } } if (nsf_af_count) SET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); else { UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); if (peer->t_gr_stale) { BGP_TIMER_OFF (peer->t_gr_stale); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart stalepath timer stopped", peer->host); } } if (peer->t_gr_restart) { BGP_TIMER_OFF (peer->t_gr_restart); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart timer stopped", peer->host); } #ifdef HAVE_SNMP bgpTrapEstablished (peer); #endif /* HAVE_SNMP */ /* Reset uptime, send keepalive, send current table. */ peer->uptime = bgp_clock (); /* Send route-refresh when ORF is enabled */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)) { if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX, REFRESH_IMMEDIATE, 0); else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD, REFRESH_IMMEDIATE, 0); } if (peer->v_keepalive) bgp_keepalive_send (peer); /* First update is deferred until ORF or ROUTE-REFRESH is received */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)) if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)) SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); bgp_announce_route_all (peer); BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1); return 0; }
/* Administrative BGP peer stop event. */ int bgp_stop (struct peer *peer) { afi_t afi; safi_t safi; char orf_name[BUFSIZ]; if (CHECK_FLAG (peer->sflags, PEER_STATUS_CREATE_INIT)) return 0; /* Increment Dropped count. */ if (peer->status == Established) { bgp_fsm_change_status (peer, Idle); peer->dropped++; /* bgp log-neighbor-changes of neighbor Down */ if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host, peer_down_str [(int) peer->last_reset]); /* graceful restart */ if (peer->t_gr_stale) { BGP_TIMER_OFF (peer->t_gr_stale); if (BGP_DEBUG (events, EVENTS)) zlog_info ("%s graceful restart stalepath timer stopped", peer->host); } if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) { if (BGP_DEBUG (events, EVENTS)) { zlog_info ("%s graceful restart timer started for %d sec", peer->host, peer->v_gr_restart); zlog_info ("%s graceful restart stalepath timer started for %d sec", peer->host, peer->bgp->stalepath_time); } BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire, peer->v_gr_restart); BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire, peer->bgp->stalepath_time); } else { UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) peer->nsf[afi][safi] = 0; } /* set last reset time */ peer->resettime = time (NULL); #ifdef HAVE_SNMP bgpTrapBackwardTransition (peer); #endif /* HAVE_SNMP */ /* Reset uptime. */ bgp_uptime_reset (peer); /* Need of clear of peer. */ bgp_clear_route_all (peer); /* Reset peer synctime */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) peer->synctime[afi][safi] = 0; } /* Stop read and write threads when exists. */ BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); /* Stop all timers. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); /* Delete all existing events of the peer. */ BGP_EVENT_DELETE (peer); /* Stream reset. */ peer->packet_size = 0; /* Clear input and output buffer. */ if (peer->ibuf) stream_reset (peer->ibuf); if (peer->work) stream_reset (peer->work); stream_fifo_clean (peer->obuf); /* Close of file descriptor. */ if (peer->fd >= 0) { close (peer->fd); peer->fd = -1; } /* Connection information. */ if (peer->su_local) { XFREE (MTYPE_SOCKUNION, peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { XFREE (MTYPE_SOCKUNION, peer->su_remote); peer->su_remote = NULL; } /* Clear remote router-id. */ peer->remote_id.s_addr = 0; /* Clear peer capability flag. */ peer->cap = 0; for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) { /* Reset all negotiated variables */ peer->afc_nego[afi][safi] = 0; peer->afc_adv[afi][safi] = 0; peer->afc_recv[afi][safi] = 0; /* peer address family capability flags*/ peer->af_cap[afi][safi] = 0; /* peer address family status flags*/ peer->af_sflags[afi][safi] = 0; /* Received ORF prefix-filter */ peer->orf_plist[afi][safi] = NULL; /* ORF received prefix-filter pnt */ sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); prefix_bgp_orf_remove_all (orf_name); } /* Reset keepalive and holdtime */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) { peer->v_keepalive = peer->keepalive; peer->v_holdtime = peer->holdtime; } else { peer->v_keepalive = peer->bgp->default_keepalive; peer->v_holdtime = peer->bgp->default_holdtime; } peer->update_time = 0; /* Until we are sure that there is no problem about prefix count this should be commented out.*/ #if 0 /* Reset prefix count */ peer->pcount[AFI_IP][SAFI_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; #endif /* 0 */ return 0; }
/* Administrative BGP peer stop event. */ int bgp_stop (struct peer *peer) { int established = 0; afi_t afi; safi_t safi; char orf_name[BUFSIZ]; /* Increment Dropped count. */ if (peer->status == Established) { established = 1; peer->dropped++; bgp_fsm_change_status (peer, Idle); #ifdef HAVE_SNMP bgpTrapBackwardTransition (peer); #endif /* HAVE_SNMP */ } /* Reset uptime. */ bgp_uptime_reset (peer); /* Need of clear of peer. */ if (established) bgp_clear_route_all (peer); /* Stop read and write threads when exists. */ BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); /* Stop all timers. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); /* Delete all existing events of the peer. */ BGP_EVENT_DELETE (peer); /* Stream reset. */ peer->packet_size = 0; /* Clear input and output buffer. */ if (peer->ibuf) stream_reset (peer->ibuf); if (peer->work) stream_reset (peer->work); stream_fifo_clean (peer->obuf); /* Close of file descriptor. */ if (peer->fd >= 0) { close (peer->fd); peer->fd = -1; } /* Connection information. */ if (peer->su_local) { XFREE (MTYPE_SOCKUNION, peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { XFREE (MTYPE_SOCKUNION, peer->su_remote); peer->su_remote = NULL; } /* Clear remote router-id. */ peer->remote_id.s_addr = 0; /* Reset all negotiated variables */ peer->afc_nego[AFI_IP][SAFI_UNICAST] = 0; peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 0; peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 0; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 0; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 0; peer->afc_adv[AFI_IP][SAFI_UNICAST] = 0; peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 0; peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 0; peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 0; peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 0; peer->afc_recv[AFI_IP][SAFI_UNICAST] = 0; peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 0; peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 0; peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 0; peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 0; /* Reset route refresh flag. */ UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV); UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) { /* peer address family capability flags*/ peer->af_cap[afi][safi] = 0; /* peer address family status flags*/ peer->af_sflags[afi][safi] = 0; /* Received ORF prefix-filter */ peer->orf_plist[afi][safi] = NULL; /* ORF received prefix-filter pnt */ sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); prefix_bgp_orf_remove_all (orf_name); } UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_DEFAULT_ORIGINATE_CHECK); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], PEER_FLAG_DEFAULT_ORIGINATE_CHECK); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_DEFAULT_ORIGINATE_CHECK); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_DEFAULT_ORIGINATE_CHECK); /* Reset keepalive and holdtime */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) { peer->v_keepalive = peer->keepalive; peer->v_holdtime = peer->holdtime; } else { peer->v_keepalive = peer->bgp->default_keepalive; peer->v_holdtime = peer->bgp->default_holdtime; } peer->update_time = 0; /* Until we are sure that there is no problem about prefix count this should be commented out.*/ #if 0 /* Reset prefix count */ peer->pcount[AFI_IP][SAFI_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; #endif /* 0 */ return 0; }