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

Generated by: LCOV version 1.14