Line data Source code
1 : /*
2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #ifndef vnsw_agent_icmpv6_proto_h
7 : #define vnsw_agent_icmpv6_proto_h
8 :
9 : #include <atomic>
10 :
11 : #include "pkt/proto.h"
12 : #include "services/icmpv6_handler.h"
13 : #include "services/ndp_entry.h"
14 :
15 : #define ICMP_PKT_SIZE 1024
16 : #define IPV6_ALL_NODES_ADDRESS "FF02::1"
17 : #define IPV6_ALL_ROUTERS_ADDRESS "FF02::2"
18 : #define PKT0_LINKLOCAL_ADDRESS "FE80::5E00:0100"
19 :
20 : #define NDP_TRACE(obj, ...) \
21 : do { \
22 : Ndp##obj::TraceMsg(Icmpv6TraceBuf, __FILE__, __LINE__, ##__VA_ARGS__); \
23 : } while (false) \
24 :
25 : #define ICMPV6_TRACE(obj, arg) \
26 : do { \
27 : std::ostringstream _str; \
28 : _str << arg; \
29 : Icmpv6##obj::TraceMsg(Icmpv6TraceBuf, __FILE__, __LINE__, _str.str()); \
30 : } while (false) \
31 :
32 : class Icmpv6VrfState;
33 : class Icmpv6PathPreferenceState;
34 :
35 : class Icmpv6Proto : public Proto {
36 : public:
37 : static const uint32_t kRouterAdvertTimeout = 30000; // milli seconds
38 : static const uint16_t kMaxRetries = 8;
39 : static const uint32_t kRetryTimeout = 2000; // milli seconds
40 : static const uint32_t kAgingTimeout = (5 * 60 * 1000); // milli seconds
41 :
42 : enum Icmpv6MsgType {
43 : NDP_RESOLVE,
44 : NDP_DELETE,
45 : NDP_SEND_UNSOL_NA,
46 : };
47 :
48 : struct Icmpv6Ipc : InterTaskMsg {
49 0 : Icmpv6Ipc(Icmpv6Proto::Icmpv6MsgType msg, NdpKey &akey, InterfaceConstRef itf)
50 0 : : InterTaskMsg(msg), key(akey), interface_(itf) {}
51 0 : Icmpv6Ipc(Icmpv6Proto::Icmpv6MsgType msg, Ip6Address ip,
52 0 : const VrfEntry *vrf, InterfaceConstRef itf) :
53 0 : InterTaskMsg(msg), key(ip, vrf), interface_(itf) {}
54 :
55 : NdpKey key;
56 : InterfaceConstRef interface_;
57 : };
58 :
59 : struct Icmpv6Stats {
60 1452 : Icmpv6Stats() { Reset(); }
61 1458 : void Reset() {
62 1458 : icmpv6_router_solicit_ = icmpv6_router_advert_ = 0;
63 1458 : icmpv6_ping_request_ = icmpv6_ping_response_ = icmpv6_drop_ = 0;
64 1458 : icmpv6_neighbor_solicit_ = icmpv6_neighbor_advert_solicited_ = 0;
65 1458 : icmpv6_neighbor_solicited_ = 0;
66 1458 : icmpv6_neighbor_advert_unsolicited_ = 0;
67 1458 : }
68 :
69 : uint32_t icmpv6_router_solicit_;
70 : uint32_t icmpv6_router_advert_;
71 : uint32_t icmpv6_ping_request_;
72 : uint32_t icmpv6_ping_response_;
73 : uint32_t icmpv6_drop_;
74 : uint32_t icmpv6_neighbor_solicit_;
75 : uint32_t icmpv6_neighbor_solicited_;
76 : uint32_t icmpv6_neighbor_advert_solicited_;
77 : uint32_t icmpv6_neighbor_advert_unsolicited_;
78 : };
79 :
80 : typedef std::map<VmInterface *, Icmpv6Stats> VmInterfaceMap;
81 : typedef std::pair<VmInterface *, Icmpv6Stats> VmInterfacePair;
82 : typedef std::map<NdpKey, NdpEntry *> NdpCache;
83 : typedef std::pair<NdpKey, NdpEntry *> NdpCachePair;
84 : typedef std::map<NdpKey, NdpEntry *>::iterator NdpIterator;
85 : typedef std::set<NdpKey> NdpKeySet;
86 : typedef std::set<NdpEntry *> NdpEntrySet;
87 : typedef std::map<NdpKey, NdpEntrySet> UnsolNaCache;
88 : typedef std::pair<NdpKey, NdpEntrySet> UnsolNaCachePair;
89 : typedef std::map<NdpKey, NdpEntrySet>::iterator UnsolNaIterator;
90 :
91 : struct InterfaceNdpInfo {
92 0 : InterfaceNdpInfo() : ndp_key_list(), stats() {}
93 : NdpKeySet ndp_key_list;
94 : Icmpv6Stats stats;
95 : };
96 : typedef std::map<uint32_t, InterfaceNdpInfo> InterfaceNdpMap;
97 : typedef std::pair<uint32_t, InterfaceNdpInfo> InterfaceNdpPair;
98 :
99 : void Shutdown();
100 : Icmpv6Proto(Agent *agent, boost::asio::io_context &io);
101 : virtual ~Icmpv6Proto();
102 : ProtoHandler *AllocProtoHandler(boost::shared_ptr<PktInfo> info,
103 : boost::asio::io_context &io);
104 : void VrfNotify(DBTablePartBase *part, DBEntryBase *entry);
105 : void VnNotify(DBEntryBase *entry);
106 : void InterfaceNotify(DBEntryBase *entry);
107 : void NexthopNotify(DBEntryBase *entry);
108 : void SendIcmpv6Ipc(Icmpv6Proto::Icmpv6MsgType type, Ip6Address ip,
109 : const VrfEntry *vrf, InterfaceConstRef itf);
110 :
111 0 : const VmInterfaceMap &vm_interfaces() { return vm_interfaces_; }
112 :
113 : void IncrementStatsRouterSolicit(VmInterface *vmi);
114 : void IncrementStatsRouterAdvert(VmInterface *vmi);
115 : void IncrementStatsPingRequest(VmInterface *vmi);
116 : void IncrementStatsPingResponse(VmInterface *vmi);
117 0 : void IncrementStatsDrop() { stats_.icmpv6_drop_++; }
118 : void IncrementStatsNeighborAdvertSolicited(VmInterface *vmi);
119 : void IncrementStatsNeighborAdvertUnSolicited(VmInterface *vmi);
120 : void IncrementStatsNeighborSolicit(VmInterface *vmi);
121 : void IncrementStatsNeighborSolicited(VmInterface *vmi);
122 8 : const Icmpv6Stats &GetStats() const { return stats_; }
123 : Icmpv6Stats *VmiToIcmpv6Stats(VmInterface *i);
124 6 : void ClearStats() { stats_.Reset(); }
125 : bool ValidateAndClearVrfState(VrfEntry *vrf, Icmpv6VrfState *state);
126 : Icmpv6VrfState *CreateAndSetVrfState(VrfEntry *vrf);
127 :
128 0 : Interface *ip_fabric_interface() const { return ip_fabric_interface_; }
129 0 : uint32_t ip_fabric_interface_index() const {
130 0 : return ip_fabric_interface_index_;
131 : }
132 0 : const MacAddress &ip_fabric_interface_mac() const {
133 0 : return ip_fabric_interface_mac_;
134 : }
135 2 : void set_ip_fabric_interface(Interface *itf) { ip_fabric_interface_ = itf; }
136 2 : void set_ip_fabric_interface_index(uint32_t ind) {
137 2 : ip_fabric_interface_index_ = ind;
138 2 : }
139 2 : void set_ip_fabric_interface_mac(const MacAddress &mac) {
140 2 : ip_fabric_interface_mac_ = mac;
141 2 : }
142 :
143 : bool AddNdpEntry(NdpEntry *entry);
144 : bool DeleteNdpEntry(NdpEntry *entry);
145 : NdpEntry *FindNdpEntry(const NdpKey &key);
146 3 : std::size_t GetNdpCacheSize() { return ndp_cache_.size(); }
147 : const NdpCache& ndp_cache() { return ndp_cache_; }
148 : const UnsolNaCache& unsol_na_cache() { return unsol_na_cache_; }
149 : const InterfaceNdpMap& interface_ndp_map() { return interface_ndp_map_; }
150 :
151 : void AddUnsolNaEntry(NdpKey &key);
152 : void DeleteUnsolNaEntry(NdpEntry *entry);
153 : void HandlePathPreferenceNA(const VrfEntry*, uint32_t, IpAddress);
154 : NdpEntry* FindUnsolNaEntry(NdpKey &key);
155 : NdpEntry* UnsolNaEntry (const NdpKey &key, const Interface *intf);
156 : Icmpv6Proto::UnsolNaIterator
157 : UnsolNaEntryIterator(const NdpKey &key, bool *key_valid);
158 21 : DBTableBase::ListenerId vrf_table_listener_id() const {
159 21 : return vrf_table_listener_id_;
160 : }
161 :
162 : private:
163 : Timer *timer_;
164 : Icmpv6Stats stats_;
165 : VmInterfaceMap vm_interfaces_;
166 : NdpCache ndp_cache_;
167 : UnsolNaCache unsol_na_cache_;
168 : InterfaceNdpMap interface_ndp_map_;
169 : bool HandlePacket();
170 : bool HandleMessage();
171 : Icmpv6Proto::NdpIterator DeleteNdpEntry(Icmpv6Proto::NdpIterator iter);
172 : void SendIcmpv6Ipc(Icmpv6Proto::Icmpv6MsgType type, NdpKey &key,
173 : InterfaceConstRef itf);
174 : // handler to send router advertisements and neighbor solicits
175 : boost::scoped_ptr<Icmpv6Handler> icmpv6_handler_;
176 : DBTableBase::ListenerId vn_table_listener_id_;
177 : DBTableBase::ListenerId vrf_table_listener_id_;
178 : DBTableBase::ListenerId interface_listener_id_;
179 : DBTableBase::ListenerId nexthop_listener_id_;
180 : uint32_t ip_fabric_interface_index_;
181 : MacAddress ip_fabric_interface_mac_;
182 : Interface *ip_fabric_interface_;
183 : DISALLOW_COPY_AND_ASSIGN(Icmpv6Proto);
184 : };
185 :
186 : class Icmpv6VrfState : public DBState {
187 : public:
188 : typedef std::map<const IpAddress,
189 : Icmpv6PathPreferenceState*> Icmpv6PathPreferenceStateMap;
190 : typedef std::pair<const IpAddress,
191 : Icmpv6PathPreferenceState*> Icmpv6PathPreferenceStatePair;
192 :
193 : Icmpv6VrfState(Agent *agent, Icmpv6Proto *proto, VrfEntry *vrf,
194 : AgentRouteTable *table, AgentRouteTable *evpn_table);
195 : ~Icmpv6VrfState();
196 0 : Agent *agent() const { return agent_; }
197 0 : Icmpv6Proto * icmp_proto() const { return icmp_proto_; }
198 74 : void set_route_table_listener_id(const DBTableBase::ListenerId &id) {
199 74 : route_table_listener_id_ = id;
200 74 : }
201 74 : void set_evpn_route_table_listener_id(const DBTableBase::ListenerId &id) {
202 74 : evpn_route_table_listener_id_ = id;
203 74 : }
204 124 : bool default_routes_added() const { return default_routes_added_; }
205 317 : void set_default_routes_added(bool value) { default_routes_added_ = value; }
206 :
207 : void RouteUpdate(DBTablePartBase *part, DBEntryBase *entry);
208 : void EvpnRouteUpdate(DBTablePartBase *part, DBEntryBase *entry);
209 148 : void ManagedDelete() { deleted_ = true;}
210 : void Delete();
211 : bool DeleteRouteState(DBTablePartBase *part, DBEntryBase *entry);
212 : bool DeleteEvpnRouteState(DBTablePartBase *part, DBEntryBase *entry);
213 : bool PreWalkDone(DBTableBase *partition);
214 : static void WalkDone(DBTableBase *partition, Icmpv6VrfState *state);
215 0 : bool deleted() const {return deleted_;}
216 :
217 : Icmpv6PathPreferenceState* Locate(const IpAddress &ip);
218 : void Erase(const IpAddress &ip);
219 21 : Icmpv6PathPreferenceState* Get(const IpAddress ip) {
220 21 : return icmpv6_path_preference_map_[ip];
221 : }
222 :
223 148 : bool l3_walk_completed() const {
224 148 : return l3_walk_completed_;
225 : }
226 :
227 130 : bool evpn_walk_completed() const {
228 130 : return evpn_walk_completed_;
229 : }
230 74 : DBTable::DBTableWalkRef managed_delete_walk_ref() {
231 74 : return managed_delete_walk_ref_;
232 : }
233 74 : DBTable::DBTableWalkRef evpn_walk_ref() {
234 74 : return evpn_walk_ref_;
235 : }
236 :
237 : private:
238 : Agent *agent_;
239 : Icmpv6Proto *icmp_proto_;
240 : VrfEntry *vrf_;
241 : AgentRouteTable *rt_table_;
242 : AgentRouteTable *evpn_rt_table_;
243 : DBTableBase::ListenerId route_table_listener_id_;
244 : DBTableBase::ListenerId evpn_route_table_listener_id_;
245 : LifetimeRef<Icmpv6VrfState> table_delete_ref_;
246 : LifetimeRef<Icmpv6VrfState> evpn_table_delete_ref_;
247 : bool deleted_;
248 : bool default_routes_added_;
249 : DBTable::DBTableWalkRef managed_delete_walk_ref_;
250 : DBTable::DBTableWalkRef evpn_walk_ref_;
251 : Icmpv6PathPreferenceStateMap icmpv6_path_preference_map_;
252 : bool l3_walk_completed_;
253 : bool evpn_walk_completed_;
254 : DISALLOW_COPY_AND_ASSIGN(Icmpv6VrfState);
255 : };
256 :
257 : struct InterfaceIcmpv6PathPreferenceInfo {
258 : uint32_t ns_try_count;
259 : uint32_t ns_send_count;
260 : uint32_t ns_retry_count;
261 10 : InterfaceIcmpv6PathPreferenceInfo() :ns_try_count(0), ns_send_count(0),
262 10 : ns_retry_count(0) {
263 10 : }
264 : };
265 :
266 : class Icmpv6PathPreferenceState {
267 : public:
268 : static const uint32_t kMaxRetry = 30 * 5; //retries upto 5 minutes,
269 : //30 tries/per minutes
270 : static const uint32_t kTimeout = 2000;
271 :
272 : static const uint32_t kTimeoutMultiplier = 5;
273 :
274 : static const uint32_t kNSTryCount = 9;
275 :
276 : typedef std::map<uint32_t, InterfaceIcmpv6PathPreferenceInfo> WaitForTrafficIntfMap;
277 : typedef std::set<uint32_t> NDTransmittedIntfMap;
278 :
279 : Icmpv6PathPreferenceState(Icmpv6VrfState *vrf_state, uint32_t vrf_id,
280 : IpAddress vm_ip_addr, uint8_t plen);
281 : ~Icmpv6PathPreferenceState();
282 : bool SendNeighborSolicit();
283 : bool SendNeighborSolicit(WaitForTrafficIntfMap &wait_for_traffic_map,
284 : NDTransmittedIntfMap &nd_transmitted_map);
285 : void SendNeighborSolicitForAllIntf(const AgentRoute *route);
286 : void StartTimer();
287 : void HandleNA(uint32_t itf);
288 363 : Icmpv6VrfState* vrf_state() {
289 363 : return vrf_state_;
290 : }
291 :
292 363 : const IpAddress& ip() const {
293 363 : return vm_ip_;
294 : }
295 :
296 : MacAddress mac(void) const { return mac_; }
297 :
298 6 : bool IntfPresentInIpMap(uint32_t id) {
299 6 : if (l3_wait_for_traffic_map_.find(id) ==
300 12 : l3_wait_for_traffic_map_.end()) {
301 1 : return false;
302 : }
303 5 : return true;
304 : }
305 :
306 6 : bool IntfPresentInEvpnMap(uint32_t id) {
307 6 : if (evpn_wait_for_traffic_map_.find(id) ==
308 12 : evpn_wait_for_traffic_map_.end()) {
309 1 : return false;
310 : }
311 5 : return true;
312 : }
313 :
314 4 : uint32_t IntfRetryCountInIpMap(uint32_t id) {
315 4 : return l3_wait_for_traffic_map_[id].ns_retry_count;
316 : }
317 :
318 5 : uint32_t IntfRetryCountInEvpnMap(uint32_t id) {
319 5 : return evpn_wait_for_traffic_map_[id].ns_retry_count;
320 : }
321 :
322 : private:
323 : friend void intrusive_ptr_add_ref(Icmpv6PathPreferenceState *ps);
324 : friend void intrusive_ptr_release(Icmpv6PathPreferenceState *ps);
325 : Icmpv6VrfState *vrf_state_;
326 : Timer *ns_req_timer_;
327 : uint32_t vrf_id_;
328 : IpAddress vm_ip_;
329 : MacAddress mac_;
330 : uint8_t plen_;
331 : IpAddress svc_ip_;
332 : WaitForTrafficIntfMap l3_wait_for_traffic_map_;
333 : WaitForTrafficIntfMap evpn_wait_for_traffic_map_;
334 : std::atomic<int> refcount_;
335 : };
336 :
337 : typedef boost::intrusive_ptr<Icmpv6PathPreferenceState>
338 : Icmpv6PathPreferenceStatePtr;
339 :
340 : void intrusive_ptr_add_ref(Icmpv6PathPreferenceState *ps);
341 : void intrusive_ptr_release(Icmpv6PathPreferenceState *ps);
342 :
343 : class Icmpv6RouteState : public DBState {
344 : public:
345 : Icmpv6RouteState(Icmpv6VrfState *vrf_state, uint32_t vrf_id,
346 : IpAddress vm_ip_addr, uint8_t plen);
347 : ~Icmpv6RouteState();
348 : void SendNeighborSolicitForAllIntf(const AgentRoute *route);
349 : private:
350 : Icmpv6PathPreferenceStatePtr icmpv6_path_preference_state_;
351 : };
352 : #endif // vnsw_agent_icmpv6_proto_h
|