Line data Source code
1 : /*
2 : * Copyright (c) 2014 CodiLime, Inc. All rights reserved.
3 : */
4 :
5 : #include "bfd/bfd_common.h"
6 : #include "bfd/bfd_session.h"
7 : #include "bfd/bfd_state_machine.h"
8 :
9 : #include <list>
10 : #include <boost/optional.hpp>
11 : #include <boost/bind/bind.hpp>
12 : #include <boost/statechart/event.hpp>
13 : #include <boost/statechart/transition.hpp>
14 : #include <boost/statechart/state_machine.hpp>
15 : #include <boost/statechart/simple_state.hpp>
16 : #include <boost/statechart/custom_reaction.hpp>
17 : #include <boost/mpl/list.hpp>
18 :
19 : #include "base/logging.h"
20 :
21 : using namespace boost::placeholders;
22 : namespace mpl = boost::mpl;
23 : namespace sc = boost::statechart;
24 :
25 : namespace BFD {
26 :
27 : struct EvRecvInit : sc::event<EvRecvInit> {};
28 : struct EvRecvDown : sc::event<EvRecvDown> {};
29 : struct EvRecvUp : sc::event<EvRecvUp> {};
30 : struct EvRecvAdminDown : sc::event<EvRecvAdminDown> {};
31 : struct EvTimeout : sc::event<EvTimeout> {};
32 : // struct EvReset : sc::event<EvReset> {};
33 :
34 : struct BFDStateAware {
35 : virtual BFDState getState() const = 0;
36 172 : virtual ~BFDStateAware(){}
37 : };
38 :
39 : struct InitState;
40 : struct DownState;
41 : struct UpState;
42 : class StateMachineImpl : public StateMachine,
43 : public sc::state_machine<StateMachineImpl, DownState> {
44 : public:
45 32 : explicit StateMachineImpl(EventManager *evm, Session *session) :
46 32 : evm_(evm), session_(session) {
47 32 : initiate();
48 32 : }
49 :
50 62 : void Notify(BFDState state) {
51 62 : LOG(DEBUG, "StateMachine state: " << state);
52 62 : if (cb_.is_initialized() && session_) {
53 55 : (cb_.get())(session_->key(), GetState());
54 : } else {
55 7 : LOG(ERROR, "StateMachine cb initialized: "
56 : << cb_.is_initialized() << " session: " << session_);
57 : }
58 62 : }
59 :
60 127 : void ProcessRemoteState(BFDState state) {
61 127 : BFDState old_state = GetState();
62 127 : switch (state) {
63 0 : case kAdminDown:
64 0 : process_event(EvRecvAdminDown());
65 0 : break;
66 28 : case kDown:
67 28 : process_event(EvRecvDown());
68 28 : break;
69 29 : case kInit:
70 29 : process_event(EvRecvInit());
71 29 : break;
72 70 : case kUp:
73 70 : process_event(EvRecvUp());
74 70 : break;
75 : }
76 127 : if (old_state != GetState()) {
77 56 : Notify(GetState());
78 : }
79 127 : }
80 :
81 13 : void ProcessTimeout() {
82 13 : BFDState old_state = GetState();
83 13 : process_event(EvTimeout());
84 13 : if (old_state != GetState())
85 6 : Notify(GetState());
86 13 : }
87 :
88 11732 : BFDState GetState() {
89 11732 : return state_cast<const BFDStateAware &>().getState();
90 : }
91 :
92 59 : void SetCallback(boost::optional<ChangeCb> cb) {
93 59 : cb_ = cb;
94 59 : }
95 :
96 : private:
97 : boost::optional<ChangeCb> cb_;
98 : EventManager *evm_;
99 : Session *session_;
100 : };
101 :
102 : struct InitState : sc::simple_state<InitState, StateMachineImpl>,
103 : BFDStateAware {
104 : typedef mpl::list<
105 : sc::transition<EvRecvInit, UpState>,
106 : sc::transition<EvRecvDown, InitState>,
107 : sc::transition<EvRecvUp, UpState>,
108 : sc::transition<EvRecvAdminDown, DownState>,
109 : sc::transition<EvTimeout, DownState>
110 : > reactions;
111 4979 : virtual BFDState getState() const { return kInit; }
112 50 : virtual ~InitState() {}
113 : };
114 :
115 : struct UpState : sc::simple_state<UpState, StateMachineImpl>, BFDStateAware {
116 : typedef mpl::list<
117 : sc::transition<EvRecvInit, UpState>,
118 : sc::transition<EvRecvDown, DownState>,
119 : sc::transition<EvRecvUp, UpState>,
120 : sc::transition<EvRecvAdminDown, DownState>,
121 : sc::transition<EvTimeout, DownState>
122 : > reactions;
123 637 : virtual BFDState getState() const { return kUp; }
124 196 : virtual ~UpState() {}
125 : };
126 :
127 : struct DownState : sc::simple_state<DownState, StateMachineImpl>,
128 : BFDStateAware {
129 : typedef mpl::list<
130 : sc::transition<EvRecvInit, UpState>,
131 : sc::transition<EvRecvDown, InitState>,
132 : sc::transition<EvRecvUp, DownState>,
133 : sc::transition<EvRecvAdminDown, DownState>,
134 : sc::transition<EvTimeout, DownState>
135 : > reactions;
136 6116 : virtual BFDState getState() const { return kDown; }
137 98 : virtual ~DownState() {}
138 : };
139 :
140 32 : StateMachine *CreateStateMachine(EventManager *evm, Session *session) {
141 32 : return new StateMachineImpl(evm, session);
142 : }
143 :
144 : } // namespace BFD
|