LCOV - code coverage report
Current view: top level - vnsw/agent/services - arp_proto.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 78 110 70.9 %
Date: 2026-06-11 01:56:02 Functions: 39 56 69.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef vnsw_agent_arp_proto_hpp
       6             : #define vnsw_agent_arp_proto_hpp
       7             : 
       8             : #include <atomic>
       9             : 
      10             : #include "pkt/proto.h"
      11             : #include "services/arp_handler.h"
      12             : #include "services/arp_entry.h"
      13             : 
      14             : #define ARP_TRACE(obj, ...)                                                 \
      15             : do {                                                                        \
      16             :     Arp##obj::TraceMsg(ArpTraceBuf, __FILE__, __LINE__, ##__VA_ARGS__);     \
      17             : } while (false)                                                             \
      18             : 
      19             : struct ArpVrfState;
      20             : 
      21             : class ArpProto : public Proto {
      22             : public:
      23             :     static const uint16_t kGratRetries = 2;
      24             :     static const uint16_t kMaxFailures = 3;
      25             :     static const uint32_t kGratRetryTimeout = 2000;        // milli seconds
      26             :     static const uint16_t kMaxRetries = 8;
      27             :     static const uint32_t kRetryTimeout = 2000;            // milli seconds
      28             :     static const uint32_t kAgingTimeout = (5 * 60 * 1000); // milli seconds
      29             : 
      30             :     typedef std::map<ArpKey, ArpEntry *> ArpCache;
      31             :     typedef std::pair<ArpKey, ArpEntry *> ArpCachePair;
      32             :     typedef std::map<ArpKey, ArpEntry *>::iterator ArpIterator;
      33             :     typedef std::set<ArpKey> ArpKeySet;
      34             :     typedef std::set<ArpEntry *> ArpEntrySet;
      35             :     typedef std::map<ArpKey, ArpEntrySet> GratuitousArpCache;
      36             :     typedef std::pair<ArpKey, ArpEntrySet> GratuitousArpCachePair;
      37             :     typedef std::map<ArpKey, ArpEntrySet>::iterator GratuitousArpIterator;
      38             : 
      39             :     enum ArpMsgType {
      40             :         ARP_RESOLVE,
      41             :         ARP_DELETE,
      42             :         ARP_SEND_GRATUITOUS,
      43             :         RETRY_TIMER_EXPIRED,
      44             :         AGING_TIMER_EXPIRED,
      45             :         GRATUITOUS_TIMER_EXPIRED,
      46             :     };
      47             : 
      48             :     struct ArpIpc : InterTaskMsg {
      49           0 :         ArpIpc(ArpProto::ArpMsgType msg, ArpKey &akey, InterfaceConstRef itf)
      50           0 :             : InterTaskMsg(msg), key(akey), interface_(itf) {}
      51         149 :         ArpIpc(ArpProto::ArpMsgType msg, in_addr_t ip, const VrfEntry *vrf,
      52         149 :                InterfaceConstRef itf) :
      53         149 :             InterTaskMsg(msg), key(ip, vrf), interface_(itf) {}
      54             : 
      55             :         ArpKey key;
      56             :         InterfaceConstRef interface_;
      57             :     };
      58             : 
      59             :     struct ArpStats {
      60          10 :         ArpStats() { Reset(); }
      61          15 :         void Reset() {
      62          15 :             arp_req = arp_replies = arp_gratuitous =
      63          15 :             resolved = max_retries_exceeded = errors = 0;
      64          15 :             arp_invalid_packets = arp_invalid_interface = arp_invalid_vrf =
      65          15 :             arp_invalid_address = vm_arp_req = vm_garp_req =
      66          15 :             ipfabric_not_inst = 0;
      67          15 :         }
      68             : 
      69             :         uint32_t arp_req;
      70             :         uint32_t arp_replies;
      71             :         uint32_t arp_gratuitous;
      72             :         uint32_t resolved;
      73             :         uint32_t max_retries_exceeded;
      74             :         uint32_t errors;
      75             :         uint32_t arp_invalid_packets;
      76             :         uint32_t arp_invalid_interface;
      77             :         uint32_t arp_invalid_vrf;
      78             :         uint32_t arp_invalid_address;
      79             :         uint32_t vm_arp_req;
      80             :         uint32_t vm_garp_req;
      81             :         uint32_t agent_not_inst;
      82             :         uint32_t ipfabric_not_inst;
      83             :     };
      84             : 
      85             :     struct InterfaceArpInfo {
      86           2 :         InterfaceArpInfo() : arp_key_list(), stats() {}
      87             :         ArpKeySet arp_key_list;
      88             :         ArpStats stats;
      89             :     };
      90             :     typedef std::map<uint32_t, InterfaceArpInfo> InterfaceArpMap;
      91             :     typedef std::pair<uint32_t, InterfaceArpInfo> InterfaceArpPair;
      92             : 
      93             :     void Shutdown();
      94             :     ArpProto(Agent *agent, boost::asio::io_context &io, bool run_with_vrouter);
      95             :     virtual ~ArpProto();
      96             : 
      97             :     ProtoHandler *AllocProtoHandler(boost::shared_ptr<PktInfo> info,
      98             :                                     boost::asio::io_context &io);
      99             :     bool TimerExpiry(ArpKey &key, uint32_t timer_type, const Interface *itf);
     100             : 
     101             :     bool AddArpEntry(ArpEntry *entry);
     102             :     bool DeleteArpEntry(ArpEntry *entry);
     103             :     ArpEntry *FindArpEntry(const ArpKey &key);
     104          23 :     std::size_t GetArpCacheSize() { return arp_cache_.size(); }
     105          40 :     const ArpCache& arp_cache() { return arp_cache_; }
     106           0 :     const GratuitousArpCache& gratuitous_arp_cache() { return gratuitous_arp_cache_; }
     107           0 :     const InterfaceArpMap& interface_arp_map() { return interface_arp_map_; }
     108             : 
     109          69 :     Interface *ip_fabric_interface() const { return ip_fabric_interface_; }
     110           1 :     uint32_t ip_fabric_interface_index() const {
     111           1 :         return ip_fabric_interface_index_;
     112             :     }
     113           0 :     const MacAddress &ip_fabric_interface_mac() const {
     114           0 :         return ip_fabric_interface_mac_;
     115             :     }
     116           2 :     void set_ip_fabric_interface(Interface *itf) { ip_fabric_interface_ = itf; }
     117           2 :     void set_ip_fabric_interface_index(uint32_t ind) {
     118           2 :         ip_fabric_interface_index_ = ind;
     119           2 :     }
     120           1 :     void set_ip_fabric_interface_mac(const MacAddress &mac) {
     121           1 :         ip_fabric_interface_mac_ = mac;
     122           1 :     }
     123             : 
     124             :     void  AddGratuitousArpEntry(ArpKey &key);
     125             :     void DeleteGratuitousArpEntry(ArpEntry *entry);
     126             :     ArpEntry* GratuitousArpEntry (const ArpKey &key, const Interface *intf);
     127             :     ArpProto::GratuitousArpIterator
     128             :         GratuitousArpEntryIterator(const ArpKey &key, bool *key_valid);
     129           2 :     void IncrementStatsArpReq() { arp_stats_.arp_req++; }
     130           0 :     void IncrementStatsArpReplies() { arp_stats_.arp_replies++; }
     131           0 :     void IncrementStatsGratuitous() { arp_stats_.arp_gratuitous++; }
     132           0 :     void IncrementStatsResolved() { arp_stats_.resolved++; }
     133           0 :     void IncrementStatsMaxRetries() { arp_stats_.max_retries_exceeded++; }
     134           0 :     void IncrementStatsErrors() { arp_stats_.errors++; }
     135           0 :     void IncrementStatsVmGarpReq() { arp_stats_.vm_garp_req++; }
     136          98 :     void IncrementStatsVmArpReq() { arp_stats_.vm_arp_req++; }
     137           0 :     void IncrementStatsInvalidPackets() {
     138           0 :         IncrementStatsErrors();
     139           0 :         arp_stats_.arp_invalid_packets++;
     140           0 :     }
     141           0 :     void IncrementStatsInvalidInterface() {
     142           0 :         IncrementStatsErrors();
     143           0 :         arp_stats_.arp_invalid_interface++;
     144           0 :     }
     145           0 :     void IncrementStatsInvalidVrf() {
     146           0 :         IncrementStatsErrors();
     147           0 :         arp_stats_.arp_invalid_vrf++;
     148           0 :     }
     149           0 :     void IncrementStatsInvalidAddress() {
     150           0 :         IncrementStatsErrors();
     151           0 :         arp_stats_.arp_invalid_address++;
     152           0 :     }
     153             : 
     154           0 :     void IncrementStatsIPFabricNotInst() { arp_stats_.ipfabric_not_inst++; }
     155             : 
     156          10 :     const ArpStats &GetStats() const { return arp_stats_; }
     157           3 :     void ClearStats() { arp_stats_.Reset(); }
     158             : 
     159             :     void IncrementStatsArpRequest(uint32_t idx);
     160             :     void IncrementStatsArpReply(uint32_t idx);
     161             :     void IncrementStatsResolved(uint32_t idx);
     162             :     InterfaceArpInfo& ArpMapIndexToEntry(uint32_t idx);
     163             :     uint32_t ArpRequestStatsCounter(uint32_t idx);
     164             :     uint32_t ArpReplyStatsCounter(uint32_t idx);
     165             :     uint32_t ArpResolvedStatsCounter(uint32_t idx);
     166             :     void ClearInterfaceArpStats(uint32_t idx);
     167             : 
     168           0 :     uint16_t max_retries() const { return max_retries_; }
     169           1 :     uint32_t retry_timeout() const { return retry_timeout_; }
     170           0 :     uint32_t aging_timeout() const { return aging_timeout_; }
     171           1 :     void set_max_retries(uint16_t retries) { max_retries_ = retries; }
     172           1 :     void set_retry_timeout(uint32_t timeout) { retry_timeout_ = timeout; }
     173           1 :     void set_aging_timeout(uint32_t timeout) { aging_timeout_ = timeout; }
     174             :     void SendArpIpc(ArpProto::ArpMsgType type, in_addr_t ip,
     175             :                     const VrfEntry *vrf, InterfaceConstRef itf);
     176             :     bool ValidateAndClearVrfState(VrfEntry *vrf, const ArpVrfState *vrf_state);
     177             :     ArpIterator FindUpperBoundArpEntry(const ArpKey &key);
     178             :     ArpIterator FindLowerBoundArpEntry(const ArpKey &key);
     179             :     void HandlePathPreferenceArpReply(const VrfEntry *vrf, uint32_t itf,
     180             :                                       Ip4Address sip);
     181             : 
     182          21 :     DBTableBase::ListenerId vrf_table_listener_id() const {
     183          21 :         return vrf_table_listener_id_;
     184             :     }
     185           2 :     DBTableBase::ListenerId interface_table_listener_id() const {
     186           2 :         return interface_table_listener_id_;
     187             :     }
     188             : private:
     189             :     void VrfNotify(DBTablePartBase *part, DBEntryBase *entry);
     190             :     void NextHopNotify(DBEntryBase *entry);
     191             :     void InterfaceNotify(DBEntryBase *entry);
     192             :     void SendArpIpc(ArpProto::ArpMsgType type, ArpKey &key,
     193             :                     InterfaceConstRef itf);
     194             :     ArpProto::ArpIterator DeleteArpEntry(ArpProto::ArpIterator iter);
     195             : 
     196             :     ArpCache arp_cache_;
     197             :     ArpStats arp_stats_;
     198             :     GratuitousArpCache gratuitous_arp_cache_;
     199             :     bool run_with_vrouter_;
     200             :     uint32_t ip_fabric_interface_index_;
     201             :     MacAddress ip_fabric_interface_mac_;
     202             :     Interface *ip_fabric_interface_;
     203             :     DBTableBase::ListenerId vrf_table_listener_id_;
     204             :     DBTableBase::ListenerId interface_table_listener_id_;
     205             :     DBTableBase::ListenerId nexthop_table_listener_id_;
     206             :     InterfaceArpMap interface_arp_map_;
     207             : 
     208             :     uint16_t max_retries_;
     209             :     uint32_t retry_timeout_;   // milli seconds
     210             :     uint32_t aging_timeout_;   // milli seconds
     211             : 
     212             :     DISALLOW_COPY_AND_ASSIGN(ArpProto);
     213             : };
     214             : 
     215             : struct ArpPathPreferenceStateKey {
     216             :     IpAddress ip;
     217             :     uint8_t plen;
     218          85 :     ArpPathPreferenceStateKey(const IpAddress &addr, uint8_t len) :
     219          85 :         ip(addr), plen(len) {}
     220         334 :     bool IsLess(const ArpPathPreferenceStateKey &key) const {
     221         334 :         if (ip != key.ip) {
     222         236 :             return ip < key.ip;
     223             :         }
     224          98 :         return plen < key.plen;
     225             :     }
     226             : };
     227             : 
     228             : struct InterfaceArpPathPreferenceInfo {
     229             :     /* When prefix-len is less than 32 we send ARP request for all IPs in the
     230             :      * prefix. Whoever responds last, his IP will stored in field
     231             :      * prev_responded_ip. Subsequently periodic ARP requests will be sent
     232             :      * only for this IP instead of whole subnet. We will fallback to whole
     233             :      * subnet when prev_responded_ip does not respond for kMaxFailures times */
     234             :     Ip4Address prev_responded_ip;
     235             :     uint32_t arp_reply_count;
     236             :     uint32_t arp_failure_count;
     237             :     uint32_t arp_send_count;
     238             :     uint32_t arp_retry_count; //used by UT
     239             :     uint32_t arp_try_count;
     240          27 :     InterfaceArpPathPreferenceInfo() : prev_responded_ip(0), arp_reply_count(0),
     241          27 :         arp_failure_count(0), arp_send_count(0), arp_retry_count(0),
     242          27 :         arp_try_count(0) {
     243          27 :     }
     244             : };
     245             : //Stucture used to retry ARP queries when a particular route is in
     246             : //backup state.
     247             : class ArpPathPreferenceState {
     248             : public:
     249             :     static const uint32_t kMaxRetry = 30 * 5; //retries upto 5 minutes,
     250             :                                               //30 tries/per minutes
     251             :     static const uint32_t kTimeout = 2000;
     252             :     static const uint32_t kArpTryCount = 9;
     253             :     typedef std::map<uint32_t, InterfaceArpPathPreferenceInfo>
     254             :         WaitForTrafficIntfMap;
     255             :     typedef std::pair<uint32_t, InterfaceArpPathPreferenceInfo>
     256             :         WaitForTrafficIntfPair;
     257             :     typedef std::set<uint32_t> ArpTransmittedIntfMap;
     258             : 
     259             :     ArpPathPreferenceState(ArpVrfState *state, uint32_t vrf_id,
     260             :                            const IpAddress &vm_ip, uint8_t plen);
     261             :     ~ArpPathPreferenceState();
     262             : 
     263             :     bool SendArpRequest();
     264             :     bool SendArpRequest(WaitForTrafficIntfMap &wait_for_traffic_map,
     265             :                         ArpTransmittedIntfMap &arp_transmitted_intf_map);
     266             :     void SendArpRequestForAllIntf(const AgentRoute *route);
     267             :     void StartTimer();
     268             : 
     269          49 :     ArpVrfState* vrf_state() {
     270          49 :         return vrf_state_;
     271             :     }
     272             : 
     273         428 :     const IpAddress& ip() const { return vm_ip_; }
     274         232 :     uint8_t plen() const { return plen_; }
     275          70 :     void set_mac(MacAddress mac) { mac_ = mac; }
     276          98 :     MacAddress mac(void) const { return mac_; }
     277          98 :     uint32_t vrf_id() const { return vrf_id_; }
     278             :     void HandleArpReply(Ip4Address sip, uint32_t itf);
     279             : 
     280             : 
     281           6 :     bool IntfPresentInIpMap(uint32_t id) {
     282           6 :         if (l3_wait_for_traffic_map_.find(id) ==
     283          12 :                 l3_wait_for_traffic_map_.end()) {
     284           1 :             return false;
     285             :         }
     286           5 :         return true;
     287             :     }
     288             : 
     289           6 :     bool IntfPresentInEvpnMap(uint32_t id) {
     290           6 :         if (evpn_wait_for_traffic_map_.find(id) ==
     291          12 :                 evpn_wait_for_traffic_map_.end()) {
     292           1 :             return false;
     293             :         }
     294           5 :         return true;
     295             :     }
     296             : 
     297           4 :     uint32_t IntfRetryCountInIpMap(uint32_t id) {
     298           4 :         return GetRetryCount(id, l3_wait_for_traffic_map_);
     299             :     }
     300             : 
     301           5 :     uint32_t IntfRetryCountInEvpnMap(uint32_t id) {
     302           5 :         return GetRetryCount(id, evpn_wait_for_traffic_map_);
     303             :     }
     304             : 
     305             : private:
     306           9 :     uint32_t GetRetryCount(uint32_t id, WaitForTrafficIntfMap &imap) {
     307           9 :         WaitForTrafficIntfMap::iterator it = imap.find(id);
     308           9 :         if (it == imap.end()) {
     309           0 :             return 0;
     310             :         }
     311           9 :         return it->second.arp_retry_count;
     312             :     }
     313             :     friend void intrusive_ptr_add_ref(ArpPathPreferenceState *aps);
     314             :     friend void intrusive_ptr_release(ArpPathPreferenceState *aps);
     315             :     ArpVrfState *vrf_state_;
     316             :     Timer *arp_req_timer_;
     317             :     uint32_t vrf_id_;
     318             :     IpAddress vm_ip_;
     319             :     uint8_t plen_;
     320             :     MacAddress mac_;
     321             :     WaitForTrafficIntfMap l3_wait_for_traffic_map_;
     322             :     WaitForTrafficIntfMap evpn_wait_for_traffic_map_;
     323             :     std::atomic<int> refcount_;
     324             : };
     325             : 
     326             : typedef boost::intrusive_ptr<ArpPathPreferenceState> ArpPathPreferenceStatePtr;
     327             : 
     328             : void intrusive_ptr_add_ref(ArpPathPreferenceState *aps);
     329             : void intrusive_ptr_release(ArpPathPreferenceState *aps);
     330             : 
     331             : struct ArpPathPreferenceCmp {
     332         334 :     bool operator()(const ArpPathPreferenceStateKey &lhs,
     333             :                     const ArpPathPreferenceStateKey &rhs) const {
     334         334 :         return lhs.IsLess(rhs);
     335             :     }
     336             : };
     337             : 
     338             : struct ArpVrfState : public DBState {
     339             : public:
     340             :     typedef std::map<ArpPathPreferenceStateKey,
     341             :                      ArpPathPreferenceState*,
     342             :                      ArpPathPreferenceCmp> ArpPathPreferenceStateMap;
     343             :     typedef std::pair<ArpPathPreferenceStateKey,
     344             :                       ArpPathPreferenceState*> ArpPathPreferenceStatePair;
     345             :     ArpVrfState(Agent *agent, ArpProto *proto, VrfEntry *vrf,
     346             :                 AgentRouteTable *table, AgentRouteTable *evpn_table);
     347             :     ~ArpVrfState();
     348             :     void RouteUpdate(DBTablePartBase *part, DBEntryBase *entry);
     349             :     void EvpnRouteUpdate(DBTablePartBase *part, DBEntryBase *entry);
     350          16 :     void ManagedDelete() { deleted = true;}
     351             :     void Delete();
     352             :     bool DeleteRouteState(DBTablePartBase *part, DBEntryBase *entry);
     353             :     bool DeleteEvpnRouteState(DBTablePartBase *part, DBEntryBase *entry);
     354             :     bool PreWalkDone(DBTableBase *partition);
     355             :     static void WalkDone(DBTableBase *partition, ArpVrfState *state);
     356             : 
     357             :     ArpPathPreferenceState* Locate(const IpAddress &ip, uint8_t plen);
     358             :     void Erase(const IpAddress &ip, uint8_t plen);
     359             :     ArpPathPreferenceState* Get(const IpAddress ip, uint8_t plen=32);
     360             : 
     361          16 :     bool l3_walk_completed() const {
     362          16 :         return l3_walk_completed_;
     363             :     }
     364             : 
     365          16 :     bool evpn_walk_completed() const {
     366          16 :         return evpn_walk_completed_;
     367             :     }
     368             : 
     369             :     Agent *agent;
     370             :     ArpProto *arp_proto;
     371             :     VrfEntry *vrf;
     372             :     AgentRouteTable *rt_table;
     373             :     AgentRouteTable *evpn_rt_table;
     374             :     DBTableBase::ListenerId route_table_listener_id;
     375             :     DBTableBase::ListenerId evpn_route_table_listener_id;
     376             :     LifetimeRef<ArpVrfState> table_delete_ref;
     377             :     LifetimeRef<ArpVrfState> evpn_table_delete_ref;
     378             :     bool deleted;
     379             :     DBTable::DBTableWalkRef evpn_walk_ref_;
     380             :     DBTable::DBTableWalkRef managed_delete_walk_ref;
     381             :     ArpPathPreferenceStateMap arp_path_preference_map_;
     382             :     bool l3_walk_completed_;
     383             :     bool evpn_walk_completed_;
     384             :     friend class ArpProto;
     385             : };
     386             : 
     387             : class ArpDBState : public DBState {
     388             : public:
     389             :     static const uint32_t kMaxRetry = 30 * 5; //retries upto 5 minutes,
     390             :                                               //30 tries/per minutes
     391             :     static const uint32_t kTimeout = 2000;
     392             : 
     393             :     ArpDBState(ArpVrfState *vrf_state, uint32_t vrf_id,
     394             :                IpAddress vm_ip_addr, uint8_t plen);
     395             :     ~ArpDBState();
     396             :     void UpdateMac(const InterfaceNH *nh);
     397             :     void Update(const AgentRoute *route);
     398             :     void UpdateArpRoutes(const InetUnicastRouteEntry *route);
     399             :     void Delete(const InetUnicastRouteEntry *rt);
     400             : private:
     401             :     ArpVrfState *vrf_state_;
     402             :     SecurityGroupList sg_list_;
     403             :     TagList tag_list_;
     404             :     bool policy_;
     405             :     bool resolve_route_;
     406             :     VnListType vn_list_;
     407             :     ArpPathPreferenceStatePtr arp_path_preference_state_;
     408             : };
     409             : 
     410             : class ArpInterfaceState : public DBState {
     411             : public:
     412             :     ArpInterfaceState(Interface *intf);
     413             :     ~ArpInterfaceState();
     414             :     void SetVrf(VrfEntry *vrf, VrfEntry *fabric_vrf);
     415             : 
     416             : private:
     417             :     void WalkDone(DBTableBase *part);
     418             :     bool WalkNotify(DBTablePartBase *partition, DBEntryBase *entry);
     419             : 
     420             :     InterfaceRef intf_;
     421             :     VrfEntryRef vrf_;
     422             :     VrfEntryRef fabric_vrf_;
     423             :     DBTable::DBTableWalkRef walk_ref_;
     424             : };
     425             : #endif // vnsw_agent_arp_proto_hpp

Generated by: LCOV version 1.14