LCOV - code coverage report
Current view: top level - vnsw/agent/services - icmpv6_proto.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 234 494 47.4 %
Date: 2026-11-09 02:10:49 Functions: 29 57 50.9 %
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             : 
       6             : #include "base/os.h"
       7             : #include <init/agent_init.h>
       8             : #include <pkt/pkt_handler.h>
       9             : #include "pkt/pkt_init.h"
      10             : #include <oper/route_common.h>
      11             : #include <services/icmpv6_proto.h>
      12             : #include "mac_learning/mac_learning_proto.h"
      13             : 
      14           2 : Icmpv6Proto::Icmpv6Proto(Agent *agent, boost::asio::io_context &io) :
      15           2 :     Proto(agent, "Agent::Services", PktHandler::ICMPV6, io) {
      16             :     // limit the number of entries in the workqueue
      17           2 :     work_queue_.SetSize(agent->params()->services_queue_limit());
      18           2 :     work_queue_.SetBounded(true);
      19             : 
      20           2 :     vn_table_listener_id_ = agent->vn_table()->Register(
      21             :                              boost::bind(&Icmpv6Proto::VnNotify, this, _2));
      22           2 :     vrf_table_listener_id_ = agent->vrf_table()->Register(
      23             :                              boost::bind(&Icmpv6Proto::VrfNotify, this, _1, _2));
      24           2 :     interface_listener_id_ = agent->interface_table()->Register(
      25             :                              boost::bind(&Icmpv6Proto::InterfaceNotify,
      26             :                                          this, _2));
      27           2 :     nexthop_listener_id_ = agent->nexthop_table()->Register(
      28             :                            boost::bind(&Icmpv6Proto::NexthopNotify, this, _2));
      29             : 
      30           2 :     boost::shared_ptr<PktInfo> pkt_info(new PktInfo(PktHandler::ICMPV6, NULL));
      31           2 :     icmpv6_handler_.reset(new Icmpv6Handler(agent, pkt_info, io));
      32             : 
      33           2 :     timer_ = TimerManager::CreateTimer(io, "Icmpv6Timer",
      34             :              TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
      35             :              PktHandler::ICMPV6);
      36           2 :     timer_->Start(kRouterAdvertTimeout,
      37             :                   boost::bind(&Icmpv6Handler::RouterAdvertisement,
      38             :                   icmpv6_handler_.get(), this));
      39           2 : }
      40             : 
      41           4 : Icmpv6Proto::~Icmpv6Proto() {
      42           4 : }
      43             : 
      44           2 : void Icmpv6Proto::Shutdown() {
      45           2 :     agent_->vn_table()->Unregister(vn_table_listener_id_);
      46           2 :     agent_->vrf_table()->Unregister(vrf_table_listener_id_);
      47           2 :     agent_->interface_table()->Unregister(interface_listener_id_);
      48           2 :     timer_->Cancel();
      49           2 :     TimerManager::DeleteTimer(timer_);
      50           2 : }
      51             : 
      52           0 : ProtoHandler *Icmpv6Proto::AllocProtoHandler(boost::shared_ptr<PktInfo> info,
      53             :                                              boost::asio::io_context &io) {
      54           0 :     return new Icmpv6Handler(agent(), info, io);
      55             : }
      56             : 
      57          74 : Icmpv6VrfState *Icmpv6Proto::CreateAndSetVrfState(VrfEntry *vrf) {
      58             :     Icmpv6VrfState *state = new Icmpv6VrfState(agent_, this, vrf,
      59          74 :                                                vrf->GetInet6UnicastRouteTable(),
      60          74 :                                                vrf->GetEvpnRouteTable());
      61          74 :     state->set_route_table_listener_id(vrf->GetInet6UnicastRouteTable()->
      62          74 :         Register(boost::bind(&Icmpv6VrfState::RouteUpdate, state, _1, _2)));
      63          74 :     state->set_evpn_route_table_listener_id(vrf->GetEvpnRouteTable()->
      64          74 :         Register(boost::bind(&Icmpv6VrfState::EvpnRouteUpdate, state,  _1, _2)));
      65          74 :     vrf->SetState(vrf->get_table_partition()->parent(),
      66             :                   vrf_table_listener_id_, state);
      67          74 :     return state;
      68             : }
      69             : 
      70         269 : void Icmpv6Proto::VnNotify(DBEntryBase *entry) {
      71         269 :     if (entry->IsDeleted()) return;
      72             : 
      73         200 :     VnEntry *vn = static_cast<VnEntry *>(entry);
      74         200 :     VrfEntry *vrf = vn->GetVrf();
      75         200 :     if (!vrf || vrf->IsDeleted()) return;
      76             : 
      77         124 :     if (vrf->GetName() == agent_->fabric_vrf_name())
      78           0 :         return;
      79             : 
      80         124 :     if (vn->layer3_forwarding()) {
      81         124 :         Icmpv6VrfState *state = static_cast<Icmpv6VrfState *>(vrf->GetState(
      82             :                              vrf->get_table_partition()->parent(),
      83             :                              vrf_table_listener_id_));
      84         124 :         if (state == NULL) {
      85           0 :             state = CreateAndSetVrfState(vrf);
      86             :         }
      87         124 :         if (state->default_routes_added()) {
      88          58 :             return;
      89             :         }
      90             : 
      91          66 :         boost::system::error_code ec;
      92          66 :         Ip6Address addr = Ip6Address::from_string(IPV6_ALL_ROUTERS_ADDRESS, ec);
      93             :         static_cast<InetUnicastAgentRouteTable *>
      94          66 :             (vrf->GetInet6UnicastRouteTable())->AddHostRoute(vrf->GetName(),
      95             :                                                              addr, 128,
      96             :                                                              vn->GetName(), false);
      97          66 :         addr = Ip6Address::from_string(IPV6_ALL_NODES_ADDRESS, ec);
      98             :         static_cast<InetUnicastAgentRouteTable *>
      99          66 :             (vrf->GetInet6UnicastRouteTable())->AddHostRoute(vrf->GetName(),
     100             :                                                              addr, 128,
     101             :                                                              vn->GetName(), false);
     102             :         /* We need route for PKT0_LINKLOCAL_ADDRESS so that vrouter can respond
     103             :          * to NDP requests for PKT0_LINKLOCAL_ADDRESS. Even though the nexthop
     104             :          * for this route is pkt0, vrouter never sends pkts pointing to this
     105             :          * route on pkt0.
     106             :          */
     107          66 :         addr = Ip6Address::from_string(PKT0_LINKLOCAL_ADDRESS, ec);
     108             :         static_cast<InetUnicastAgentRouteTable *>
     109          66 :             (vrf->GetInet6UnicastRouteTable())->AddHostRoute(vrf->GetName(),
     110             :                                                              addr, 128,
     111             :                                                              vn->GetName(), false);
     112          66 :         state->set_default_routes_added(true);
     113             :     }
     114             : }
     115             : 
     116         683 : void Icmpv6Proto::VrfNotify(DBTablePartBase *part, DBEntryBase *entry) {
     117         683 :     VrfEntry *vrf = static_cast<VrfEntry *>(entry);
     118             : 
     119         683 :     Icmpv6VrfState *state = static_cast<Icmpv6VrfState *>(vrf->GetState(
     120             :                              vrf->get_table_partition()->parent(),
     121             :                              vrf_table_listener_id_));
     122         683 :     if (entry->IsDeleted()) {
     123         541 :         if (state) {
     124         251 :             boost::system::error_code ec;
     125             :             Ip6Address addr =
     126         251 :                 Ip6Address::from_string(IPV6_ALL_ROUTERS_ADDRESS, ec);
     127             :             // enqueue delete request on fabric VRF
     128         502 :             agent_->fabric_inet4_unicast_table()->DeleteReq(
     129         251 :                     agent_->local_peer(), vrf->GetName(), addr, 128, NULL);
     130         251 :             addr = Ip6Address::from_string(IPV6_ALL_NODES_ADDRESS, ec);
     131         502 :             agent_->fabric_inet4_unicast_table()->DeleteReq(
     132         251 :                     agent_->local_peer(), vrf->GetName(), addr, 128, NULL);
     133         251 :             addr = Ip6Address::from_string(PKT0_LINKLOCAL_ADDRESS, ec);
     134         502 :             agent_->fabric_inet4_unicast_table()->DeleteReq(
     135         251 :                     agent_->local_peer(), vrf->GetName(), addr, 128, NULL);
     136         251 :             state->set_default_routes_added(false);
     137         251 :             state->Delete();
     138             :         }
     139         541 :         return;
     140             :     }
     141         142 :     if (!state) {
     142          74 :         CreateAndSetVrfState(vrf);
     143             :     }
     144             : }
     145             : 
     146        1421 : void Icmpv6Proto::InterfaceNotify(DBEntryBase *entry) {
     147        1421 :     Interface *intrface = static_cast<Interface *>(entry);
     148        1421 :     if (intrface->type() != Interface::VM_INTERFACE)
     149          21 :         return;
     150             : 
     151        1400 :     Icmpv6Stats stats;
     152        1400 :     VmInterface *vm_interface = static_cast<VmInterface *>(entry);
     153        1400 :     VmInterfaceMap::iterator it = vm_interfaces_.find(vm_interface);
     154        1400 :     if (intrface->IsDeleted()) {
     155         169 :         if (it != vm_interfaces_.end()) {
     156         169 :             vm_interfaces_.erase(it);
     157             :         }
     158         169 :         if (vm_interface->vmi_type() == VmInterface::VHOST) {
     159           0 :             set_ip_fabric_interface(NULL);
     160           0 :             set_ip_fabric_interface_index(-1);
     161             :         }
     162             :     } else {
     163        1231 :         if (it == vm_interfaces_.end()) {
     164         169 :             vm_interfaces_.insert(VmInterfacePair(vm_interface, stats));
     165             :         }
     166        1231 :         if (vm_interface->vmi_type() == VmInterface::VHOST) {
     167           2 :             set_ip_fabric_interface(intrface);
     168           2 :             set_ip_fabric_interface_index(intrface->id());
     169           2 :             set_ip_fabric_interface_mac(intrface->mac());
     170             :         }
     171             :     }
     172             : }
     173             : 
     174           0 : void Icmpv6Proto::SendIcmpv6Ipc(Icmpv6Proto::Icmpv6MsgType type, Ip6Address ip,
     175             :                                 const VrfEntry *vrf, InterfaceConstRef itf) {
     176           0 :     Icmpv6Ipc *ipc = new Icmpv6Ipc(type, ip, vrf, itf);
     177           0 :     agent_->pkt()->pkt_handler()->SendMessage(PktHandler::ICMPV6, ipc);
     178           0 : }
     179             : 
     180           0 : void Icmpv6Proto::SendIcmpv6Ipc(Icmpv6Proto::Icmpv6MsgType type, NdpKey &key,
     181             :                                 InterfaceConstRef itf) {
     182           0 :     Icmpv6Ipc *ipc = new Icmpv6Ipc(type, key, itf);
     183           0 :     agent_->pkt()->pkt_handler()->SendMessage(PktHandler::ICMPV6, ipc);
     184           0 : }
     185             : 
     186        3457 : void Icmpv6Proto::NexthopNotify(DBEntryBase *entry) {
     187        3457 :     NextHop *nh = static_cast<NextHop *>(entry);
     188             : 
     189        3457 :     switch(nh->GetType()) {
     190           0 :     case NextHop::NDP: {
     191           0 :         NdpNH *ndp_nh = (static_cast<NdpNH *>(nh));
     192           0 :         if (ndp_nh->IsDeleted()) {
     193           0 :             SendIcmpv6Ipc(Icmpv6Proto::NDP_DELETE, ndp_nh->GetIp()->to_v6(),
     194             :                           ndp_nh->GetVrf(), ndp_nh->GetInterface());
     195           0 :         } else if (ndp_nh->IsValid() == false && ndp_nh->GetInterface()) {
     196           0 :             SendIcmpv6Ipc(Icmpv6Proto::NDP_RESOLVE, ndp_nh->GetIp()->to_v6(),
     197             :                           ndp_nh->GetVrf(), ndp_nh->GetInterface());
     198             :         }
     199           0 :         break;
     200             :     }
     201             : 
     202        3457 :     default:
     203        3457 :         break;
     204             :     }
     205        3457 : }
     206             : 
     207         148 : bool Icmpv6Proto::ValidateAndClearVrfState(VrfEntry *vrf,
     208             :                                            Icmpv6VrfState *vrf_state) {
     209         148 :     if (!vrf->IsDeleted()) {
     210           0 :         return false;
     211             :     }
     212             : 
     213         148 :     if (vrf_state->l3_walk_completed() == false) {
     214          18 :         return false;
     215             :     }
     216             : 
     217         130 :     if (vrf_state->evpn_walk_completed() == false) {
     218          56 :         return false;
     219             :     }
     220             : 
     221         222 :     if (vrf_state->managed_delete_walk_ref().get() != NULL ||
     222         148 :         vrf_state->evpn_walk_ref().get() != NULL) {
     223           0 :         return false;
     224             :     }
     225             : 
     226             :     DBState *state = static_cast<DBState *>
     227          74 :         (vrf->GetState(vrf->get_table_partition()->parent(),
     228             :                        vrf_table_listener_id_));
     229          74 :     if (state) {
     230          74 :         vrf->ClearState(vrf->get_table_partition()->parent(),
     231             :                         vrf_table_listener_id_);
     232             :     }
     233          74 :     return true;
     234             : }
     235             : 
     236         936 : void Icmpv6VrfState::RouteUpdate(DBTablePartBase *part, DBEntryBase *entry) {
     237         936 :     InetUnicastRouteEntry *route = static_cast<InetUnicastRouteEntry *>(entry);
     238             : 
     239             :     Icmpv6RouteState *state = static_cast<Icmpv6RouteState *>
     240         936 :         (entry->GetState(part->parent(), route_table_listener_id_));
     241             : 
     242             : #if 0
     243             :     // This is the code for sending unsolicited NA for vhost0 but it should
     244             :     // be taken care of by linux itself
     245             :     const InterfaceNH *intf_nh = dynamic_cast<const InterfaceNH *>(
     246             :             route->GetActiveNextHop());
     247             :     const Interface *intf = (intf_nh) ?
     248             :         static_cast<const Interface *>(intf_nh->GetInterface()) : NULL;
     249             : 
     250             :     NdpKey key(route->prefix_address().to_v6(), route->vrf());
     251             :     NdpEntry *ndpentry = icmp_proto_->UnsolNaEntry(key, intf);
     252             :     if (route->vrf()->GetName() == agent_->fabric_vrf_name()) {
     253             :         ndpentry = icmp_proto_->UnsolNaEntry(key, icmp_proto_->ip_fabric_interface());
     254             :     }
     255             : #endif
     256         936 :     if (entry->IsDeleted() || deleted_) {
     257         365 :         if (state) {
     258             :             //icmp_proto_->DeleteUnsolNaEntry(ndpentry);
     259         365 :             entry->ClearState(part->parent(), route_table_listener_id_);
     260         365 :             delete state;
     261             :         }
     262         365 :         return;
     263             :     }
     264             : 
     265         571 :     if (!state) {
     266         365 :         state = new Icmpv6RouteState(this, route->vrf_id(), route->prefix_address(),
     267         365 :                                      route->prefix_length());
     268         365 :         entry->SetState(part->parent(), route_table_listener_id_, state);
     269             :     }
     270             : 
     271             : #if 0
     272             :     // May not be needed since kernel can take care of sending unsolicited NA
     273             :     if (route->vrf()->GetName() == agent_->fabric_vrf_name() &&
     274             :         route->GetActiveNextHop()->GetType() == NextHop::RECEIVE &&
     275             :         icmp_proto_->agent()->router_id6() == route->prefix_address().to_v6()) {
     276             :         //Send unsolicited NA
     277             :         icmp_proto_->AddUnsolNaEntry(key);
     278             :         icmp_proto_->SendIcmpv6Ipc(Icmpv6Proto::NDP_SEND_UNSOL_NA,
     279             :                               route->prefix_address().to_v6(), route->vrf(),
     280             :                               icmp_proto_->ip_fabric_interface());
     281             :     }
     282             : #endif
     283             : 
     284             :     //Check if there is a local VM path, if yes send a
     285             :     //Neighbor Solicit request, to trigger route preference state machine
     286        1142 :     if (state && route->GetTableType() == Agent::INET6_UNICAST &&
     287         571 :         route->vrf()->GetName() != agent_->fabric_vrf_name()) {
     288         402 :         state->SendNeighborSolicitForAllIntf(route);
     289             :     }
     290             : }
     291             : 
     292        1847 : void Icmpv6VrfState::EvpnRouteUpdate(DBTablePartBase *part, DBEntryBase *entry) {
     293        1847 :     EvpnRouteEntry *route = static_cast<EvpnRouteEntry *>(entry);
     294             : 
     295             :     Icmpv6RouteState *state = static_cast<Icmpv6RouteState *>
     296        1847 :         (entry->GetState(part->parent(), evpn_route_table_listener_id_));
     297             : 
     298        1847 :     if (entry->IsDeleted() || deleted_) {
     299         338 :         if (state) {
     300         338 :             entry->ClearState(part->parent(), evpn_route_table_listener_id_);
     301         338 :             delete state;
     302             :         }
     303         338 :         return;
     304             :     }
     305             : 
     306        1509 :     if (!state) {
     307         338 :         state = new Icmpv6RouteState(this, route->vrf_id(), route->prefix_address(),
     308         338 :                                      route->prefix_length());
     309         338 :         entry->SetState(part->parent(), evpn_route_table_listener_id_, state);
     310             :     }
     311             : 
     312             :     //Check if there is a local VM path, if yes send a
     313             :     //Neighbor Solicit request, to trigger route preference state machine
     314        1509 :     if (state && route->vrf()->GetName() != agent_->fabric_vrf_name()) {
     315        1509 :         state->SendNeighborSolicitForAllIntf(route);
     316             :     }
     317             : }
     318             : 
     319           0 : bool Icmpv6VrfState::DeleteRouteState(DBTablePartBase *part, DBEntryBase *ent) {
     320           0 :     RouteUpdate(part, ent);
     321           0 :     return true;
     322             : }
     323             : 
     324           0 : bool Icmpv6VrfState::DeleteEvpnRouteState(DBTablePartBase *part,
     325             :                                           DBEntryBase *ent) {
     326           0 :     EvpnRouteUpdate(part, ent);
     327           0 :     return true;
     328             : }
     329             : 
     330         251 : void Icmpv6VrfState::Delete() {
     331         251 :     if (managed_delete_walk_ref_.get() == NULL)
     332          58 :         return;
     333             : 
     334         193 :     rt_table_->WalkAgain(managed_delete_walk_ref_);
     335         193 :     if (evpn_walk_ref_.get())
     336         170 :         evpn_rt_table_->WalkAgain(evpn_walk_ref_);
     337         193 :     deleted_ = true;
     338             : }
     339             : 
     340         148 : bool Icmpv6VrfState::PreWalkDone(DBTableBase *partition) {
     341         148 :     if (icmp_proto_->ValidateAndClearVrfState(vrf_, this) == false) {
     342          74 :         return false;
     343             :     }
     344             : 
     345          74 :     rt_table_->Unregister(route_table_listener_id_);
     346          74 :     table_delete_ref_.Reset(NULL);
     347             : 
     348          74 :     evpn_rt_table_->Unregister(evpn_route_table_listener_id_);
     349          74 :     evpn_table_delete_ref_.Reset(NULL);
     350          74 :     return true;
     351             : }
     352             : 
     353         148 : void Icmpv6VrfState::WalkDone(DBTableBase *partition, Icmpv6VrfState *state) {
     354         148 :     if (partition == state->rt_table_) {
     355          74 :         state->rt_table_->ReleaseWalker(state->managed_delete_walk_ref_);
     356          74 :         state->managed_delete_walk_ref_ = NULL;
     357          74 :         state->l3_walk_completed_ = true;
     358             :     } else {
     359          74 :         state->evpn_rt_table_->ReleaseWalker(state->evpn_walk_ref_);
     360          74 :         state->evpn_walk_ref_ = NULL;
     361          74 :         state->evpn_walk_completed_ = true;
     362             :     }
     363             : 
     364         148 :     if (state->PreWalkDone(partition)) {
     365          74 :         delete state;
     366             :     }
     367         148 : }
     368             : 
     369         363 : Icmpv6PathPreferenceState* Icmpv6VrfState::Locate(const IpAddress &ip) {
     370         363 :     Icmpv6PathPreferenceState* ptr = icmpv6_path_preference_map_[ip];
     371         363 :     if (ptr == NULL) {
     372         363 :         ptr = new Icmpv6PathPreferenceState(this, vrf_->vrf_id(), ip, 128);
     373         363 :         icmpv6_path_preference_map_[ip] = ptr;
     374             :     }
     375         363 :     return ptr;
     376             : }
     377             : 
     378           0 : void Icmpv6PathPreferenceState::HandleNA(uint32_t itf) {
     379           0 :     WaitForTrafficIntfMap::iterator it = l3_wait_for_traffic_map_.find(itf);
     380           0 :     if (it == l3_wait_for_traffic_map_.end()) {
     381           0 :         return;
     382             :     }
     383           0 :     InterfaceIcmpv6PathPreferenceInfo &data = it->second;
     384             : 
     385             :     // resetting ns_try_count as interface sent NA
     386           0 :     data.ns_try_count = 0;
     387             : 
     388             : }
     389             : 
     390           0 : void Icmpv6Proto::HandlePathPreferenceNA(const VrfEntry *vrf, uint32_t itf,
     391             :                                             IpAddress sip) {
     392           0 :     if (!vrf) {
     393           0 :         return;
     394             :     }
     395           0 :     InetUnicastRouteEntry *rt = vrf->GetUcRoute(sip);
     396           0 :     if (!rt) {
     397           0 :         return;
     398             :     }
     399             : 
     400             :     Icmpv6VrfState *state = static_cast<Icmpv6VrfState *>
     401           0 :         (vrf->GetState(vrf->get_table_partition()->parent(),
     402             :                        vrf_table_listener_id_));
     403           0 :     if (!state) {
     404           0 :         return;
     405             :     }
     406           0 :     Icmpv6PathPreferenceState *pstate = state->Get(sip);
     407           0 :     if (!pstate) {
     408           0 :         return;
     409             :     }
     410           0 :     pstate->HandleNA(itf);
     411             : }
     412             : 
     413         363 : void Icmpv6VrfState::Erase(const IpAddress &ip) {
     414         363 :     icmpv6_path_preference_map_.erase(ip);
     415         363 : }
     416             : 
     417          74 : Icmpv6VrfState::Icmpv6VrfState(Agent *agent_ptr, Icmpv6Proto *proto,
     418             :                                VrfEntry *vrf_entry, AgentRouteTable *table,
     419          74 :                                AgentRouteTable *evpn_rt_table):
     420          74 :     agent_(agent_ptr), icmp_proto_(proto), vrf_(vrf_entry), rt_table_(table),
     421          74 :     evpn_rt_table_(evpn_rt_table),
     422          74 :     route_table_listener_id_(DBTableBase::kInvalidId),
     423          74 :     evpn_route_table_listener_id_(DBTableBase::kInvalidId),
     424          74 :     table_delete_ref_(this, table->deleter()),
     425          74 :     evpn_table_delete_ref_(this, evpn_rt_table_->deleter()),
     426          74 :     deleted_(false),
     427         148 :     default_routes_added_(false), l3_walk_completed_(false),
     428         148 :     evpn_walk_completed_(false) {
     429         148 :     evpn_walk_ref_ = evpn_rt_table_->AllocWalker(
     430             :             boost::bind(&Icmpv6VrfState::DeleteEvpnRouteState, this, _1, _2),
     431          74 :             boost::bind(&Icmpv6VrfState::WalkDone, _2, this));
     432         148 :     managed_delete_walk_ref_ = table->AllocWalker(
     433             :             boost::bind(&Icmpv6VrfState::DeleteRouteState, this, _1, _2),
     434          74 :             boost::bind(&Icmpv6VrfState::WalkDone, _2, this));
     435          74 : }
     436             : 
     437         148 : Icmpv6VrfState::~Icmpv6VrfState() {
     438          74 :     assert(icmpv6_path_preference_map_.size() == 0);
     439         148 : }
     440             : 
     441         363 : void intrusive_ptr_add_ref(Icmpv6PathPreferenceState *ps) {
     442         363 :     ps->refcount_++;
     443         363 : }
     444             : 
     445         363 : void intrusive_ptr_release(Icmpv6PathPreferenceState *ps) {
     446         363 :     Icmpv6VrfState *state = ps->vrf_state();
     447         363 :     int prev = ps->refcount_.fetch_sub(1);
     448         363 :     if (prev == 1) {
     449         363 :         state->Erase(ps->ip());
     450         363 :         delete ps;
     451             :     }
     452         363 : }
     453             : 
     454         363 : Icmpv6PathPreferenceState::Icmpv6PathPreferenceState(
     455             :         Icmpv6VrfState *vrf_state, uint32_t vrf_id,
     456         363 :         IpAddress ip, uint8_t plen) :
     457         363 :     vrf_state_(vrf_state), ns_req_timer_(NULL), vrf_id_(vrf_id), vm_ip_(ip),
     458         363 :     plen_(plen), svc_ip_(Ip6Address()) {
     459         363 :     refcount_ = 0;
     460         363 : }
     461             : 
     462         363 : Icmpv6PathPreferenceState::~Icmpv6PathPreferenceState() {
     463         363 :     if (ns_req_timer_) {
     464           0 :         ns_req_timer_->Cancel();
     465           0 :         TimerManager::DeleteTimer(ns_req_timer_);
     466             :     }
     467         363 :     assert(refcount_ == 0);
     468         363 : }
     469             : 
     470           0 : bool Icmpv6PathPreferenceState::SendNeighborSolicit(WaitForTrafficIntfMap
     471             :                                                     &wait_for_traffic_map,
     472             :                                                     NDTransmittedIntfMap
     473             :                                                     &nd_transmitted_map) {
     474           0 :     bool ret = false;
     475           0 :     boost::shared_ptr<PktInfo> pkt(new PktInfo(vrf_state_->agent(),
     476             :                                                ICMP_PKT_SIZE,
     477           0 :                                                PktHandler::ICMPV6, 0));
     478           0 :     Icmpv6Handler handler(vrf_state_->agent(), pkt,
     479           0 :                          *(vrf_state_->agent()->event_manager()->io_service()));
     480             : 
     481           0 :     WaitForTrafficIntfMap::iterator it = wait_for_traffic_map.begin();
     482           0 :     for (;it != wait_for_traffic_map.end(); it++) {
     483             : 
     484             :         VmInterface *vm_intf = static_cast<VmInterface *>(
     485           0 :              vrf_state_->agent()->interface_table()->FindInterface(it->first));
     486           0 :         if (!vm_intf) {
     487           0 :             continue;
     488             :         }
     489           0 :         InterfaceIcmpv6PathPreferenceInfo &data = it->second;
     490           0 :         bool inserted = nd_transmitted_map.insert(it->first).second;
     491           0 :         ++data.ns_retry_count;
     492           0 :         if (inserted == false) {
     493           0 :             continue;
     494             :         }
     495             : 
     496           0 :         MacAddress mil_mac = vrf_state_->agent()->mac_learning_proto()->
     497             :                         GetMacIpLearningTable()->GetPairedMacAddress(
     498           0 :                                 vm_intf->vrf_id(), ip());
     499           0 :         if (mil_mac != MacAddress()) {
     500           0 :             ++data.ns_try_count;
     501           0 :             if (data.ns_try_count == kNSTryCount) {
     502           0 :                 IpAddress ip = vm_ip_;
     503           0 :                 MacAddress mac = mil_mac;
     504           0 :                 vrf_state_->agent()->mac_learning_proto()->
     505           0 :                         GetMacIpLearningTable()->MacIpEntryUnreachable(
     506             :                                 vm_intf->vrf_id(), ip, mac);
     507           0 :                 return true;
     508             :             }
     509             :         }
     510             : 
     511           0 :         Ip6Address src_addr;
     512           0 :         if (svc_ip_.is_unspecified() == false && svc_ip_.is_v6())
     513           0 :             src_addr = svc_ip_.to_v6();
     514           0 :         handler.SendNeighborSolicit(src_addr, vm_ip_.to_v6(), vm_intf, vrf_id_);
     515             : 
     516           0 :         vrf_state_->icmp_proto()->IncrementStatsNeighborSolicit(vm_intf);
     517           0 :         ++data.ns_send_count;
     518             : 
     519             :         // reduce the frequency of NS requests after some tries
     520           0 :         if (data.ns_send_count >= kMaxRetry) {
     521             :             // change frequency only if not in gateway mode with remote VMIs and
     522             :             // learnt mac is not present
     523           0 :             if (vm_intf->vmi_type() != VmInterface::REMOTE_VM
     524           0 :                  && mil_mac == MacAddress()) {
     525           0 :                 ns_req_timer_->Reschedule(kTimeout * kTimeoutMultiplier);
     526             :             }
     527             :         }
     528             : 
     529           0 :         ret = true;
     530             :     }
     531           0 :     return ret;
     532           0 : }
     533             : 
     534           0 : bool Icmpv6PathPreferenceState::SendNeighborSolicit() {
     535           0 :     if (l3_wait_for_traffic_map_.size() == 0 &&
     536           0 :             evpn_wait_for_traffic_map_.size() == 0) {
     537           0 :         return false;
     538             :     }
     539             : 
     540           0 :     bool ret = false;
     541           0 :     NDTransmittedIntfMap nd_transmitted_map;
     542           0 :     if (SendNeighborSolicit(l3_wait_for_traffic_map_, nd_transmitted_map)) {
     543           0 :         ret = true;
     544             :     }
     545             : 
     546           0 :     if (SendNeighborSolicit(evpn_wait_for_traffic_map_, nd_transmitted_map)) {
     547           0 :         ret = true;
     548             :     }
     549           0 :     return ret;
     550           0 : }
     551             : 
     552           0 : void Icmpv6PathPreferenceState::StartTimer() {
     553           0 :     if (ns_req_timer_ == NULL) {
     554           0 :         ns_req_timer_ = TimerManager::CreateTimer(
     555           0 :                 *(vrf_state_->agent()->event_manager()->io_service()),
     556             :                 "Neighbor Solicit Request timer for VM",
     557             :                 TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
     558             :                 PktHandler::ICMPV6);
     559             :     }
     560           0 :     ns_req_timer_->Start(kTimeout,
     561             :                          boost::bind(&Icmpv6PathPreferenceState::
     562             :                                       SendNeighborSolicit,
     563             :                                      this));
     564           0 : }
     565             : 
     566         703 : Icmpv6RouteState::Icmpv6RouteState(Icmpv6VrfState *vrf_state,
     567             :                                    uint32_t vrf_id, IpAddress ip,
     568         703 :                                    uint8_t plen) {
     569         703 :     if (plen == Address::kMaxV6PrefixLen) {
     570         363 :         icmpv6_path_preference_state_ = vrf_state->Locate(ip);
     571             :     }
     572         703 : }
     573             : 
     574        1406 : Icmpv6RouteState::~Icmpv6RouteState() {
     575         703 :     icmpv6_path_preference_state_.reset(NULL);
     576        1406 : }
     577             : 
     578        1911 : void Icmpv6RouteState::SendNeighborSolicitForAllIntf(const AgentRoute *route) {
     579        1911 :     if (icmpv6_path_preference_state_.get()) {
     580         402 :         icmpv6_path_preference_state_->SendNeighborSolicitForAllIntf(route);
     581             :     }
     582        1911 : }
     583             : 
     584             : //Send Neighbor Solicit request on interface in Active-BackUp mode
     585             : //So that preference of route can be incremented if the VM replies with
     586             : //Neighbor Advertisement
     587         402 : void Icmpv6PathPreferenceState::SendNeighborSolicitForAllIntf
     588             :     (const AgentRoute *route) {
     589             : 
     590         402 :     WaitForTrafficIntfMap wait_for_traffic_map = evpn_wait_for_traffic_map_;
     591         402 :     if (dynamic_cast<const InetUnicastRouteEntry *>(route)) {
     592         402 :         wait_for_traffic_map = l3_wait_for_traffic_map_;
     593             :     }
     594             : 
     595         402 :     WaitForTrafficIntfMap new_wait_for_traffic_map;
     596         804 :     for (Route::PathList::const_iterator it = route->GetPathList().begin();
     597        1608 :             it != route->GetPathList().end(); it++) {
     598         402 :         const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
     599         804 :         if (path->peer() &&
     600         402 :             path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
     601           0 :             const NextHop *nh = path->ComputeNextHop(vrf_state_->agent());
     602           0 :             if (nh->GetType() != NextHop::INTERFACE) {
     603           0 :                 continue;
     604             :             }
     605             : 
     606           0 :             const InterfaceNH *intf_nh =
     607             :                 static_cast<const  InterfaceNH *>(nh);
     608             :             const Interface *intf =
     609           0 :                 static_cast<const Interface *>(intf_nh->GetInterface());
     610           0 :             if (intf->type() != Interface::VM_INTERFACE) {
     611             :                 //Ignore non vm interface nexthop
     612           0 :                 continue;
     613             :             }
     614           0 :             if (dynamic_cast<const InetUnicastRouteEntry *>(route)) {
     615           0 :                 const VmInterface *vm_intf =
     616             :                     static_cast<const VmInterface *>(intf);
     617           0 :                 if (vm_intf->primary_ip6_addr().is_unspecified() == false) {
     618           0 :                     svc_ip_ = vm_intf->GetServiceIp(vm_intf->primary_ip6_addr());
     619             :                 }
     620             :             }
     621             : 
     622           0 :             if (path->path_preference().IsDependentRt() == true) {
     623           0 :                 continue;
     624             :             }
     625             : 
     626           0 :             uint32_t intf_id = intf->id();
     627             :             WaitForTrafficIntfMap::const_iterator wait_for_traffic_it =
     628           0 :                 wait_for_traffic_map.find(intf_id);
     629           0 :             if (wait_for_traffic_it == wait_for_traffic_map.end()) {
     630           0 :                 InterfaceIcmpv6PathPreferenceInfo data;
     631           0 :                 new_wait_for_traffic_map.insert(std::make_pair(intf_id, data));
     632             :             } else {
     633           0 :                 new_wait_for_traffic_map.insert(std::make_pair(intf_id,
     634           0 :                     wait_for_traffic_it->second));
     635             :             }
     636             :         }
     637             :     }
     638             : 
     639             : 
     640         402 :     if (dynamic_cast<const InetUnicastRouteEntry *>(route)) {
     641         402 :         l3_wait_for_traffic_map_ = new_wait_for_traffic_map;
     642             :     } else {
     643           0 :         evpn_wait_for_traffic_map_ = new_wait_for_traffic_map;
     644             :     }
     645         402 :     if (new_wait_for_traffic_map.size() > 0) {
     646           0 :         SendNeighborSolicit();
     647           0 :         StartTimer();
     648             :     }
     649         402 : }
     650             : 
     651           0 : Icmpv6Proto::Icmpv6Stats *Icmpv6Proto::VmiToIcmpv6Stats(VmInterface *i) {
     652           0 :     VmInterfaceMap::iterator it = vm_interfaces_.find(i);
     653           0 :     if (it == vm_interfaces_.end()) {
     654           0 :         return NULL;
     655             :     }
     656           0 :     return &it->second;
     657             : }
     658             : 
     659           0 : void Icmpv6Proto::IncrementStatsRouterSolicit(VmInterface *vmi) {
     660           0 :     stats_.icmpv6_router_solicit_++;
     661           0 :     Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
     662           0 :     if (stats) {
     663           0 :         stats->icmpv6_router_solicit_++;
     664             :     }
     665           0 : }
     666             : 
     667           0 : void Icmpv6Proto::IncrementStatsRouterAdvert(VmInterface *vmi) {
     668           0 :     stats_.icmpv6_router_advert_++;
     669           0 :     Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
     670           0 :     if (stats) {
     671           0 :         stats->icmpv6_router_advert_++;
     672             :     }
     673           0 : }
     674             : 
     675           0 : void Icmpv6Proto::IncrementStatsPingRequest(VmInterface *vmi) {
     676           0 :     stats_.icmpv6_ping_request_++;
     677           0 :     Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
     678           0 :     if (stats) {
     679           0 :         stats->icmpv6_ping_request_++;
     680             :     }
     681           0 : }
     682             : 
     683           0 : void Icmpv6Proto::IncrementStatsPingResponse(VmInterface *vmi) {
     684           0 :     stats_.icmpv6_ping_response_++;
     685           0 :     Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
     686           0 :     if (stats) {
     687           0 :         stats->icmpv6_ping_response_++;
     688             :     }
     689           0 : }
     690             : 
     691           0 : void Icmpv6Proto::IncrementStatsNeighborSolicit(VmInterface *vmi) {
     692           0 :     stats_.icmpv6_neighbor_solicit_++;
     693           0 :     Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
     694           0 :     if (stats) {
     695           0 :         stats->icmpv6_neighbor_solicit_++;
     696             :     }
     697           0 : }
     698             : 
     699           0 : void Icmpv6Proto::IncrementStatsNeighborSolicited(VmInterface *vmi) {
     700           0 :     stats_.icmpv6_neighbor_solicited_++;
     701           0 :     Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
     702           0 :     if (stats) {
     703           0 :         stats->icmpv6_neighbor_solicited_++;
     704             :     }
     705           0 : }
     706             : 
     707           0 : void Icmpv6Proto::IncrementStatsNeighborAdvertSolicited(VmInterface *vmi) {
     708           0 :     stats_.icmpv6_neighbor_advert_solicited_++;
     709           0 :     Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
     710           0 :     if (stats) {
     711           0 :         stats->icmpv6_neighbor_advert_solicited_++;
     712             :     }
     713           0 : }
     714             : 
     715           0 : void Icmpv6Proto::IncrementStatsNeighborAdvertUnSolicited(VmInterface *vmi) {
     716           0 :     stats_.icmpv6_neighbor_advert_unsolicited_++;
     717           0 :     Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
     718           0 :     if (stats) {
     719           0 :         stats->icmpv6_neighbor_advert_unsolicited_++;
     720             :     }
     721           0 : }
     722             : 
     723           0 : NdpEntry* Icmpv6Proto::FindUnsolNaEntry(NdpKey &key) {
     724           0 :     Icmpv6Proto::UnsolNaIterator iter = unsol_na_cache_.find(key);
     725           0 :     if (iter == unsol_na_cache_.end()) {
     726           0 :         return NULL;
     727             :     }
     728           0 :     return *iter->second.begin();
     729             : }
     730             : 
     731           0 : void Icmpv6Proto::AddUnsolNaEntry(NdpKey &key) {
     732           0 :      NdpEntrySet empty_set;
     733           0 :      unsol_na_cache_.insert(UnsolNaCachePair(key, empty_set));
     734           0 : }
     735             : 
     736           0 : void Icmpv6Proto::DeleteUnsolNaEntry(NdpEntry *entry) {
     737           0 :     if (!entry)
     738           0 :         return ;
     739             : 
     740           0 :     Icmpv6Proto::UnsolNaIterator iter = unsol_na_cache_.find(entry->key());
     741           0 :     if (iter == unsol_na_cache_.end()) {
     742           0 :         return;
     743             :     }
     744             : 
     745           0 :     iter->second.erase(entry);
     746           0 :     delete entry;
     747           0 :     if (iter->second.empty()) {
     748           0 :         unsol_na_cache_.erase(iter);
     749             :     }
     750             : }
     751             : 
     752             : NdpEntry *
     753           0 : Icmpv6Proto::UnsolNaEntry(const NdpKey &key, const Interface *intf) {
     754           0 :     Icmpv6Proto::UnsolNaIterator it = unsol_na_cache_.find(key);
     755           0 :     if (it == unsol_na_cache_.end())
     756           0 :         return NULL;
     757             : 
     758           0 :     for (NdpEntrySet::iterator sit = it->second.begin();
     759           0 :          sit != it->second.end(); sit++) {
     760           0 :         NdpEntry *entry = *sit;
     761           0 :         if (entry->get_interface() == intf)
     762           0 :             return *sit;
     763             :     }
     764             : 
     765           0 :     return NULL;
     766             : }
     767             : 
     768             : Icmpv6Proto::UnsolNaIterator
     769           0 : Icmpv6Proto::UnsolNaEntryIterator(const NdpKey &key, bool *key_valid) {
     770           0 :     Icmpv6Proto::UnsolNaIterator it = unsol_na_cache_.find(key);
     771           0 :     if (it == unsol_na_cache_.end())
     772           0 :         return it;
     773           0 :     const VrfEntry *vrf = key.vrf;
     774           0 :     if (!vrf)
     775           0 :         return it;
     776             :     const Icmpv6VrfState *state = static_cast<const Icmpv6VrfState *>
     777           0 :                          (vrf->GetState(vrf->get_table_partition()->parent(),
     778             :                           vrf_table_listener_id_));
     779             :     // If VRF is delete marked, do not add Ndp entries to cache
     780           0 :     if (state == NULL || state->deleted() == true)
     781           0 :         return it;
     782           0 :     *key_valid = true;
     783           0 :     return it;
     784             : }
     785             : 
     786           0 : bool Icmpv6Proto::AddNdpEntry(NdpEntry *entry) {
     787           0 :     const VrfEntry *vrf = entry->key().vrf;
     788             :     const Icmpv6VrfState *state = static_cast<const Icmpv6VrfState *>
     789           0 :                          (vrf->GetState(vrf->get_table_partition()->parent(),
     790             :                           vrf_table_listener_id_));
     791             :     // If VRF is delete marked, do not add Ndp entries to cache
     792           0 :     if (state == NULL || state->deleted() == true)
     793           0 :         return false;
     794             : 
     795           0 :     bool ret = ndp_cache_.insert(NdpCachePair(entry->key(), entry)).second;
     796           0 :     uint32_t intf_id = entry->get_interface()->id();
     797           0 :     InterfaceNdpMap::iterator it = interface_ndp_map_.find(intf_id);
     798           0 :     if (it == interface_ndp_map_.end()) {
     799           0 :         InterfaceNdpInfo intf_entry;
     800           0 :         intf_entry.ndp_key_list.insert(entry->key());
     801           0 :         interface_ndp_map_.insert(InterfaceNdpPair(intf_id, intf_entry));
     802           0 :     } else {
     803           0 :         InterfaceNdpInfo &intf_entry = it->second;
     804           0 :         NdpKeySet::iterator key_it = intf_entry.ndp_key_list.find(entry->key());
     805           0 :         if (key_it == intf_entry.ndp_key_list.end()) {
     806           0 :             intf_entry.ndp_key_list.insert(entry->key());
     807             :         }
     808             :     }
     809           0 :     return ret;
     810             : }
     811             : 
     812           0 : bool Icmpv6Proto::DeleteNdpEntry(NdpEntry *entry) {
     813           0 :     if (!entry)
     814           0 :         return false;
     815             : 
     816           0 :     Icmpv6Proto::NdpIterator iter = ndp_cache_.find(entry->key());
     817           0 :     if (iter == ndp_cache_.end()) {
     818           0 :         return false;
     819             :     }
     820             : 
     821           0 :     DeleteNdpEntry(iter);
     822           0 :     return true;
     823             : }
     824             : 
     825             : Icmpv6Proto::NdpIterator
     826           0 : Icmpv6Proto::DeleteNdpEntry(Icmpv6Proto::NdpIterator iter) {
     827           0 :     NdpEntry *entry = iter->second;
     828           0 :     ndp_cache_.erase(iter++);
     829           0 :     delete entry;
     830           0 :     return iter;
     831             : }
     832             : 
     833           0 : NdpEntry *Icmpv6Proto::FindNdpEntry(const NdpKey &key) {
     834           0 :     NdpIterator it = ndp_cache_.find(key);
     835           0 :     if (it == ndp_cache_.end())
     836           0 :         return NULL;
     837           0 :     return it->second;
     838             : }

Generated by: LCOV version 1.14