LCOV - code coverage report
Current view: top level - vnsw/agent/oper - path_preference.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 464 610 76.1 %
Date: 2026-08-17 02:09:53 Functions: 52 70 74.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14