-
Notifications
You must be signed in to change notification settings - Fork 390
/
path_preference.h
209 lines (188 loc) · 6.75 KB
/
path_preference.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*
* Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
*/
#ifndef __ROUTE_PREFERENCE_H__
#define __ROUTE_PREFERENCE_H__
#include <boost/statechart/custom_reaction.hpp>
#include <boost/statechart/event.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/state_machine.hpp>
namespace sc = boost::statechart;
struct Init;
struct WaitForTraffic;
struct TrafficSeen;
struct ActiveActiveState;
class PathPreferenceModule;
#define PATH_PREFERENCE_TRACE(...) \
do { \
PathPreferenceTrace::TraceMsg(PathPreferenceTraceBuf, __FILE__, __LINE__,\
##__VA_ARGS__); \
} while (false) \
//Per Path state machine to determine preference of a path based on
//traffic(GARP or flow from VM)
class PathPreferenceSM:
public sc::state_machine<PathPreferenceSM, Init> {
public:
static const uint32_t kMinInterval = 4 * 1000;
static const uint32_t kMaxInterval = 32 * 1000;
static const uint32_t kMaxFlapCount = 5;
PathPreferenceSM(Agent *agent, const Peer *peer,
AgentRoute *rt);
~PathPreferenceSM();
uint32_t sequence() const {return path_preference_.sequence();}
uint32_t preference() const {return path_preference_.preference();}
bool wait_for_traffic() const {return path_preference_.wait_for_traffic();}
bool ecmp() const {return path_preference_.ecmp();}
uint32_t timeout() const { return timeout_;}
uint64_t last_stable_high_priority_change_at() const {
return last_stable_high_priority_change_at_;
}
uint32_t flap_count() const { return flap_count_;}
void set_sequence(uint32_t seq_no) {
path_preference_.set_sequence(seq_no);
}
void set_preference(PathPreference::Preference preference) {
path_preference_.set_preference(preference);
}
void set_wait_for_traffic(bool wait_for_traffic) {
path_preference_.set_wait_for_traffic(wait_for_traffic);
}
void set_ecmp(bool ecmp) {
path_preference_.set_ecmp(ecmp);
}
void set_seen(bool seen) {
seen_ = seen;
}
void set_max_sequence(uint32_t seq) {
max_sequence_ = seq;
}
void set_timeout(uint32_t timeout) {
timeout_ = timeout;
}
void set_last_stable_high_priority_change_at(uint64_t timestamp) {
last_stable_high_priority_change_at_ = timestamp;
}
bool IsFlap() const;
bool seen() { return seen_; }
uint32_t max_sequence() const { return max_sequence_;}
void Process();
void Delete();
void Log(std::string state);
void EnqueuePathChange();
bool Retry();
void StartRetryTimer();
void CancelRetryTimer();
bool RetryTimerRunning();
void IncreaseRetryTimeout();
void DecreaseRetryTimeout();
bool IsPathFlapping() const;
bool IsPathStable() const;
void UpdateFlapTime();
private:
Agent *agent_;
const Peer *peer_;
AgentRoute *rt_;
PathPreference path_preference_;
uint32_t max_sequence_;
bool seen_;
Timer *timer_;
uint32_t timeout_;
uint64_t last_stable_high_priority_change_at_;
uint64_t backoff_timer_fired_time_;
uint32_t flap_count_;
};
//Per Route state machine containing a map for all
//local path state machine data
class PathPreferenceState: public DBState {
public:
typedef std::map<const Peer *, PathPreferenceSM *> PeerPathPreferenceMap;
PathPreferenceState(Agent *agent, AgentRoute *rt_);
~PathPreferenceState();
void Process();
PathPreferenceSM *GetSM(const Peer *);
private:
Agent *agent_;
AgentRoute *rt_;
PeerPathPreferenceMap path_preference_peer_map_;
};
//Per VM interface state, containing floating IP
//and static route a interface contains
struct PathPreferenceIntfState : public DBState {
PathPreferenceIntfState(const VmInterface *intf);
struct RouteAddrList {
bool operator<(const RouteAddrList &rhs) const;
bool operator==(const RouteAddrList &rhs) const;
Address::Family family_;
IpAddress ip_;
uint32_t plen_;
std::string vrf_name_;
mutable bool seen_;
};
void Notify();
void Insert(RouteAddrList &rt, bool traffic_seen);
void DeleteOldEntries();
void UpdateDependentRoute(std::string vrf_name, Ip4Address ip,
uint32_t plen, bool traffic_seen,
PathPreferenceModule *path_preference_module);
uint32_t DependentRouteListSize() const { return dependent_rt_.size(); }
private:
const VmInterface *intf_;
RouteAddrList instance_ip_;
std::set<RouteAddrList> dependent_rt_;
};
struct PathPreferenceVrfState: public DBState {
PathPreferenceVrfState(DBTableBase::ListenerId uc_rt_id,
DBTableBase::ListenerId evpn_rt_id):
uc_rt_id_(uc_rt_id), evpn_rt_id_(evpn_rt_id) {}
DBTableBase::ListenerId uc_rt_id_;
DBTableBase::ListenerId evpn_rt_id_;
};
struct PathPreferenceRouteListener : public DBState {
PathPreferenceRouteListener(Agent *agent, AgentRouteTable *table);
virtual void Delete();
void Notify(DBTablePartBase *partition, DBEntryBase *e);
void Init();
bool DeleteState(DBTablePartBase *partition, DBEntryBase *e);
void Walkdone(DBTableBase *partition, PathPreferenceRouteListener *state);
DBTableBase::ListenerId id() const { return id_;}
void ManagedDelete();
void set_deleted() {deleted_ = true;}
bool deleted() const {return deleted_;}
private:
Agent *agent_;
AgentRouteTable *rt_table_;
DBTableBase::ListenerId id_;
LifetimeRef<PathPreferenceRouteListener> table_delete_ref_;
bool deleted_;
};
class PathPreferenceModule {
public:
struct PathPreferenceEventContainer {
IpAddress ip_;
uint32_t plen_;
MacAddress mac_;
uint32_t interface_index_;
uint32_t vrf_index_;
uint32_t vxlan_id_;
boost::intrusive_ptr<const sc::event_base> event;
};
PathPreferenceModule(Agent *agent);
void Init();
void Shutdown();
void VrfNotify(DBTablePartBase *partition, DBEntryBase *e);
void IntfNotify(DBTablePartBase *partition, DBEntryBase *e);
void EnqueueTrafficSeen(Ip4Address ip_, uint32_t plen,
uint32_t interface_index, uint32_t vrf_index,
const MacAddress &mac);
bool DequeueEvent(PathPreferenceEventContainer e);
Agent *agent() { return agent_;}
DBTableBase::ListenerId vrf_id() const { return vrf_id_;}
DBTableBase::ListenerId intf_id() const { return intf_id_;}
private:
Agent *agent_;
DBTableBase::ListenerId vrf_id_;
DBTableBase::ListenerId intf_id_;
WorkQueue<PathPreferenceEventContainer> work_queue_;
};
#endif