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
|