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