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