--- embedaddon/quagga/bgpd/bgp_fsm.c 2013/07/21 23:54:37 1.1.1.3 +++ embedaddon/quagga/bgpd/bgp_fsm.c 2016/11/02 10:09:10 1.1.1.4 @@ -30,6 +30,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330 #include "stream.h" #include "memory.h" #include "plist.h" +#include "workqueue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -43,7 +45,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330 #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 @@ -65,7 +67,7 @@ static int bgp_start (struct peer *); static int bgp_start_jitter (int time) { - return ((rand () % (time + 1)) - (time / 2)); + return ((random () % (time + 1)) - (time / 2)); } /* Check if suppress start/restart of sessions to peer. */ @@ -100,7 +102,6 @@ bgp_timer_set (struct peer *peer) 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; @@ -112,7 +113,6 @@ bgp_timer_set (struct peer *peer) 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; @@ -132,7 +132,6 @@ bgp_timer_set (struct peer *peer) } 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; @@ -150,7 +149,6 @@ bgp_timer_set (struct peer *peer) 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; @@ -173,7 +171,6 @@ bgp_timer_set (struct peer *peer) 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; @@ -197,7 +194,6 @@ bgp_timer_set (struct peer *peer) BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, peer->v_keepalive); } - BGP_TIMER_OFF (peer->t_asorig); break; case Deleted: BGP_TIMER_OFF (peer->t_gr_restart); @@ -208,7 +204,6 @@ bgp_timer_set (struct peer *peer) 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); } } @@ -406,7 +401,23 @@ bgp_fsm_change_status (struct peer *peer, int status) * (and must do so before actually changing into Deleted.. */ if (status >= Clearing) - bgp_clear_route_all (peer); + { + 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; @@ -505,7 +516,6 @@ bgp_stop (struct peer *peer) 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); /* Stream reset. */ @@ -545,7 +555,7 @@ bgp_stop (struct peer *peer) /* ORF received prefix-filter pnt */ sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); - prefix_bgp_orf_remove_all (orf_name); + prefix_bgp_orf_remove_all (afi, orf_name); } /* Reset keepalive and holdtime */ @@ -592,6 +602,32 @@ bgp_stop_with_error (struct peer *peer) return 0; } + +/* something went wrong, send notify and tear down */ +static int +bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) +{ + /* Send notify to remote peer */ + bgp_notify_send (peer, code, sub_code); + + /* Sweep if it is temporary peer. */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); + peer_delete (peer); + return -1; + } + + /* Clear start timer value to default. */ + peer->v_start = BGP_INIT_START_TIMER; + + /* bgp_stop needs to be invoked while in Established state */ + bgp_stop(peer); + + return 0; +} + + /* TCP connection open. Next we send open message to remote peer. And add read thread for reading open message. */ static int @@ -740,29 +776,26 @@ bgp_fsm_keepalive_expire (struct peer *peer) return 0; } +/* FSM error, unexpected event. This is error of BGP connection. So cut the + peer and change to Idle status. */ +static int +bgp_fsm_event_error (struct peer *peer) +{ + plog_err (peer->log, "%s [FSM] unexpected packet received in state %s", + peer->host, LOOKUP (bgp_status_msg, peer->status)); + + return bgp_stop_with_notify (peer, BGP_NOTIFY_FSM_ERR, 0); +} + /* Hold timer expire. This is error of BGP connection. So cut the peer and change to Idle status. */ static int bgp_fsm_holdtime_expire (struct peer *peer) { if (BGP_DEBUG (fsm, FSM)) - zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host); + plog_debug (peer->log, "%s [FSM] Hold timer expire", peer->host); - /* Send notify to remote peer. */ - bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0); - - /* Sweep if it is temporary peer. */ - if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) - { - zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); - peer_delete (peer); - return -1; - } - - /* bgp_stop needs to be invoked while in Established state */ - bgp_stop(peer); - - return 0; + return bgp_stop_with_notify (peer, BGP_NOTIFY_HOLD_ERR, 0); } /* Status goes to Established. Send keepalive packet then make first @@ -905,7 +938,7 @@ bgp_ignore (struct peer *peer) zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host); return 0; } - + /* Finite State Machine structure */ static const struct { int (*func) (struct peer *); @@ -977,8 +1010,8 @@ static const struct { {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ - {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ - {bgp_ignore, Idle}, /* Receive_UPDATE_message */ + {bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */ + {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ },