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

Generated by: LCOV version 1.14