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