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