📄 bgp_fsm.c
字号:
/* BGP-4 Finite State Machine From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] Copyright (C) 1996, 97, 98 Kunihiro IshiguroThis file is part of GNU Zebra.GNU Zebra is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2, or (at your option) anylater version.GNU Zebra is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Zebra; see the file COPYING. If not, write to the FreeSoftware Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA02111-1307, USA. */#include <zebra.h>#include "linklist.h"#include "prefix.h"#include "vty.h"#include "sockunion.h"#include "thread.h"#include "log.h"#include "stream.h"#include "memory.h"#include "plist.h"#include "bgpd/bgpd.h"#include "bgpd/bgp_attr.h"#include "bgpd/bgp_debug.h"#include "bgpd/bgp_fsm.h"#include "bgpd/bgp_packet.h"#include "bgpd/bgp_network.h"#include "bgpd/bgp_route.h"#include "bgpd/bgp_dump.h"#include "bgpd/bgp_open.h"#ifdef HAVE_SNMP#include "bgpd/bgp_snmp.h"#endif /* HAVE_SNMP *//* BGP FSM (finite state machine) has three types of functions. Type one is thread functions. Type two is event functions. Type three is FSM functions. Timer functions are set by bgp_timer_set function. *//* BGP event function. */int bgp_event (struct thread *);/* BGP thread functions. */static int bgp_start_timer (struct thread *);static int bgp_connect_timer (struct thread *);static int bgp_holdtime_timer (struct thread *);static int bgp_keepalive_timer (struct thread *);/* BGP FSM functions. */static int bgp_start (struct peer *);/* BGP start timer jitter. */intbgp_start_jitter (int time){ return ((rand () % (time + 1)) - (time / 2));}/* Hook function called after bgp event is occered. And vty's neighbor command invoke this function after making neighbor structure. */voidbgp_timer_set (struct peer *peer){ int jitter = 0; switch (peer->status) { case Idle: /* First entry point of peer's finite state machine. In Idle status start timer is on unless peer is shutdown or peer is inactive. All other timer must be turned off */ if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN) || CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW) || ! peer_active (peer)) { BGP_TIMER_OFF (peer->t_start); } else { jitter = bgp_start_jitter (peer->v_start); BGP_TIMER_ON (peer->t_start, bgp_start_timer, peer->v_start + jitter); } 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); break; case Connect: /* After start timer is expired, the peer moves to Connnect status. Make sure start timer is off and connect timer is on. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_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); break; case Active: /* Active is waiting connection from remote peer. And if connect timer is expired, change status to Connect. */ BGP_TIMER_OFF (peer->t_start); /* If peer is passive mode, do not set connect timer. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) { BGP_TIMER_OFF (peer->t_connect); } else { BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_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); break; case OpenSent: /* OpenSent status. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); if (peer->v_holdtime != 0) { BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); } else { BGP_TIMER_OFF (peer->t_holdtime); } BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; case OpenConfirm: /* OpenConfirm status. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); /* If the negotiated Hold Time value is zero, then the Hold Time timer and KeepAlive timers are not started. */ if (peer->v_holdtime == 0) { BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); } else { BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, peer->v_keepalive); } BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; case Established: /* In Established status start and connect timer is turned off. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); /* Same as OpenConfirm, if holdtime is zero then both holdtime and keepalive must be turned off. */ if (peer->v_holdtime == 0) { BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); } else { BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, peer->v_keepalive); } BGP_TIMER_OFF (peer->t_asorig); break; }}/* BGP start timer. This function set BGP_Start event to thread value and process event. */static intbgp_start_timer (struct thread *thread){ struct peer *peer; peer = THREAD_ARG (thread); peer->t_start = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (start timer expire).", peer->host); THREAD_VAL (thread) = BGP_Start; bgp_event (thread); return 0;}/* BGP connect retry timer. */static intbgp_connect_timer (struct thread *thread){ struct peer *peer; peer = THREAD_ARG (thread); peer->t_connect = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (connect timer expire)", peer->host); THREAD_VAL (thread) = ConnectRetry_timer_expired; bgp_event (thread); return 0;}/* BGP holdtime timer. */static intbgp_holdtime_timer (struct thread *thread){ struct peer *peer; peer = THREAD_ARG (thread); peer->t_holdtime = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (holdtime timer expire)", peer->host); THREAD_VAL (thread) = Hold_Timer_expired; bgp_event (thread); return 0;}/* BGP keepalive fire ! */static intbgp_keepalive_timer (struct thread *thread){ struct peer *peer; peer = THREAD_ARG (thread); peer->t_keepalive = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (keepalive timer expire)", peer->host); THREAD_VAL (thread) = KeepAlive_timer_expired; bgp_event (thread); return 0;}intbgp_routeadv_timer (struct thread *thread){ struct peer *peer; peer = THREAD_ARG (thread); peer->t_routeadv = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (routeadv timer expire)", peer->host); peer->synctime = time (NULL); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, peer->v_routeadv); return 0;}/* Reset bgp update timer */static voidbgp_uptime_reset (struct peer *peer){ peer->uptime = time (NULL);}/* BGP Peer Down Cause */char *peer_down_str[] ={ "", "Router ID changed", "Remote AS changed", "Local AS change", "Cluster ID changed", "Confederation identifier changed", "Confederation peer changed", "RR client config change", "RS client config change", "Update source change", "Address family activated", "Admin. shutdown", "User reset", "BGP Notification received", "BGP Notification send", "Peer closed the session", "Neighbor deleted", "Peer-group add member", "Peer-group delete member", "Capability changed", "Passive config change", "Multihop config change"};/* Administrative BGP peer stop event. */intbgp_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); /* 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]); /* 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. */ 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -