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: 443 610 72.6 %
Date: 2026-11-09 02:10:49 Functions: 48 70 68.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14