LCOV - code coverage report
Current view: top level - vnsw/agent/services - arp_entry.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 132 231 57.1 %
Date: 2026-11-09 02:10:49 Functions: 12 16 75.0 %
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 "services/arp_proto.h"
       8             : #include "services/services_sandesh.h"
       9             : #include "services/services_init.h"
      10             : #include "oper/route_common.h"
      11             : 
      12         124 : ArpEntry::ArpEntry(boost::asio::io_context &io, ArpHandler *handler,
      13             :                    ArpKey &key, const VrfEntry *vrf, State state,
      14         124 :                    const Interface *itf)
      15         372 :     : io_(io), key_(key), nh_vrf_(vrf), state_(state), retry_count_(0),
      16         124 :       handler_(handler), arp_timer_(NULL), interface_(itf) {
      17         124 :     if (!IsDerived()) {
      18         124 :         arp_timer_ = TimerManager::CreateTimer(io, "Arp Entry timer",
      19             :                 TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
      20             :                 PktHandler::ARP);
      21             :     }
      22         124 : }
      23             : 
      24         248 : ArpEntry::~ArpEntry() {
      25         124 :     if (!IsDerived()) {
      26         124 :         arp_timer_->Cancel();
      27         124 :         TimerManager::DeleteTimer(arp_timer_);
      28             :     }
      29         124 :     handler_.reset(NULL);
      30         248 : }
      31             : 
      32           0 : void ArpEntry::HandleDerivedArpRequest() {
      33           0 :     ArpProto *arp_proto = handler_->agent()->GetArpProto();
      34             :     //Add ArpRoute for Derived entry
      35           0 :     AddArpRoute(IsResolved());
      36             : 
      37           0 :     ArpKey key(key_.ip, nh_vrf_);
      38           0 :     ArpEntry *entry = arp_proto->FindArpEntry(key);
      39           0 :     if (entry) {
      40           0 :         entry->HandleArpRequest();
      41             :     } else {
      42           0 :         entry = new ArpEntry(io_, handler_.get(), key, nh_vrf_, ArpEntry::INITING,
      43           0 :                              interface_.get());
      44           0 :         if (arp_proto->AddArpEntry(entry) == false) {
      45           0 :             delete entry;
      46           0 :             return;
      47             :         }
      48           0 :         entry->HandleArpRequest();
      49             :     }
      50             : }
      51             : 
      52           4 : bool ArpEntry::HandleArpRequest() {
      53           4 :     if (IsDerived()) {
      54           0 :         HandleDerivedArpRequest();
      55           0 :         return true;
      56             :     }
      57           4 :     if (IsResolved())
      58           0 :         AddArpRoute(true);
      59             :     else {
      60           4 :         AddArpRoute(false);
      61           4 :         if (state_ & ArpEntry::INITING) {
      62           2 :             state_ = ArpEntry::RESOLVING;
      63           2 :             SendArpRequest();
      64             :         }
      65             :     }
      66           4 :     return true;
      67             : }
      68             : 
      69           0 : void ArpEntry::HandleArpReply(const MacAddress &mac) {
      70             : 
      71           0 :     if (IsDerived()) {
      72             :         /* We don't expect ARP replies in derived Vrf */
      73           0 :         return;
      74             :     }
      75           0 :     if ((state_ == ArpEntry::RESOLVING) || (state_ == ArpEntry::ACTIVE) ||
      76           0 :         (state_ == ArpEntry::INITING) || (state_ == ArpEntry::RERESOLVING)) {
      77           0 :         ArpProto *arp_proto = handler_->agent()->GetArpProto();
      78           0 :         arp_timer_->Cancel();
      79           0 :         retry_count_ = 0;
      80           0 :         mac_address_ = mac;
      81           0 :         if (state_ == ArpEntry::RESOLVING) {
      82           0 :             arp_proto->IncrementStatsResolved();
      83           0 :             arp_proto->IncrementStatsResolved(interface_->id());
      84             :         }
      85           0 :         state_ = ArpEntry::ACTIVE;
      86           0 :         StartTimer(arp_proto->aging_timeout(), ArpProto::AGING_TIMER_EXPIRED);
      87           0 :         AddArpRoute(true);
      88             :     }
      89             : }
      90             : 
      91           2 : bool ArpEntry::RetryExpiry() {
      92           2 :     if (state_ & ArpEntry::ACTIVE)
      93           0 :         return true;
      94           2 :     ArpProto *arp_proto = handler_->agent()->GetArpProto();
      95           2 :     if (retry_count_ < arp_proto->max_retries()) {
      96           2 :         retry_count_++;
      97           2 :         SendArpRequest();
      98             :     } else {
      99             :         std::vector<Ip4Address> gateway_list =
     100           0 :             handler_->agent()->vhost_default_gateway();
     101           0 :         Ip4Address ip(key_.ip);
     102           0 :         if (std::find(gateway_list.begin(), gateway_list.end(), ip) !=
     103           0 :                 gateway_list.end()) {
     104           0 :             state_ = ArpEntry::RESOLVING;
     105           0 :             ARP_TRACE(Trace, "Retry exceeded, set arp to resolving",
     106             :                     ip.to_string(),  key_.vrf->GetName(), "");
     107             :         }
     108           0 :         ARP_TRACE(Trace, "Retry exceeded", ip.to_string(),
     109             :                   key_.vrf->GetName(), "");
     110           0 :         arp_proto->IncrementStatsMaxRetries();
     111             : 
     112             :         // if Arp NH is not present, let the entry be deleted
     113           0 :         if (DeleteArpRoute())
     114           0 :             return false;
     115             : 
     116             :         // keep retrying till Arp NH is deleted
     117           0 :         retry_count_ = 0;
     118           0 :         SendArpRequest();
     119           0 :     }
     120           2 :     return true;
     121             : }
     122             : 
     123           0 : bool ArpEntry::AgingExpiry() {
     124           0 :     Ip4Address ip(key_.ip);
     125           0 :     const string& vrf_name = key_.vrf->GetName();
     126           0 :     ArpNHKey nh_key(vrf_name, ip, false);
     127           0 :     ArpNH *arp_nh = static_cast<ArpNH *>(handler_->agent()->nexthop_table()->
     128           0 :                                          FindActiveEntry(&nh_key));
     129           0 :     if (!arp_nh) {
     130             :         // do not re-resolve if Arp NH doesnt exist
     131           0 :         return false;
     132             :     }
     133           0 :     state_ = ArpEntry::RERESOLVING;
     134           0 :     SendArpRequest();
     135           0 :     return true;
     136           0 : }
     137             : 
     138         542 : void ArpEntry::SendGratuitousArp() {
     139         542 :     Agent *agent = handler_->agent();
     140         542 :     ArpProto *arp_proto = agent->GetArpProto();
     141         542 :     if (agent->router_id_configured()) {
     142         542 :         if (interface_->type() == Interface::VM_INTERFACE) {
     143             :             const VmInterface *vmi =
     144         542 :                 static_cast<const VmInterface *>(interface_.get());
     145         542 :             MacAddress smac = vmi->GetVifMac(agent);
     146         542 :             if (key_.vrf && key_.vrf->vn()) {
     147         500 :                 IpAddress gw_ip = key_.vrf->vn()->GetGatewayFromIpam
     148         500 :                     (Ip4Address(key_.ip));
     149         500 :                 IpAddress dns_ip = key_.vrf->vn()->GetDnsFromIpam
     150         500 :                     (Ip4Address(key_.ip));
     151         500 :                 if (!gw_ip.is_unspecified() && gw_ip.is_v4())  {
     152        2000 :                     handler_->SendArp(ARPOP_REQUEST, smac,
     153         500 :                                       gw_ip.to_v4().to_ulong(),
     154        1000 :                                       smac, vmi->vm_mac(), gw_ip.to_v4().to_ulong(),
     155         500 :                                       vmi->id(), key_.vrf->vrf_id());
     156             :                 }
     157        1000 :                 if (!dns_ip.is_unspecified() && dns_ip.is_v4() &&
     158         500 :                     dns_ip != gw_ip)  {
     159           0 :                     handler_->SendArp(ARPOP_REQUEST, smac,
     160           0 :                                       dns_ip.to_v4().to_ulong(),
     161           0 :                                       smac, vmi->vm_mac(), dns_ip.to_v4().to_ulong(),
     162           0 :                                       vmi->id(), key_.vrf->vrf_id());
     163             :                 }
     164             :             }
     165             :         } else {
     166           0 :             handler_->SendArp(ARPOP_REQUEST, arp_proto->ip_fabric_interface_mac(),
     167           0 :                               agent->router_id().to_ulong(), MacAddress(),
     168           0 :                               MacAddress::BroadcastMac(), agent->router_id().to_ulong(),
     169             :                               arp_proto->ip_fabric_interface_index(),
     170           0 :                               key_.vrf->vrf_id());
     171             :         }
     172             : 
     173             :     }
     174             : 
     175         542 :     retry_count_++;
     176         542 :     StartTimer(ArpProto::kGratRetryTimeout, ArpProto::GRATUITOUS_TIMER_EXPIRED);
     177         542 : }
     178             : 
     179           4 : bool ArpEntry::IsResolved() {
     180           4 :     return (state_ & (ArpEntry::ACTIVE | ArpEntry::RERESOLVING));
     181             : }
     182             : 
     183         258 : bool ArpEntry::IsDerived() {
     184         258 :     if (key_.vrf != nh_vrf_) {
     185           0 :         return true;
     186             :     }
     187         258 :     return false;
     188             : }
     189             : 
     190         546 : void ArpEntry::StartTimer(uint32_t timeout, uint32_t mtype) {
     191         546 :     arp_timer_->Cancel();
     192        1092 :     arp_timer_->Start(timeout, boost::bind(&ArpProto::TimerExpiry,
     193         546 :                                            handler_->agent()->GetArpProto(),
     194         546 :                                            key_, mtype, interface_.get()));
     195         546 : }
     196             : 
     197           4 : void ArpEntry::SendArpRequest() {
     198           4 :     assert(!IsDerived());
     199           4 :     Agent *agent = handler_->agent();
     200           4 :     ArpProto *arp_proto = agent->GetArpProto();
     201           4 :     uint32_t vrf_id = VrfEntry::kInvalidIndex;
     202           4 :     uint32_t intf_id = arp_proto->ip_fabric_interface_index();
     203           4 :     Ip4Address ip;
     204           4 :     MacAddress smac;
     205           4 :     if (interface_->type() == Interface::VM_INTERFACE) {
     206             :         const VmInterface *vmi =
     207           4 :             static_cast<const VmInterface *>(interface_.get());
     208           4 :         ip = vmi->GetServiceIp(Ip4Address(key_.ip)).to_v4();
     209           4 :         if (vmi->vmi_type() == VmInterface::VHOST) {
     210           4 :             ip = agent->router_id();
     211             :         }
     212           4 :         vrf_id = nh_vrf_->vrf_id();
     213           4 :         if (vmi->parent()) {
     214           4 :             intf_id = vmi->parent()->id();
     215             :         }
     216           4 :         smac = vmi->GetVifMac(agent);
     217             :     } else {
     218           0 :         if (agent->is_l3mh() == true) {
     219           0 :             intf_id = interface_->id();
     220           0 :             ip = agent->ip_fabric_intf_addr_list()[intf_id];
     221             :         } else {
     222           0 :             ip = agent->router_id();
     223             :         }
     224             :         VrfEntry *vrf =
     225           0 :             agent->vrf_table()->FindVrfFromName(agent->fabric_vrf_name());
     226           0 :         if (vrf) {
     227           0 :             vrf_id = vrf->vrf_id();
     228             :         }
     229           0 :         smac = interface_->mac();
     230             :     }
     231             : 
     232           4 :     if (vrf_id != VrfEntry::kInvalidIndex) {
     233           8 :         handler_->SendArp(ARPOP_REQUEST, smac, ip.to_ulong(),
     234           8 :                           MacAddress(), MacAddress::BroadcastMac(), key_.ip, intf_id, vrf_id);
     235             :     }
     236             : 
     237           4 :     StartTimer(arp_proto->retry_timeout(), ArpProto::RETRY_TIMER_EXPIRED);
     238           4 : }
     239             : 
     240           4 : void ArpEntry::AddArpRoute(bool resolved) {
     241           4 :     if (key_.vrf->GetName() == handler_->agent()->linklocal_vrf_name()) {
     242             :         // Do not squash existing route entry.
     243             :         // should be smarter and not replace an existing route.
     244           4 :         return;
     245             :     }
     246             : 
     247           4 :     Ip4Address ip(key_.ip);
     248           4 :     const string& vrf_name = key_.vrf->GetName();
     249           4 :     ArpNHKey nh_key(nh_vrf_->GetName(), ip, false);
     250           8 :     ArpNH *arp_nh = static_cast<ArpNH *>(handler_->agent()->nexthop_table()->
     251           4 :                                          FindActiveEntry(&nh_key));
     252             : 
     253           4 :     MacAddress mac = mac_address();
     254           4 :     if (arp_nh && arp_nh->GetResolveState() &&
     255           0 :         mac.CompareTo(arp_nh->GetMac()) == 0) {
     256             :         // MAC address unchanged, ignore
     257           0 :         if (!IsDerived()) {
     258           0 :             return;
     259             :         } else {
     260             :             /* Return if the route is already existing */
     261             :             InetUnicastRouteKey *rt_key = new InetUnicastRouteKey(
     262           0 :                     handler_->agent()->local_peer(), vrf_name, ip, 32);
     263           0 :             AgentRoute *entry = key_.vrf->GetInet4UnicastRouteTable()->
     264           0 :                 FindActiveEntry(rt_key);
     265           0 :             delete rt_key;
     266           0 :             if (entry) {
     267           0 :                 return;
     268             :             }
     269           0 :             resolved = true;
     270             :         }
     271             :     }
     272             : 
     273           4 :     ARP_TRACE(Trace, "Add", ip.to_string(), vrf_name, mac.ToString());
     274           4 :     AgentRoute *entry = key_.vrf->GetInet4UnicastRouteTable()->FindLPM(ip);
     275             : 
     276           4 :     bool policy = false;
     277           4 :     SecurityGroupList sg;
     278           4 :     TagList tag;
     279           4 :     VnListType vn_list;
     280             :     const NextHop *anh;
     281           4 :     if (entry && (anh = entry->GetActiveNextHop()) != NULL) {
     282           4 :         policy = anh->PolicyEnabled();
     283           4 :         sg = entry->GetActivePath()->sg_list();
     284           4 :         tag = entry->GetActivePath()->tag_list();
     285           4 :         vn_list = entry->GetActivePath()->dest_vn_list();
     286             :     }
     287             : 
     288           4 :     const Interface *itf = handler_->agent()->GetArpProto()->ip_fabric_interface();
     289           4 :     if (interface_->type() == Interface::PHYSICAL) {
     290           0 :         itf = interface_.get();
     291             :     }
     292           4 :     if (interface_->type() == Interface::VM_INTERFACE) {
     293             :         const VmInterface *vintf =
     294           4 :             static_cast<const VmInterface *>(interface_.get());
     295           4 :         if (vintf->vmi_type() == VmInterface::VHOST) {
     296           8 :             for (InterfaceList::size_type i = 0; i != vintf->parent_list().size(); i++) {
     297           4 :                 itf = vintf->parent_list()[i];
     298           8 :                 handler_->agent()->fabric_inet4_unicast_table()->ArpRoute(
     299             :                         DBRequest::DB_ENTRY_ADD_CHANGE, vrf_name, ip, mac,
     300           4 :                         nh_vrf_->GetName(), *itf, resolved, 32, policy,
     301             :                         vn_list, sg, tag);
     302             :             }
     303           4 :             return;
     304             :         }
     305             :     }
     306             : 
     307           0 :     handler_->agent()->fabric_inet4_unicast_table()->ArpRoute(
     308             :                        DBRequest::DB_ENTRY_ADD_CHANGE, vrf_name, ip, mac,
     309           0 :                        nh_vrf_->GetName(), *itf, resolved, 32, policy,
     310             :                        vn_list, sg, tag);
     311          16 : }
     312             : 
     313           2 : bool ArpEntry::DeleteArpRoute() {
     314           2 :     if (key_.vrf->GetName() == handler_->agent()->linklocal_vrf_name()) {
     315           0 :         return true;
     316             :     }
     317             : 
     318           2 :     Ip4Address ip(key_.ip);
     319           2 :     const string& vrf_name = key_.vrf->GetName();
     320           2 :     ArpNHKey nh_key(nh_vrf_->GetName(), ip, false);
     321           4 :     ArpNH *arp_nh = static_cast<ArpNH *>(handler_->agent()->nexthop_table()->
     322           2 :                                          FindActiveEntry(&nh_key));
     323           2 :     if (!arp_nh)
     324           0 :         return true;
     325             : 
     326           2 :     MacAddress mac = mac_address();
     327           2 :     ARP_TRACE(Trace, "Delete", ip.to_string(), vrf_name, mac.ToString());
     328           2 :     if (IsDerived()) {
     329             :         //Just enqueue a delete, no need to mark nexthop invalid
     330           0 :         InetUnicastAgentRouteTable::Delete(handler_->agent()->local_peer(),
     331             :                                            vrf_name, ip, 32);
     332           0 :         return true;
     333             :     }
     334             : 
     335           6 :     handler_->agent()->fabric_inet4_unicast_table()->ArpRoute(
     336           2 :                        DBRequest::DB_ENTRY_DELETE, vrf_name, ip, mac, nh_vrf_->GetName(),
     337           2 :                        *interface_, false, 32, false, Agent::NullStringList(),
     338           4 :                        SecurityGroupList(), TagList());
     339           2 :     return false;
     340           2 : }
     341             : 
     342           0 : void ArpEntry::Resync(bool policy, const VnListType &vnlist,
     343             :                       const SecurityGroupList &sg,
     344             :                       const TagList &tag) {
     345           0 :     Ip4Address ip(key_.ip);
     346           0 :     const string& vrf_name = key_.vrf->GetName();
     347           0 :     ARP_TRACE(Trace, "Resync", ip.to_string(), vrf_name,
     348             :               mac_address().ToString());
     349           0 :     handler_->agent()->fabric_inet4_unicast_table()->ArpRoute(
     350           0 :                        DBRequest::DB_ENTRY_ADD_CHANGE, key_.vrf->GetName(), ip,
     351           0 :                        mac_address_, nh_vrf_->GetName(), *interface_, IsResolved(),
     352             :                        32, policy, vnlist, sg, tag);
     353           0 : }

Generated by: LCOV version 1.14