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 82 : ArpIpc(ArpProto::ArpMsgType msg, in_addr_t ip, const VrfEntry *vrf,
52 82 : InterfaceConstRef itf) :
53 82 : InterTaskMsg(msg), key(ip, vrf), interface_(itf) {}
54 :
55 : ArpKey key;
56 : InterfaceConstRef interface_;
57 : };
58 :
59 : struct ArpStats {
60 7 : ArpStats() { Reset(); }
61 12 : void Reset() {
62 12 : arp_req = arp_replies = arp_gratuitous =
63 12 : resolved = max_retries_exceeded = errors = 0;
64 12 : arp_invalid_packets = arp_invalid_interface = arp_invalid_vrf =
65 12 : arp_invalid_address = vm_arp_req = vm_garp_req =
66 12 : ipfabric_not_inst = 0;
67 12 : }
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 0 : 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 0 : 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 0 : Interface *ip_fabric_interface() const { return ip_fabric_interface_; }
110 0 : uint32_t ip_fabric_interface_index() const {
111 0 : return ip_fabric_interface_index_;
112 : }
113 0 : const MacAddress &ip_fabric_interface_mac() const {
114 0 : return ip_fabric_interface_mac_;
115 : }
116 0 : void set_ip_fabric_interface(Interface *itf) { ip_fabric_interface_ = itf; }
117 0 : void set_ip_fabric_interface_index(uint32_t ind) {
118 0 : ip_fabric_interface_index_ = ind;
119 0 : }
120 0 : void set_ip_fabric_interface_mac(const MacAddress &mac) {
121 0 : ip_fabric_interface_mac_ = mac;
122 0 : }
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 0 : 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 0 : 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 0 : 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 0 : ArpPathPreferenceStateKey(const IpAddress &addr, uint8_t len) :
219 0 : ip(addr), plen(len) {}
220 0 : bool IsLess(const ArpPathPreferenceStateKey &key) const {
221 0 : if (ip != key.ip) {
222 0 : return ip < key.ip;
223 : }
224 0 : 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 0 : InterfaceArpPathPreferenceInfo() : prev_responded_ip(0), arp_reply_count(0),
241 0 : arp_failure_count(0), arp_send_count(0), arp_retry_count(0),
242 0 : arp_try_count(0) {
243 0 : }
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 0 : ArpVrfState* vrf_state() {
270 0 : return vrf_state_;
271 : }
272 :
273 0 : const IpAddress& ip() const { return vm_ip_; }
274 0 : uint8_t plen() const { return plen_; }
275 0 : void set_mac(MacAddress mac) { mac_ = mac; }
276 0 : MacAddress mac(void) const { return mac_; }
277 0 : 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 0 : bool operator()(const ArpPathPreferenceStateKey &lhs,
333 : const ArpPathPreferenceStateKey &rhs) const {
334 0 : 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 0 : 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 0 : bool l3_walk_completed() const {
362 0 : return l3_walk_completed_;
363 : }
364 :
365 0 : bool evpn_walk_completed() const {
366 0 : 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
|