LCOV - code coverage report
Current view: top level - bgp - state_machine.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 14 15 93.3 %
Date: 2026-06-04 02:06:09 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef SRC_BGP_STATE_MACHINE_H_
       6             : #define SRC_BGP_STATE_MACHINE_H_
       7             : 
       8             : #include <boost/statechart/state_machine.hpp>
       9             : 
      10             : #include <string>
      11             : #include <utility>
      12             : 
      13             : #include "base/queue_task.h"
      14             : #include "base/timer.h"
      15             : #include "bgp/bgp_proto.h"
      16             : #include "io/tcp_session.h"
      17             : #include "sandesh/sandesh.h"
      18             : 
      19             : namespace sc = boost::statechart;
      20             : 
      21             : class BgpPeer;
      22             : class BgpSession;
      23             : class BgpPeerInfo;
      24             : class BgpPeerInfoData;
      25             : class BgpMessage;
      26             : class StateMachine;
      27             : 
      28             : namespace fsm {
      29             : struct Idle;
      30             : struct EvBgpNotification;
      31             : }
      32             : 
      33             : typedef boost::function<bool(StateMachine *)> EvValidate;
      34             : 
      35             : //
      36             : // This class implements the state machine for a BgpPeer. Note that a single
      37             : // state machine is used for a BgpPeer, instead of using one per TCP session.
      38             : // As a consequence, the state machine keeps track of the active and passive
      39             : // sessions to/from the peer.  Connection collision is resolved using remote
      40             : // and local router ids as specified in the RFC.  When the state machine has
      41             : // determined which session (active or passive) will be used in the steady
      42             : // state, ownership of that session is transferred to the peer and the other
      43             : // session, if any, is closed.
      44             : //
      45             : // Events for the state machine can be posted from a few different contexts.
      46             : // Administrative events are posted from the bgp::Config task, TCP related
      47             : // events from the ASIO thread, Timer events from bgp::StateMachine task and
      48             : // BGP Message related events are posted from the io::Reader task.
      49             : //
      50             : // Timers run in the context of the bgp::StateMachine task instead of running
      51             : // directly from the ASIO thread.  This avoids race conditions wherein timers
      52             : // expire at the same time that the state machine task is attempting to cancel
      53             : // them.
      54             : //
      55             : // TCP session related events are posted directly from the ASIO thread.  Race
      56             : // conditions wherein the bgp::StateMachine task tries to delete a session at
      57             : // the same time that the ASIO thread is attempting to notify an event for the
      58             : // session are avoided by have the state machine post a pseudo event to delete
      59             : // the session. See comments for the DeleteSession method for more information.
      60             : //
      61             : // All events on the state machine are processed asynchronously by enqueueing
      62             : // them to a WorkQueue. The WorkQueue is serviced by a bgp::StateMachine task.
      63             : // The BgpPeer index is used as the instance id for the task. This allows the
      64             : // state machines for multiple BgpPeers to run concurrently.
      65             : //
      66             : // Since events are processed asynchronously, it is possible that an event is
      67             : // no longer relevant by the time we get around to processing it. For example,
      68             : // we may see a TCP session close event after we've already decided to delete
      69             : // the session. The optional validate method in the event is used to determine
      70             : // if an event is still valid/relevant before feeding it to the state machine.
      71             : // Note that the validate routine needs to be run right before we process the
      72             : // event i.e. it's not correct to call it when posting the event.  Hence the
      73             : // need for the EventContainer structure.
      74             : //
      75             : class StateMachine : public sc::state_machine<StateMachine, fsm::Idle> {
      76             : public:
      77             :     typedef boost::function<void(void)> EventCB;
      78             : 
      79             :     static const int kOpenTime;
      80             :     static const int kConnectInterval;
      81             :     static const int kHoldTime;
      82             :     static const int kOpenSentHoldTime;
      83             :     static const int kIdleHoldTime;
      84             :     static const int kMaxIdleHoldTime;
      85             :     static const int kJitter;
      86             : 
      87             :     enum State {
      88             :         IDLE        = 0,
      89             :         ACTIVE      = 1,
      90             :         CONNECT     = 2,
      91             :         OPENSENT    = 3,
      92             :         OPENCONFIRM = 4,
      93             :         ESTABLISHED = 5
      94             :     };
      95             : 
      96             :     explicit StateMachine(BgpPeer *peer);
      97             :     virtual ~StateMachine();
      98             : 
      99             :     void Initialize();
     100             :     void Shutdown(int subcode);
     101             :     void SetAdminState(bool down, int subcode);
     102             :     bool IsQueueEmpty() const;
     103             : 
     104             :     template <typename Ev, int code> void OnIdle(const Ev &event);
     105             :     template <typename Ev> void OnIdleCease(const Ev &event);
     106             :     template <typename Ev, int code> void OnIdleError(const Ev &event);
     107             :     void OnIdleNotification(const fsm::EvBgpNotification &event);
     108             : 
     109             :     int GetConnectTime() const;
     110             :     virtual void StartConnectTimer(int seconds);
     111             :     void CancelConnectTimer();
     112             :     bool ConnectTimerRunning();
     113             : 
     114             :     virtual void StartOpenTimer(int seconds);
     115             :     void CancelOpenTimer();
     116             :     bool OpenTimerRunning();
     117             : 
     118             :     int GetConfiguredHoldTime() const;
     119             :     virtual void StartHoldTimer();
     120             :     void CancelHoldTimer();
     121             :     bool HoldTimerRunning();
     122             : 
     123             :     virtual void StartIdleHoldTimer();
     124             :     void CancelIdleHoldTimer();
     125             :     bool IdleHoldTimerRunning();
     126             : 
     127             :     void StartSession();
     128             :     virtual void DeleteSession(BgpSession *session);
     129             :     void AssignSession(bool active);
     130             : 
     131             :     virtual void OnSessionEvent(TcpSession *session, TcpSession::Event event);
     132             :     bool PassiveOpen(BgpSession *session);
     133             : 
     134             :     void OnMessage(BgpSession *session, BgpProto::BgpMessage *msg,
     135             :         size_t msgsize = 0);
     136             :     void OnMessageError(BgpSession *session, const ParseErrorContext *context);
     137             : 
     138             :     void SendNotification(BgpSession *session, int code, int subcode = 0,
     139             :                           const std::string &data = std::string());
     140             :     bool ProcessNotificationEvent(BgpSession *session);
     141             :     void SetDataCollectionKey(BgpPeerInfo *peer_info) const;
     142             : 
     143             :     const std::string &StateName() const;
     144             :     const std::string &LastStateName() const;
     145             : 
     146      409432 :     BgpPeer *peer() { return peer_; }
     147             :     BgpSession *active_session();
     148             :     void set_active_session(BgpSession *session);
     149             :     BgpSession *passive_session();
     150             :     void set_passive_session(BgpSession *session);
     151             : 
     152         225 :     int connect_attempts() const { return attempts_; }
     153        6994 :     void connect_attempts_inc() { attempts_++; }
     154        5341 :     void connect_attempts_clear() { attempts_ = 0; }
     155             : 
     156         324 :     int hold_time() const { return hold_time_; }
     157             :     void reset_hold_time();
     158             :     void set_hold_time(int hold_time);
     159      134377 :     virtual int keepalive_time_msecs() const { return hold_time_ * 1000 / 3; }
     160             : 
     161       37294 :     int idle_hold_time() const { return idle_hold_time_; }
     162         410 :     void reset_idle_hold_time() { idle_hold_time_ = 0; }
     163       16402 :     void set_idle_hold_time(int idle_hold_time) {
     164       16402 :         idle_hold_time_ = idle_hold_time;
     165       16402 :     }
     166             : 
     167             :     void set_state(State state);
     168     1234607 :     State get_state() const { return state_; }
     169             :     const std::string last_state_change_at() const;
     170             :     const uint64_t last_state_change_usecs_at() const;
     171             :     void set_last_event(const std::string &event);
     172          56 :     const std::string &last_event() const { return last_event_; }
     173             : 
     174             :     void set_last_notification_in(int code, int subcode,
     175             :         const std::string &reason);
     176             :     void set_last_notification_out(int code, int subcode,
     177             :         const std::string &reason);
     178             :     const std::string last_notification_out_error() const;
     179             :     const std::string last_notification_in_error() const;
     180             :     void reset_last_info();
     181             :     void LogEvent(std::string event_name, std::string msg,
     182             :                   SandeshLevel::type log_level = SandeshLevel::SYS_DEBUG);
     183             :     bool HoldTimerExpired();
     184             :     virtual bool IsCloseGraceful() const;
     185             :     virtual bool IsRouterTypeBGPaaS() const;
     186             :     virtual bool IsPeerCloseInProgress() const;
     187             : 
     188             : protected:
     189             :     virtual void OnNotificationMessage(BgpSession *session,
     190             :                                        BgpProto::BgpMessage *msg);
     191        5348 :     virtual const int GetIdleHoldTimeMSecs() const { return kIdleHoldTime; }
     192             : 
     193             : private:
     194             :     friend class StateMachineTest;
     195             :     friend class StateMachineUnitTest;
     196             : 
     197             :     struct EventContainer {
     198             :         boost::intrusive_ptr<const sc::event_base> event;
     199             :         EvValidate validate;
     200             :     };
     201             : 
     202             :     bool ConnectTimerExpired();
     203             :     void FireConnectTimer();
     204             :     bool OpenTimerExpired();
     205             :     void FireOpenTimer();
     206             :     void FireHoldTimer();
     207             :     bool IdleHoldTimerExpired();
     208             :     void FireIdleHoldTimer();
     209             : 
     210           0 :     void TimerErrorHanlder(std::string name, std::string error) { }
     211             :     void DeleteAllTimers();
     212             :     void BGPPeerInfoSend(const BgpPeerInfoData &peer_info);
     213             : 
     214             :     template <typename Ev> bool Enqueue(const Ev &event);
     215             :     bool DequeueEvent(EventContainer ec);
     216             :     void DequeueEventDone(bool done);
     217             :     void UpdateFlapCount();
     218             :     void PeerClose(int code, int subcode);
     219             : 
     220             :     WorkQueue<EventContainer> work_queue_;
     221             :     BgpPeer *peer_;
     222             :     BgpSession *active_session_;
     223             :     BgpSession *passive_session_;
     224             :     Timer *connect_timer_;
     225             :     Timer *open_timer_;
     226             :     Timer *hold_timer_;
     227             :     Timer *idle_hold_timer_;
     228             :     int hold_time_;
     229             :     int idle_hold_time_;
     230             :     int attempts_;
     231             :     unsigned int seed_;
     232             :     bool deleted_;
     233             :     State state_;
     234             :     State last_state_;
     235             :     std::string last_event_;
     236             :     uint64_t last_event_at_;
     237             :     uint64_t last_state_change_at_;
     238             :     std::pair<int, int> last_notification_in_;
     239             :     std::string last_notification_in_error_;
     240             :     uint64_t last_notification_in_at_;
     241             :     std::pair<int, int> last_notification_out_;
     242             :     std::string last_notification_out_error_;
     243             :     uint64_t last_notification_out_at_;
     244             : 
     245             :     DISALLOW_COPY_AND_ASSIGN(StateMachine);
     246             : };
     247             : 
     248             : std::ostream &operator<<(std::ostream &out, const StateMachine::State &state);
     249             : 
     250             : #endif  // SRC_BGP_STATE_MACHINE_H_

Generated by: LCOV version 1.14