Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 : #include <boost/statechart/custom_reaction.hpp>
5 : #include <boost/statechart/event.hpp>
6 : #include <boost/statechart/simple_state.hpp>
7 : #include <boost/statechart/state.hpp>
8 : #include <boost/statechart/state_machine.hpp>
9 : #include <cmn/agent_cmn.h>
10 : #include <route/route.h>
11 : #include <oper/route_common.h>
12 : #include <oper/vrf.h>
13 : #include <oper/mirror_table.h>
14 : #include <oper/path_preference.h>
15 : #include <mac_learning/mac_learning_init.h>
16 :
17 : namespace sc = boost::statechart;
18 : namespace mpl = boost::mpl;
19 :
20 : SandeshTraceBufferPtr PathPreferenceTraceBuf(
21 : SandeshTraceBufferCreate("PathPreference", 5000));
22 : struct EvStart : sc::event<EvStart> {
23 0 : EvStart() {
24 0 : }
25 :
26 : static const char *Name() {
27 : return "Start";
28 : }
29 : };
30 :
31 : struct EvTrafficSeen : sc::event<EvTrafficSeen> {
32 0 : EvTrafficSeen() {
33 0 : }
34 : static const char *Name() {
35 : return "TrafficSeen";
36 : }
37 : };
38 :
39 : struct EvWaitForTraffic : sc::event<EvWaitForTraffic> {
40 0 : EvWaitForTraffic() {
41 0 : }
42 : static const char *Name() {
43 : return "WaitForTraffic";
44 : }
45 : };
46 :
47 : struct EvSeqChange : sc::event<EvSeqChange> {
48 0 : EvSeqChange(uint32_t sequence) : sequence_(sequence) {
49 0 : }
50 : static const char *Name() {
51 : return "SeqChange";
52 : }
53 : uint32_t sequence_;
54 : };
55 :
56 : //Path transition to ECMP
57 : struct EvActiveActiveMode : sc::event<EvActiveActiveMode> {
58 0 : EvActiveActiveMode() {
59 0 : }
60 : static const char *Name() {
61 : return "EcmpRoute";
62 : }
63 : };
64 :
65 : struct EvControlNodeInSync : sc::event<EvControlNodeInSync> {
66 0 : EvControlNodeInSync() {
67 0 : }
68 : static const char *Name() {
69 : return "Control node route in sync";
70 : }
71 : };
72 :
73 : struct Init : public sc::state<Init, PathPreferenceSM> {
74 : typedef mpl::list<
75 : sc::custom_reaction<EvStart>
76 : > reactions;
77 :
78 0 : Init(my_context ctx) : my_base(ctx) {
79 0 : PathPreferenceSM *state_machine = &context<PathPreferenceSM>();
80 0 : state_machine->Log("INIT");
81 0 : }
82 :
83 0 : sc::result react(const EvStart &event) {
84 0 : return transit<WaitForTraffic>();
85 : }
86 : };
87 :
88 : struct WaitForTraffic : sc::state<WaitForTraffic, PathPreferenceSM> {
89 : typedef mpl::list<
90 : sc::custom_reaction<EvTrafficSeen>,
91 : sc::custom_reaction<EvSeqChange>,
92 : sc::custom_reaction<EvWaitForTraffic>,
93 : sc::custom_reaction<EvActiveActiveMode>,
94 : sc::custom_reaction<EvControlNodeInSync>
95 : > reactions;
96 :
97 0 : WaitForTraffic(my_context ctx) : my_base(ctx) {
98 0 : PathPreferenceSM *state_machine = &context<PathPreferenceSM>();
99 0 : if (state_machine->wait_for_traffic() == false) {
100 0 : state_machine->set_wait_for_traffic(true);
101 0 : state_machine->set_preference(PathPreference::LOW);
102 0 : state_machine->EnqueuePathChange();
103 0 : state_machine->UpdateDependentRoute();
104 0 : state_machine->Log("Wait For Traffic");
105 : }
106 0 : }
107 :
108 0 : sc::result react(const EvTrafficSeen &event) {
109 0 : return transit<TrafficSeen>();
110 : }
111 :
112 0 : sc::result react(const EvSeqChange &event) {
113 0 : PathPreferenceSM *state_machine = &context<PathPreferenceSM>();
114 0 : state_machine->set_max_sequence(event.sequence_);
115 0 : state_machine->Log("WaitForTraffic EvSeqChange");
116 0 : return discard_event();
117 : }
118 :
119 0 : sc::result react(const EvWaitForTraffic &event) {
120 0 : return discard_event();
121 : }
122 :
123 0 : sc::result react(const EvActiveActiveMode &event) {
124 0 : return transit<ActiveActiveState>();
125 : }
126 :
127 0 : sc::result react(const EvControlNodeInSync &event) {
128 0 : return discard_event();
129 : }
130 : };
131 :
132 : struct TrafficSeen : sc::state<TrafficSeen, PathPreferenceSM> {
133 : typedef mpl::list<
134 : sc::custom_reaction<EvTrafficSeen>,
135 : sc::custom_reaction<EvSeqChange>,
136 : sc::custom_reaction<EvWaitForTraffic>,
137 : sc::custom_reaction<EvActiveActiveMode>,
138 : sc::custom_reaction<EvControlNodeInSync>
139 : > reactions;
140 :
141 0 : TrafficSeen(my_context ctx) : my_base(ctx) {
142 0 : PathPreferenceSM *state_machine = &context<PathPreferenceSM>();
143 : //Enqueue a route change
144 0 : if (state_machine->wait_for_traffic() == true) {
145 0 : state_machine->UpdateFlapTime();
146 0 : uint32_t seq = state_machine->max_sequence();
147 0 : state_machine->set_wait_for_traffic(false);
148 0 : seq++;
149 0 : state_machine->set_max_sequence(seq);
150 0 : if (state_machine->is_dependent_rt() == false) {
151 0 : state_machine->set_sequence(seq);
152 : }
153 0 : state_machine->set_preference(PathPreference::HIGH);
154 0 : state_machine->EnqueuePathChange();
155 0 : state_machine->UpdateDependentRoute();
156 0 : state_machine->Log("Traffic seen");
157 : }
158 0 : }
159 :
160 0 : sc::result react(const EvTrafficSeen &event) {
161 0 : return discard_event();
162 : }
163 :
164 0 : sc::result react(const EvWaitForTraffic &event) {
165 0 : return transit<WaitForTraffic>();
166 : }
167 :
168 0 : sc::result react(const EvSeqChange &event) {
169 0 : PathPreferenceSM *state_machine = &context<PathPreferenceSM>();
170 0 : if (event.sequence_ > state_machine->sequence()) {
171 0 : state_machine->set_max_sequence(event.sequence_);
172 0 : state_machine->Log("TrafficSeen EvSeqChange");
173 0 : if (state_machine->IsPathFlapping()) {
174 : //If path is continuosly flapping
175 : //delay wihtdrawing of route
176 0 : if (state_machine->RetryTimerRunning() == false) {
177 0 : state_machine->IncreaseRetryTimeout();
178 0 : state_machine->StartRetryTimer();
179 0 : state_machine->Log("Back off and retry update");
180 : }
181 0 : return discard_event();
182 : }
183 : }
184 0 : return transit<WaitForTraffic>();
185 : }
186 :
187 0 : sc::result react(const EvActiveActiveMode &event) {
188 0 : return transit<ActiveActiveState>();
189 : }
190 :
191 0 : sc::result react(const EvControlNodeInSync &event) {
192 0 : PathPreferenceSM *state_machine = &context<PathPreferenceSM>();
193 0 : state_machine->Log("in sync with control-node");
194 0 : return discard_event();
195 : }
196 : };
197 :
198 : struct ActiveActiveState : sc::state<ActiveActiveState, PathPreferenceSM> {
199 : typedef mpl::list<
200 : sc::custom_reaction<EvTrafficSeen>,
201 : sc::custom_reaction<EvSeqChange>,
202 : sc::custom_reaction<EvWaitForTraffic>,
203 : sc::custom_reaction<EvActiveActiveMode>,
204 : sc::custom_reaction<EvControlNodeInSync>
205 : > reactions;
206 :
207 0 : ActiveActiveState(my_context ctx) : my_base(ctx) {
208 0 : PathPreferenceSM *state_machine = &context<PathPreferenceSM>();
209 : //Enqueue a route change
210 0 : if (state_machine->preference() == PathPreference::LOW ||
211 0 : state_machine->wait_for_traffic() == true) {
212 0 : state_machine->set_wait_for_traffic(false);
213 0 : uint32_t seq = 0;
214 0 : state_machine->set_max_sequence(seq);
215 0 : state_machine->set_sequence(seq);
216 0 : state_machine->set_preference(PathPreference::HIGH);
217 0 : state_machine->EnqueuePathChange();
218 0 : state_machine->UpdateDependentRoute();
219 0 : state_machine->Log("Ecmp path");
220 : }
221 0 : }
222 :
223 0 : sc::result react(const EvTrafficSeen &event) {
224 0 : return discard_event();
225 : }
226 :
227 0 : sc::result react(const EvWaitForTraffic &event) {
228 0 : return transit<WaitForTraffic>();
229 : }
230 :
231 0 : sc::result react(const EvSeqChange &event) {
232 0 : PathPreferenceSM *state_machine = &context<PathPreferenceSM>();
233 0 : state_machine->set_max_sequence(event.sequence_);
234 0 : state_machine->Log("ActiveActiveState EvSeqChange");
235 0 : return transit<WaitForTraffic>();
236 : }
237 :
238 0 : sc::result react(const EvActiveActiveMode &event) {
239 0 : return discard_event();
240 : }
241 :
242 0 : sc::result react(const EvControlNodeInSync &event) {
243 0 : return discard_event();
244 : }
245 : };
246 :
247 0 : PathPreferenceSM::PathPreferenceSM(Agent *agent, const Peer *peer,
248 : AgentRoute *rt, bool is_dependent_route,
249 0 : const PathPreference &pref): agent_(agent), peer_(peer),
250 0 : rt_(rt), path_preference_(0, PathPreference::LOW, false, false),
251 0 : max_sequence_(0), timer_(NULL), timeout_(kMinInterval),
252 0 : flap_count_(0), is_dependent_rt_(is_dependent_route),
253 0 : dependent_rt_(this) {
254 0 : path_preference_ = pref;
255 0 : initiate();
256 0 : process_event(EvStart());
257 0 : backoff_timer_fired_time_ = UTCTimestampUsec();
258 0 : }
259 :
260 0 : PathPreferenceSM::~PathPreferenceSM() {
261 0 : if (timer_ != NULL) {
262 0 : timer_->Cancel();
263 0 : TimerManager::DeleteTimer(timer_);
264 : }
265 :
266 0 : PathDependencyList::iterator iter = dependent_routes_.begin();
267 0 : for (;iter != dependent_routes_.end(); iter++) {
268 0 : PathPreferenceSM *path_sm = iter.operator->();
269 0 : path_sm->process_event(EvWaitForTraffic());
270 : }
271 :
272 0 : timer_ = NULL;
273 0 : }
274 :
275 0 : bool PathPreferenceSM::Retry() {
276 0 : flap_count_ = 0;
277 0 : backoff_timer_fired_time_ = UTCTimestampUsec();
278 0 : process_event(EvWaitForTraffic());
279 0 : return false;
280 : }
281 :
282 0 : void PathPreferenceSM::StartRetryTimer() {
283 0 : if (timer_ == NULL) {
284 0 : timer_ = TimerManager::CreateTimer(
285 0 : *(agent_->event_manager())->io_service(),
286 : "Stale cleanup timer",
287 : TaskScheduler::GetInstance()->GetTaskId("db::DBTable"),
288 : 0, false);
289 : }
290 0 : timer_->Start(timeout_,
291 : boost::bind(&PathPreferenceSM::Retry, this));
292 0 : }
293 :
294 0 : void PathPreferenceSM::CancelRetryTimer() {
295 0 : if (timer_ == NULL) {
296 0 : return;
297 : }
298 0 : timer_->Cancel();
299 : }
300 :
301 0 : bool PathPreferenceSM::RetryTimerRunning() {
302 0 : if (timer_ == NULL) {
303 0 : return false;
304 : }
305 0 : return timer_->running();
306 : }
307 :
308 0 : void PathPreferenceSM::IncreaseRetryTimeout() {
309 0 : timeout_ = timeout_ * 2;
310 0 : if (timeout_ > kMaxInterval) {
311 0 : timeout_ = kMaxInterval;
312 : }
313 0 : }
314 :
315 0 : bool PathPreferenceSM::IsFlap() const {
316 0 : uint64_t time_sec = (UTCTimestampUsec() -
317 0 : last_stable_high_priority_change_at_)/1000;
318 0 : if (time_sec > kMinInterval) {
319 0 : return false;
320 : }
321 0 : return true;
322 : }
323 :
324 0 : void PathPreferenceSM::DecreaseRetryTimeout() {
325 : uint64_t time_sec =
326 0 : (UTCTimestampUsec() - backoff_timer_fired_time_)/1000;
327 0 : if (time_sec > kMinInterval) {
328 0 : timeout_ = kMinInterval;
329 : }
330 0 : }
331 :
332 0 : void PathPreferenceSM::UpdateFlapTime() {
333 0 : if (IsFlap()) {
334 0 : flap_count_++;
335 : } else {
336 0 : DecreaseRetryTimeout();
337 0 : last_stable_high_priority_change_at_ = UTCTimestampUsec();
338 0 : flap_count_ = 0;
339 : }
340 0 : }
341 :
342 0 : bool PathPreferenceSM::IsPathFlapping() const {
343 0 : if (flap_count_ >= kMaxFlapCount && IsFlap()) {
344 0 : return true;
345 : }
346 0 : return false;
347 : }
348 :
349 0 : void PathPreferenceSM::UpdateDependentRoute() {
350 0 : if (is_dependent_rt_ == true) {
351 0 : return;
352 : }
353 :
354 0 : PathDependencyList::iterator iter = dependent_routes_.begin();
355 0 : for (;iter != dependent_routes_.end(); iter++) {
356 0 : PathPreferenceSM *path_sm = iter.operator->();
357 0 : if (path_preference_.preference() == PathPreference::HIGH) {
358 0 : path_sm->process_event(EvTrafficSeen());
359 : } else {
360 0 : path_sm->process_event(EvWaitForTraffic());
361 : }
362 : }
363 : }
364 :
365 0 : void PathPreferenceSM::Process() {
366 0 : uint32_t max_sequence = 0;
367 0 : const AgentPath *best_path = NULL;
368 0 : bool maciplearning_prefix = false;
369 0 : const AgentPath *local_path = rt_->FindPath(peer_);
370 : //Dont act on notification of derived routes
371 0 : if (is_dependent_rt_) {
372 0 : path_preference_.set_ecmp(local_path->path_preference().ecmp());
373 0 : if (dependent_rt_.get()) {
374 0 : if (dependent_rt_->path_preference_.preference() ==
375 : PathPreference::HIGH) {
376 0 : process_event(EvTrafficSeen());
377 : } else {
378 0 : process_event(EvWaitForTraffic());
379 : }
380 : }
381 0 : return;
382 : }
383 :
384 0 : if (local_path->path_preference().ecmp() == true) {
385 0 : path_preference_.set_ecmp(true);
386 : //If a path is ecmp, just set the priority to HIGH
387 0 : process_event(EvActiveActiveMode());
388 0 : return;
389 : }
390 :
391 0 : if (ecmp() == true) {
392 0 : path_preference_.set_ecmp(local_path->path_preference().ecmp());
393 : //Route transition from ECMP to non ECMP,
394 : //move to wait for traffic state
395 0 : process_event(EvWaitForTraffic());
396 0 : return;
397 : }
398 :
399 : //Check if BGP path is present
400 0 : for (Route::PathList::iterator it = rt_->GetPathList().begin();
401 0 : it != rt_->GetPathList().end(); ++it) {
402 : const AgentPath *path =
403 0 : static_cast<const AgentPath *>(it.operator->());
404 0 : if (path == local_path) {
405 0 : if (path->path_preference().sequence() < sequence()) {
406 0 : EnqueuePathChange();
407 : }
408 0 : continue;
409 : }
410 : //Get best preference and sequence no from all BGP peer
411 0 : if (max_sequence < path->sequence()) {
412 0 : max_sequence = path->sequence();
413 0 : best_path = path;
414 : }
415 : }
416 :
417 0 : if (!best_path) {
418 0 : return;
419 : }
420 :
421 : //Skip seq number change for macip learning prefix inet rt path in waitfortraffic state to exclude stale paths
422 0 : if ( rt_->vrf() && rt_->vrf()->vn() && rt_->vrf()->vn()->mac_ip_learning_enable()) {
423 0 : MacIpLearningEntry *entry = NULL;
424 : const InetUnicastRouteEntry *inet_rt =
425 0 : dynamic_cast<const InetUnicastRouteEntry *>(rt_);
426 0 : if ( inet_rt != NULL) {
427 0 : MacIpLearningKey macip_entry_key(rt_->vrf()->vrf_id(), inet_rt->prefix_address());
428 0 : entry = agent_->mac_learning_proto()->
429 0 : GetMacIpLearningTable()->Find(macip_entry_key);
430 : }
431 0 : if (entry != NULL && wait_for_traffic() ==true) {
432 0 : maciplearning_prefix = true;
433 0 : if (max_sequence > sequence()) {
434 0 : Log("WaitForTraffic EvSeqChange skipped ");
435 : }
436 : }
437 : }
438 0 : if ((max_sequence > sequence()) && (maciplearning_prefix == false)) {
439 0 : process_event(EvSeqChange(max_sequence));
440 0 : } else if (sequence() == max_sequence &&
441 0 : best_path->ComputeNextHop(agent_) ==
442 0 : local_path->ComputeNextHop(agent_)) {
443 : //Control node chosen path and local path are same
444 0 : process_event(EvControlNodeInSync());
445 0 : } else if (sequence() == max_sequence &&
446 0 : best_path->ComputeNextHop(agent_) !=
447 0 : local_path->ComputeNextHop(agent_)) {
448 0 : process_event(EvWaitForTraffic());
449 : }
450 :
451 0 : UpdateDependentRoute();
452 : }
453 :
454 0 : void PathPreferenceSM::Log(std::string state) {
455 0 : std::string dependent_ip_str = "";
456 0 : if (is_dependent_rt()) {
457 0 : dependent_ip_str = dependent_ip().to_string();
458 : }
459 :
460 0 : PATH_PREFERENCE_TRACE(rt_->vrf()->GetName(), rt_->GetAddressString(),
461 : preference(), sequence(), state, timeout(),
462 : dependent_ip_str, flap_count_, max_sequence_);
463 0 : }
464 :
465 0 : void PathPreferenceSM::EnqueuePathChange() {
466 0 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
467 0 : req.key = rt_->GetDBRequestKey();
468 0 : AgentRouteKey *key = static_cast<AgentRouteKey *>(req.key.get());
469 0 : key->sub_op_ = AgentKey::RESYNC;
470 0 : key->set_peer(peer_);
471 0 : req.data.reset(new PathPreferenceData(path_preference_));
472 :
473 0 : if (rt_->vrf() == NULL) {
474 0 : return;
475 : }
476 :
477 0 : AgentRouteTable *table = NULL;
478 0 : if (rt_->GetTableType() == Agent::EVPN) {
479 0 : table = agent_->fabric_evpn_table();
480 0 : } else if (rt_->GetTableType() == Agent::INET4_UNICAST) {
481 0 : table = agent_->fabric_inet4_unicast_table();
482 0 : } else if (rt_->GetTableType() == Agent::INET4_MPLS) {
483 0 : table = agent_->fabric_inet4_mpls_table();
484 0 : } else if (rt_->GetTableType() == Agent::INET6_UNICAST) {
485 0 : table = agent_->fabric_inet4_unicast_table();
486 : }
487 :
488 0 : if (table) {
489 0 : table->Enqueue(&req);
490 : }
491 0 : }
492 :
493 0 : PathPreferenceIntfState::RouteAddrList::RouteAddrList() :
494 0 : family_(Address::INET), ip_(), plen_(0), vrf_name_(), seen_(false) {
495 0 : }
496 :
497 0 : PathPreferenceIntfState::RouteAddrList::RouteAddrList
498 : (const Address::Family &family, const IpAddress &ip, uint32_t plen,
499 0 : const std::string &vrf) :
500 0 : family_(family), ip_(ip), plen_(plen), vrf_name_(vrf), seen_(false) {
501 0 : }
502 :
503 0 : bool PathPreferenceIntfState::RouteAddrList::operator<(
504 : const RouteAddrList &rhs) const {
505 0 : if (family_ != rhs.family_) {
506 0 : return family_ < rhs.family_;
507 : }
508 :
509 0 : if (ip_ != rhs.ip_) {
510 0 : return ip_ < rhs.ip_;
511 : }
512 :
513 0 : if (plen_ != rhs.plen_) {
514 0 : return plen_ < rhs.plen_;
515 : }
516 :
517 0 : return vrf_name_ < rhs.vrf_name_;
518 : }
519 :
520 0 : bool PathPreferenceIntfState::RouteAddrList::operator==(
521 : const RouteAddrList &rhs) const {
522 0 : if ((family_ == rhs.family_) && (ip_ == rhs.ip_) &&
523 0 : (plen_ == rhs.plen_) && (vrf_name_ == rhs.vrf_name_)) {
524 0 : return true;
525 : }
526 0 : return false;
527 : }
528 :
529 0 : PathPreferenceIntfState::PathPreferenceIntfState(const VmInterface *intf):
530 0 : intf_(intf) {
531 0 : }
532 :
533 0 : PathPreferenceState::PathPreferenceState(Agent *agent,
534 0 : AgentRoute *rt): agent_(agent), rt_(rt) {
535 0 : }
536 :
537 0 : PathPreferenceState::~PathPreferenceState() {
538 : PeerPathPreferenceMap::iterator path_preference_it =
539 0 : path_preference_peer_map_.begin();
540 0 : while (path_preference_it != path_preference_peer_map_.end()) {
541 0 : PeerPathPreferenceMap::iterator prev_it = path_preference_it++;
542 0 : PathPreferenceSM *path_preference_sm = prev_it->second;
543 0 : delete path_preference_sm;
544 0 : path_preference_peer_map_.erase(prev_it);
545 : }
546 :
547 : PathPreferenceModule *path_module =
548 0 : agent_->oper_db()->route_preference_module();
549 0 : path_module->DeleteUnresolvedPath(this);
550 0 : }
551 :
552 : //Given a VRF table the table listener id for given route
553 : bool
554 0 : PathPreferenceState::GetRouteListenerId(const VrfEntry* vrf,
555 : const Agent::RouteTableType &table_type,
556 : DBTableBase::ListenerId &rt_id) const {
557 0 : if (vrf == NULL) {
558 0 : return false;
559 : }
560 :
561 : DBTableBase::ListenerId vrf_id =
562 0 : agent_->oper_db()->route_preference_module()->vrf_id();
563 : const PathPreferenceVrfState *vrf_state =
564 : static_cast<const PathPreferenceVrfState *>(
565 0 : vrf->GetState(agent_->vrf_table(), vrf_id));
566 0 : if (!vrf_state) {
567 0 : return false;
568 : }
569 :
570 0 : rt_id = DBTableBase::kInvalidId;
571 0 : if (table_type == Agent::EVPN) {
572 0 : rt_id = vrf_state->evpn_rt_id_;
573 0 : } else if (table_type == Agent::INET4_UNICAST) {
574 0 : rt_id = vrf_state->uc_rt_id_;
575 0 : } else if (table_type == Agent::INET4_MPLS) {
576 0 : rt_id = vrf_state->mpls_rt_id_;
577 0 : } else if (table_type == Agent::INET6_UNICAST) {
578 0 : rt_id = vrf_state->uc6_rt_id_;
579 : } else {
580 0 : return false;
581 : }
582 :
583 0 : return true;
584 : }
585 :
586 : PathPreferenceSM*
587 0 : PathPreferenceState::GetDependentPath(const AgentPath *path) const {
588 :
589 0 : if (path->path_preference().IsDependentRt() == false) {
590 0 : return NULL;
591 : }
592 0 : uint32_t plen = 32;
593 0 : if (path->path_preference().dependent_ip().is_v6()) {
594 0 : plen = 128;
595 : }
596 :
597 0 : InetUnicastRouteKey key(path->peer(), path->path_preference().vrf(),
598 0 : path->path_preference().dependent_ip(), plen);
599 : const VrfEntry *vrf =
600 0 : agent_->vrf_table()->FindVrfFromName(path->path_preference().vrf());
601 0 : if (!vrf) {
602 0 : return NULL;
603 : }
604 :
605 0 : AgentRouteTable *table = NULL;
606 0 : Agent::RouteTableType table_type = Agent::INET4_UNICAST;
607 0 : if (path->path_preference().dependent_ip().is_v4()) {
608 : table = static_cast<AgentRouteTable *>(
609 0 : vrf->GetInet4UnicastRouteTable());
610 0 : } else if (path->path_preference().dependent_ip().is_v6()) {
611 : table = static_cast<AgentRouteTable *>(
612 0 : vrf->GetInet6UnicastRouteTable());
613 0 : table_type = Agent::INET6_UNICAST;
614 : }
615 0 : AgentRoute *rt = static_cast<AgentRoute *>(table->Find(&key));
616 0 : if (rt == NULL) {
617 0 : return NULL;
618 : }
619 :
620 0 : DBTableBase::ListenerId rt_id = DBTableBase::kInvalidId;
621 0 : GetRouteListenerId(vrf, table_type, rt_id);
622 :
623 : PathPreferenceState *state = static_cast<PathPreferenceState *>(
624 0 : rt->GetState(table, rt_id));
625 0 : if (state == NULL) {
626 0 : return NULL;
627 : }
628 0 : return state->GetSM(path->peer());
629 0 : }
630 :
631 0 : void PathPreferenceState::Process(bool &should_resolve) {
632 : PathPreferenceModule *path_module =
633 0 : agent_->oper_db()->route_preference_module();
634 : //Set all the path as not seen, eventually when path is seen
635 : //flag would be set appropriatly
636 : PeerPathPreferenceMap::iterator path_preference_it =
637 0 : path_preference_peer_map_.begin();
638 0 : while (path_preference_it != path_preference_peer_map_.end()) {
639 0 : PathPreferenceSM *path_preference_sm = path_preference_it->second;
640 0 : path_preference_sm->set_seen(false);
641 0 : path_preference_it++;
642 : }
643 :
644 0 : for (Route::PathList::iterator it = rt_->GetPathList().begin();
645 0 : it != rt_->GetPathList().end(); ++it) {
646 : const AgentPath *path =
647 0 : static_cast<const AgentPath *>(it.operator->());
648 0 : if (path->peer() == NULL) {
649 0 : continue;
650 : }
651 0 : if (path->peer()->GetType() != Peer::LOCAL_VM_PORT_PEER) {
652 0 : continue;
653 : }
654 :
655 0 : bool new_path_added = false;
656 : PathPreferenceSM *path_preference_sm;
657 0 : if (path_preference_peer_map_.find(path->peer()) ==
658 0 : path_preference_peer_map_.end()) {
659 : //Add new path
660 0 : path_preference_sm =
661 0 : new PathPreferenceSM(agent_, path->peer(), rt_,
662 0 : false, path->path_preference());
663 0 : path_preference_peer_map_.insert(
664 0 : std::pair<const Peer *, PathPreferenceSM *>
665 0 : (path->peer(), path_preference_sm));
666 0 : new_path_added = true;
667 : } else {
668 0 : path_preference_sm =
669 0 : path_preference_peer_map_.find(path->peer())->second;
670 : }
671 0 : bool dependent_rt = path->path_preference().IsDependentRt();
672 0 : if (dependent_rt) {
673 0 : PathPreferenceSM *sm = GetDependentPath(path);
674 0 : if (sm == NULL) {
675 : //Path is unresolved,
676 : //add it to unresolved list
677 0 : path_module->AddUnresolvedPath(this);
678 : } else {
679 0 : path_module->DeleteUnresolvedPath(this);
680 : }
681 0 : path_preference_sm->set_dependent_rt(sm);
682 : } else {
683 0 : path_preference_sm->set_dependent_rt(NULL);
684 : }
685 0 : path_preference_sm->set_is_dependent_rt(dependent_rt);
686 0 : path_preference_sm->set_dependent_ip(
687 0 : path->path_preference().dependent_ip());
688 :
689 0 : path_preference_sm->set_seen(true);
690 0 : path_preference_sm->Process();
691 :
692 0 : if (dependent_rt == false && new_path_added) {
693 0 : should_resolve = true;
694 : }
695 : }
696 :
697 : //Delete all path not seen, in latest path list
698 0 : path_preference_it = path_preference_peer_map_.begin();
699 0 : while (path_preference_it != path_preference_peer_map_.end()) {
700 0 : PeerPathPreferenceMap::iterator prev_it = path_preference_it++;
701 0 : PathPreferenceSM *path_preference_sm = prev_it->second;
702 0 : if (path_preference_sm->seen() == false) {
703 0 : delete path_preference_sm;
704 0 : path_preference_peer_map_.erase(prev_it);
705 : }
706 : }
707 0 : }
708 :
709 0 : PathPreferenceSM* PathPreferenceState::GetSM(const Peer *peer) {
710 0 : if (path_preference_peer_map_.find(peer) ==
711 0 : path_preference_peer_map_.end()) {
712 0 : return NULL;
713 : }
714 0 : return path_preference_peer_map_.find(peer)->second;
715 : }
716 :
717 0 : PathPreferenceRouteListener::PathPreferenceRouteListener(Agent *agent,
718 0 : AgentRouteTable *table): agent_(agent), rt_table_(table),
719 0 : id_(DBTableBase::kInvalidId), table_delete_ref_(this, table->deleter()),
720 0 : deleted_(false) {
721 : managed_delete_walk_ref_ = table->
722 0 : AllocWalker(boost::bind(&PathPreferenceRouteListener::DeleteState,
723 : this, _1, _2),
724 : boost::bind(&PathPreferenceRouteListener::Walkdone, this,
725 0 : _1, _2, this));
726 0 : }
727 :
728 0 : void PathPreferenceRouteListener::Init() {
729 0 : id_ = rt_table_->Register(boost::bind(&PathPreferenceRouteListener::Notify,
730 : this,
731 : _1, _2));
732 0 : }
733 :
734 0 : void PathPreferenceRouteListener::Delete() {
735 0 : set_deleted();
736 : //Managed delete walk need to be done only once.
737 0 : if (managed_delete_walk_ref_.get()) {
738 0 : rt_table_->WalkAgain(managed_delete_walk_ref_);
739 : }
740 0 : }
741 :
742 0 : void PathPreferenceRouteListener::ManagedDelete() {
743 0 : Delete();
744 0 : }
745 :
746 0 : void PathPreferenceRouteListener::Walkdone(DBTable::DBTableWalkRef walk_ref,
747 : DBTableBase *partition,
748 : PathPreferenceRouteListener *state) {
749 0 : rt_table_->Unregister(id_);
750 0 : table_delete_ref_.Reset(NULL);
751 0 : if (walk_ref.get() != NULL)
752 0 : (static_cast<DBTable *>(partition))->ReleaseWalker(walk_ref);
753 0 : managed_delete_walk_ref_ = NULL;
754 0 : delete state;
755 0 : }
756 :
757 0 : bool PathPreferenceRouteListener::DeleteState(DBTablePartBase *partition,
758 : DBEntryBase *e) {
759 : PathPreferenceState *state =
760 0 : static_cast<PathPreferenceState *>(e->GetState(rt_table_, id_));
761 0 : if (state) {
762 0 : e->ClearState(rt_table_, id_);
763 0 : delete state;
764 : }
765 0 : return true;
766 : }
767 :
768 0 : void PathPreferenceRouteListener::Notify(DBTablePartBase *partition,
769 : DBEntryBase *e) {
770 : PathPreferenceState *state =
771 0 : static_cast<PathPreferenceState *>(e->GetState(rt_table_, id_));
772 0 : if (e->IsDeleted()) {
773 0 : if (state) {
774 0 : e->ClearState(rt_table_, id_);
775 0 : delete state;
776 : }
777 0 : return;
778 : }
779 :
780 0 : if (deleted_) return;
781 :
782 0 : AgentRoute *rt = static_cast<AgentRoute *>(e);
783 0 : for (Route::PathList::iterator it = rt->GetPathList().begin();
784 0 : it != rt->GetPathList().end(); ++it) {
785 : const AgentPath *path =
786 0 : static_cast<const AgentPath *>(it.operator->());
787 0 : if (path->peer() == NULL) {
788 0 : continue;
789 : }
790 0 : if (path->peer()->GetType() != Peer::LOCAL_VM_PORT_PEER) {
791 0 : continue;
792 : }
793 0 : if (path->path_preference().static_preference() == true) {
794 0 : return;
795 : }
796 : }
797 :
798 0 : if (!state) {
799 0 : state = new PathPreferenceState(agent_, rt);
800 : }
801 0 : bool should_resolve = false;
802 0 : state->Process(should_resolve);
803 0 : e->SetState(rt_table_, id_, state);
804 :
805 0 : if (should_resolve) {
806 : PathPreferenceModule *path_module =
807 0 : agent_->oper_db()->route_preference_module();
808 0 : path_module->Resolve();
809 : }
810 : }
811 :
812 0 : PathPreferenceModule::PathPreferenceModule(Agent *agent):
813 0 : agent_(agent), vrf_id_(DBTableBase::kInvalidId),
814 0 : work_queue_(TaskScheduler::GetInstance()->GetTaskId("db::DBTable"), 0,
815 0 : boost::bind(&PathPreferenceModule::DequeueEvent, this, _1)) {
816 0 : work_queue_.set_name("Path Preference");
817 0 : }
818 :
819 0 : bool PathPreferenceModule::DequeueEvent(PathPreferenceEventContainer event) {
820 : const Interface *intf =
821 0 : agent_->interface_table()->FindInterface(event.interface_index_);
822 0 : if (intf == NULL || (intf->type() != Interface::VM_INTERFACE)) {
823 0 : return true;
824 : }
825 :
826 0 : const VmInterface *vm_intf = static_cast<const VmInterface *>(intf);
827 :
828 : const VrfEntry *vrf =
829 0 : agent_->vrf_table()->FindVrfFromId(event.vrf_index_);
830 0 : if (vrf == NULL) {
831 0 : return true;
832 : }
833 :
834 : const PathPreferenceVrfState *state =
835 : static_cast<const PathPreferenceVrfState *>(
836 0 : vrf->GetState(agent_->vrf_table(), vrf_id_));
837 :
838 0 : if (!state) {
839 0 : return true;
840 : }
841 :
842 0 : PathPreferenceState *path_preference = NULL;
843 0 : PathPreferenceSM *path_preference_sm = NULL;
844 0 : const PathPreferenceState *cpath_preference = NULL;
845 :
846 : EvpnRouteKey evpn_key(NULL, vrf->GetName(),
847 0 : event.mac_, event.ip_,
848 0 : EvpnAgentRouteTable::ComputeHostIpPlen(event.ip_),
849 0 : event.vxlan_id_);
850 : const EvpnRouteEntry *evpn_rt =
851 : static_cast<const EvpnRouteEntry *>(
852 0 : vrf->GetEvpnRouteTable()->FindActiveEntry(&evpn_key));
853 :
854 0 : if (evpn_rt) {
855 : cpath_preference = static_cast<const PathPreferenceState *>(
856 0 : evpn_rt->GetState(vrf->GetEvpnRouteTable(),
857 0 : state->evpn_rt_id_));
858 0 : if (cpath_preference) {
859 0 : path_preference = const_cast<PathPreferenceState *>(cpath_preference);
860 0 : path_preference_sm = path_preference->GetSM(vm_intf->peer());
861 0 : if (path_preference_sm) {
862 0 : EvTrafficSeen ev;
863 0 : path_preference_sm->process_event(ev);
864 0 : }
865 : }
866 : }
867 :
868 0 : EvpnRouteKey evpn_null_ip_key(NULL, vrf->GetName(), event.mac_,
869 0 : Ip4Address(0), 32, event.vxlan_id_);
870 : evpn_rt = static_cast<const EvpnRouteEntry *>(
871 0 : vrf->GetEvpnRouteTable()->FindActiveEntry(&evpn_null_ip_key));
872 0 : if (evpn_rt) {
873 : cpath_preference = static_cast<const PathPreferenceState *>(
874 0 : evpn_rt->GetState(vrf->GetEvpnRouteTable(),
875 0 : state->evpn_rt_id_));
876 0 : if (cpath_preference) {
877 0 : path_preference = const_cast<PathPreferenceState *>(cpath_preference);
878 0 : path_preference_sm = path_preference->GetSM(vm_intf->peer());
879 0 : if (path_preference_sm) {
880 0 : EvTrafficSeen ev;
881 0 : path_preference_sm->process_event(ev);
882 0 : }
883 : }
884 : }
885 :
886 0 : InetUnicastRouteKey rt_key(NULL, vrf->GetName(), event.ip_, event.plen_);
887 0 : const InetUnicastRouteEntry *rt = NULL;
888 0 : if (event.ip_.is_v4()) {
889 : rt = static_cast<const InetUnicastRouteEntry *>(
890 0 : vrf->GetInet4UnicastRouteTable()->FindActiveEntry(&rt_key));
891 0 : } else if(event.ip_.is_v6()) {
892 : rt = static_cast<const InetUnicastRouteEntry *>(
893 0 : vrf->GetInet6UnicastRouteTable()->FindActiveEntry(&rt_key));
894 : }
895 0 : if (!rt) {
896 0 : return true;
897 : }
898 :
899 0 : if (event.ip_.is_v4()) {
900 : cpath_preference = static_cast<const PathPreferenceState *>(
901 0 : rt->GetState(vrf->GetInet4UnicastRouteTable(), state->uc_rt_id_));
902 0 : } else if(event.ip_.is_v6()) {
903 : cpath_preference = static_cast<const PathPreferenceState *>(
904 0 : rt->GetState(vrf->GetInet6UnicastRouteTable(), state->uc6_rt_id_));
905 : }
906 0 : if (!cpath_preference) {
907 0 : return true;
908 : }
909 :
910 0 : path_preference = const_cast<PathPreferenceState *>(cpath_preference);
911 0 : path_preference_sm = path_preference->GetSM(vm_intf->peer());
912 0 : if (path_preference_sm) {
913 0 : EvTrafficSeen ev;
914 0 : path_preference_sm->process_event(ev);
915 0 : }
916 0 : return true;
917 0 : }
918 :
919 0 : void PathPreferenceModule::EnqueueTrafficSeen(IpAddress ip, uint32_t plen,
920 : uint32_t interface_index,
921 : uint32_t vrf_index,
922 : const MacAddress &mac) {
923 : const Interface *intf =
924 0 : agent_->interface_table()->FindInterface(interface_index);
925 0 : if (intf == NULL || (intf->type() != Interface::VM_INTERFACE)) {
926 0 : return;
927 : }
928 :
929 0 : const VmInterface *vm_intf = static_cast<const VmInterface *>(intf);
930 :
931 :
932 : //If the local preference is set by config, we dont identify Active
933 : //node dynamically
934 0 : if (vm_intf->local_preference() != 0) {
935 0 : return;
936 : }
937 :
938 0 : const VrfEntry *vrf = agent_->vrf_table()->FindVrfFromId(vrf_index);
939 0 : if (vrf == NULL) {
940 0 : return;
941 : }
942 :
943 0 : if (vrf == vm_intf->forwarding_vrf()) {
944 0 : vrf = vm_intf->vrf();
945 : }
946 :
947 0 : InetUnicastRouteEntry *rt = vrf->GetUcRoute(ip);
948 : EvpnRouteKey key(vm_intf->peer(), vrf->GetName(), mac, ip,
949 : EvpnAgentRouteTable::ComputeHostIpPlen(ip),
950 0 : vm_intf->ethernet_tag());
951 : EvpnRouteEntry *evpn_rt = static_cast<EvpnRouteEntry *>(
952 0 : vrf->GetEvpnRouteTable()->FindActiveEntry(&key));
953 0 : if (!rt && !evpn_rt) {
954 0 : return;
955 : }
956 :
957 0 : const AgentPath *path = NULL;
958 0 : const AgentPath *evpn_path = NULL;
959 :
960 0 : if (rt) {
961 0 : path = rt->FindPath(vm_intf->peer());
962 : }
963 0 : if (evpn_rt) {
964 0 : evpn_path = evpn_rt->FindPath(vm_intf->peer());
965 : }
966 :
967 0 : if (!path && !evpn_path) {
968 0 : return;
969 : }
970 :
971 0 : PathPreferenceEventContainer event;
972 0 : if (rt) {
973 0 : event.ip_ = rt->prefix_address();
974 0 : event.plen_ = rt->prefix_length();
975 : } else {
976 : // (0 IP + Mac) event required for EVPN
977 0 : event.ip_ = IpAddress();
978 0 : event.plen_ = 32;
979 : }
980 0 : event.interface_index_ = interface_index;
981 0 : event.vrf_index_ = vrf_index;
982 0 : event.mac_ = mac;
983 0 : event.vxlan_id_ = vm_intf->ethernet_tag();
984 0 : work_queue_.Enqueue(event);
985 :
986 0 : if (vm_intf->forwarding_vrf() != vm_intf->vrf() &&
987 0 : vm_intf->forwarding_vrf()->vrf_id() == vrf_index) {
988 0 : event.vrf_index_ = vm_intf->vrf()->vrf_id();
989 0 : work_queue_.Enqueue(event);
990 : }
991 0 : }
992 :
993 0 : void PathPreferenceModule::VrfNotify(DBTablePartBase *partition,
994 : DBEntryBase *e) {
995 0 : const VrfEntry *vrf = static_cast<const VrfEntry *>(e);
996 : PathPreferenceVrfState *vrf_state =
997 0 : static_cast<PathPreferenceVrfState *>(e->GetState(partition->parent(),
998 : vrf_id_));
999 :
1000 0 : if (vrf->IsDeleted()) {
1001 0 : if (vrf_state) {
1002 0 : e->ClearState(partition->parent(), vrf_id_);
1003 0 : delete vrf_state;
1004 : }
1005 0 : return;
1006 : }
1007 :
1008 0 : if (vrf_state) {
1009 0 : return;
1010 : }
1011 :
1012 : PathPreferenceRouteListener *uc_rt_listener =
1013 : new PathPreferenceRouteListener(agent_,
1014 0 : vrf->GetInet4UnicastRouteTable());
1015 0 : uc_rt_listener->Init();
1016 :
1017 : PathPreferenceRouteListener *evpn_rt_listener =
1018 : new PathPreferenceRouteListener(agent_,
1019 0 : vrf->GetEvpnRouteTable());
1020 0 : evpn_rt_listener->Init();
1021 :
1022 : PathPreferenceRouteListener *uc6_rt_listener =
1023 : new PathPreferenceRouteListener(agent_,
1024 0 : vrf->GetInet6UnicastRouteTable());
1025 0 : uc6_rt_listener->Init();
1026 : PathPreferenceRouteListener *mpls_rt_listener =
1027 : new PathPreferenceRouteListener(agent_,
1028 0 : vrf->GetInet4MplsUnicastRouteTable());
1029 0 : mpls_rt_listener->Init();
1030 :
1031 0 : vrf_state = new PathPreferenceVrfState(uc_rt_listener->id(),
1032 0 : evpn_rt_listener->id(),
1033 0 : uc6_rt_listener->id(),
1034 0 : mpls_rt_listener->id());
1035 :
1036 0 : e->SetState(partition->parent(), vrf_id_, vrf_state);
1037 0 : return;
1038 : }
1039 :
1040 0 : void PathPreferenceModule::AddUnresolvedPath(PathPreferenceState *sm) {
1041 0 : unresolved_paths_.insert(sm);
1042 0 : }
1043 :
1044 0 : void PathPreferenceModule::DeleteUnresolvedPath(PathPreferenceState *sm) {
1045 0 : std::set<PathPreferenceState *>::iterator it = unresolved_paths_.find(sm);
1046 0 : if (it != unresolved_paths_.end()) {
1047 0 : unresolved_paths_.erase(it);
1048 : }
1049 0 : }
1050 :
1051 0 : void PathPreferenceModule::Resolve() {
1052 0 : std::set<PathPreferenceState *> tmp = unresolved_paths_;
1053 0 : unresolved_paths_.clear();
1054 :
1055 0 : bool resolve_path = false;
1056 : //Process all the elements
1057 0 : std::set<PathPreferenceState *>::iterator it = tmp.begin();
1058 0 : for(; it != tmp.end(); it++) {
1059 0 : (*it)->Process(resolve_path);
1060 : }
1061 0 : }
1062 :
1063 0 : void PathPreferenceModule::Init() {
1064 0 : vrf_id_ = agent_->vrf_table()->Register(
1065 : boost::bind(&PathPreferenceModule::VrfNotify, this, _1, _2));
1066 0 : }
1067 :
1068 0 : void PathPreferenceModule::Shutdown() {
1069 0 : agent_->vrf_table()->Unregister(vrf_id_);
1070 0 : }
|