Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "base/os.h"
6 : #include <init/agent_init.h>
7 : #include <pkt/pkt_handler.h>
8 : #include "pkt/pkt_init.h"
9 : #include <oper/route_common.h>
10 : #include <services/icmpv6_proto.h>
11 : #include "mac_learning/mac_learning_proto.h"
12 :
13 2 : Icmpv6Proto::Icmpv6Proto(Agent *agent, boost::asio::io_context &io) :
14 2 : Proto(agent, "Agent::Services", PktHandler::ICMPV6, io) {
15 : // limit the number of entries in the workqueue
16 2 : work_queue_.SetSize(agent->params()->services_queue_limit());
17 2 : work_queue_.SetBounded(true);
18 :
19 2 : vn_table_listener_id_ = agent->vn_table()->Register(
20 : boost::bind(&Icmpv6Proto::VnNotify, this, _2));
21 2 : vrf_table_listener_id_ = agent->vrf_table()->Register(
22 : boost::bind(&Icmpv6Proto::VrfNotify, this, _1, _2));
23 2 : interface_listener_id_ = agent->interface_table()->Register(
24 : boost::bind(&Icmpv6Proto::InterfaceNotify,
25 : this, _2));
26 2 : nexthop_listener_id_ = agent->nexthop_table()->Register(
27 : boost::bind(&Icmpv6Proto::NexthopNotify, this, _2));
28 :
29 2 : boost::shared_ptr<PktInfo> pkt_info(new PktInfo(PktHandler::ICMPV6, NULL));
30 2 : icmpv6_handler_.reset(new Icmpv6Handler(agent, pkt_info, io));
31 :
32 2 : timer_ = TimerManager::CreateTimer(io, "Icmpv6Timer",
33 : TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
34 : PktHandler::ICMPV6);
35 2 : timer_->Start(kRouterAdvertTimeout,
36 : boost::bind(&Icmpv6Handler::RouterAdvertisement,
37 : icmpv6_handler_.get(), this));
38 2 : }
39 :
40 4 : Icmpv6Proto::~Icmpv6Proto() {
41 4 : }
42 :
43 2 : void Icmpv6Proto::Shutdown() {
44 2 : agent_->vn_table()->Unregister(vn_table_listener_id_);
45 2 : agent_->vrf_table()->Unregister(vrf_table_listener_id_);
46 2 : agent_->interface_table()->Unregister(interface_listener_id_);
47 2 : timer_->Cancel();
48 2 : TimerManager::DeleteTimer(timer_);
49 2 : }
50 :
51 0 : ProtoHandler *Icmpv6Proto::AllocProtoHandler(boost::shared_ptr<PktInfo> info,
52 : boost::asio::io_context &io) {
53 0 : return new Icmpv6Handler(agent(), info, io);
54 : }
55 :
56 24 : Icmpv6VrfState *Icmpv6Proto::CreateAndSetVrfState(VrfEntry *vrf) {
57 : Icmpv6VrfState *state = new Icmpv6VrfState(agent_, this, vrf,
58 24 : vrf->GetInet6UnicastRouteTable(),
59 24 : vrf->GetEvpnRouteTable());
60 24 : state->set_route_table_listener_id(vrf->GetInet6UnicastRouteTable()->
61 24 : Register(boost::bind(&Icmpv6VrfState::RouteUpdate, state, _1, _2)));
62 24 : state->set_evpn_route_table_listener_id(vrf->GetEvpnRouteTable()->
63 24 : Register(boost::bind(&Icmpv6VrfState::EvpnRouteUpdate, state, _1, _2)));
64 24 : vrf->SetState(vrf->get_table_partition()->parent(),
65 : vrf_table_listener_id_, state);
66 24 : return state;
67 : }
68 :
69 61 : void Icmpv6Proto::VnNotify(DBEntryBase *entry) {
70 61 : if (entry->IsDeleted()) return;
71 :
72 41 : VnEntry *vn = static_cast<VnEntry *>(entry);
73 41 : VrfEntry *vrf = vn->GetVrf();
74 41 : if (!vrf || vrf->IsDeleted()) return;
75 :
76 17 : if (vrf->GetName() == agent_->fabric_vrf_name())
77 0 : return;
78 :
79 17 : if (vn->layer3_forwarding()) {
80 17 : Icmpv6VrfState *state = static_cast<Icmpv6VrfState *>(vrf->GetState(
81 : vrf->get_table_partition()->parent(),
82 : vrf_table_listener_id_));
83 17 : if (state == NULL) {
84 0 : state = CreateAndSetVrfState(vrf);
85 : }
86 17 : if (state->default_routes_added()) {
87 0 : return;
88 : }
89 :
90 17 : boost::system::error_code ec;
91 17 : Ip6Address addr = Ip6Address::from_string(IPV6_ALL_ROUTERS_ADDRESS, ec);
92 : static_cast<InetUnicastAgentRouteTable *>
93 17 : (vrf->GetInet6UnicastRouteTable())->AddHostRoute(vrf->GetName(),
94 : addr, 128,
95 : vn->GetName(), false);
96 17 : addr = Ip6Address::from_string(IPV6_ALL_NODES_ADDRESS, ec);
97 : static_cast<InetUnicastAgentRouteTable *>
98 17 : (vrf->GetInet6UnicastRouteTable())->AddHostRoute(vrf->GetName(),
99 : addr, 128,
100 : vn->GetName(), false);
101 : /* We need route for PKT0_LINKLOCAL_ADDRESS so that vrouter can respond
102 : * to NDP requests for PKT0_LINKLOCAL_ADDRESS. Even though the nexthop
103 : * for this route is pkt0, vrouter never sends pkts pointing to this
104 : * route on pkt0.
105 : */
106 17 : addr = Ip6Address::from_string(PKT0_LINKLOCAL_ADDRESS, ec);
107 : static_cast<InetUnicastAgentRouteTable *>
108 17 : (vrf->GetInet6UnicastRouteTable())->AddHostRoute(vrf->GetName(),
109 : addr, 128,
110 : vn->GetName(), false);
111 17 : state->set_default_routes_added(true);
112 : }
113 : }
114 :
115 265 : void Icmpv6Proto::VrfNotify(DBTablePartBase *part, DBEntryBase *entry) {
116 265 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
117 :
118 265 : Icmpv6VrfState *state = static_cast<Icmpv6VrfState *>(vrf->GetState(
119 : vrf->get_table_partition()->parent(),
120 : vrf_table_listener_id_));
121 265 : if (entry->IsDeleted()) {
122 209 : if (state) {
123 122 : boost::system::error_code ec;
124 : Ip6Address addr =
125 122 : Ip6Address::from_string(IPV6_ALL_ROUTERS_ADDRESS, ec);
126 : // enqueue delete request on fabric VRF
127 244 : agent_->fabric_inet4_unicast_table()->DeleteReq(
128 122 : agent_->local_peer(), vrf->GetName(), addr, 128, NULL);
129 122 : addr = Ip6Address::from_string(IPV6_ALL_NODES_ADDRESS, ec);
130 244 : agent_->fabric_inet4_unicast_table()->DeleteReq(
131 122 : agent_->local_peer(), vrf->GetName(), addr, 128, NULL);
132 122 : addr = Ip6Address::from_string(PKT0_LINKLOCAL_ADDRESS, ec);
133 244 : agent_->fabric_inet4_unicast_table()->DeleteReq(
134 122 : agent_->local_peer(), vrf->GetName(), addr, 128, NULL);
135 122 : state->set_default_routes_added(false);
136 122 : state->Delete();
137 : }
138 209 : return;
139 : }
140 56 : if (!state) {
141 24 : CreateAndSetVrfState(vrf);
142 : }
143 : }
144 :
145 144 : void Icmpv6Proto::InterfaceNotify(DBEntryBase *entry) {
146 144 : Interface *intrface = static_cast<Interface *>(entry);
147 144 : if (intrface->type() != Interface::VM_INTERFACE)
148 19 : return;
149 :
150 125 : Icmpv6Stats stats;
151 125 : VmInterface *vm_interface = static_cast<VmInterface *>(entry);
152 125 : VmInterfaceMap::iterator it = vm_interfaces_.find(vm_interface);
153 125 : if (intrface->IsDeleted()) {
154 30 : if (it != vm_interfaces_.end()) {
155 30 : vm_interfaces_.erase(it);
156 : }
157 30 : if (vm_interface->vmi_type() == VmInterface::VHOST) {
158 0 : set_ip_fabric_interface(NULL);
159 0 : set_ip_fabric_interface_index(-1);
160 : }
161 : } else {
162 95 : if (it == vm_interfaces_.end()) {
163 30 : vm_interfaces_.insert(VmInterfacePair(vm_interface, stats));
164 : }
165 95 : if (vm_interface->vmi_type() == VmInterface::VHOST) {
166 2 : set_ip_fabric_interface(intrface);
167 2 : set_ip_fabric_interface_index(intrface->id());
168 2 : set_ip_fabric_interface_mac(intrface->mac());
169 : }
170 : }
171 : }
172 :
173 0 : void Icmpv6Proto::SendIcmpv6Ipc(Icmpv6Proto::Icmpv6MsgType type, Ip6Address ip,
174 : const VrfEntry *vrf, InterfaceConstRef itf) {
175 0 : Icmpv6Ipc *ipc = new Icmpv6Ipc(type, ip, vrf, itf);
176 0 : agent_->pkt()->pkt_handler()->SendMessage(PktHandler::ICMPV6, ipc);
177 0 : }
178 :
179 0 : void Icmpv6Proto::SendIcmpv6Ipc(Icmpv6Proto::Icmpv6MsgType type, NdpKey &key,
180 : InterfaceConstRef itf) {
181 0 : Icmpv6Ipc *ipc = new Icmpv6Ipc(type, key, itf);
182 0 : agent_->pkt()->pkt_handler()->SendMessage(PktHandler::ICMPV6, ipc);
183 0 : }
184 :
185 528 : void Icmpv6Proto::NexthopNotify(DBEntryBase *entry) {
186 528 : NextHop *nh = static_cast<NextHop *>(entry);
187 :
188 528 : switch(nh->GetType()) {
189 0 : case NextHop::NDP: {
190 0 : NdpNH *ndp_nh = (static_cast<NdpNH *>(nh));
191 0 : if (ndp_nh->IsDeleted()) {
192 0 : SendIcmpv6Ipc(Icmpv6Proto::NDP_DELETE, ndp_nh->GetIp()->to_v6(),
193 : ndp_nh->GetVrf(), ndp_nh->GetInterface());
194 0 : } else if (ndp_nh->IsValid() == false && ndp_nh->GetInterface()) {
195 0 : SendIcmpv6Ipc(Icmpv6Proto::NDP_RESOLVE, ndp_nh->GetIp()->to_v6(),
196 : ndp_nh->GetVrf(), ndp_nh->GetInterface());
197 : }
198 0 : break;
199 : }
200 :
201 528 : default:
202 528 : break;
203 : }
204 528 : }
205 :
206 48 : bool Icmpv6Proto::ValidateAndClearVrfState(VrfEntry *vrf,
207 : Icmpv6VrfState *vrf_state) {
208 48 : if (!vrf->IsDeleted()) {
209 0 : return false;
210 : }
211 :
212 48 : if (vrf_state->l3_walk_completed() == false) {
213 11 : return false;
214 : }
215 :
216 37 : if (vrf_state->evpn_walk_completed() == false) {
217 13 : return false;
218 : }
219 :
220 72 : if (vrf_state->managed_delete_walk_ref().get() != NULL ||
221 48 : vrf_state->evpn_walk_ref().get() != NULL) {
222 0 : return false;
223 : }
224 :
225 : DBState *state = static_cast<DBState *>
226 24 : (vrf->GetState(vrf->get_table_partition()->parent(),
227 : vrf_table_listener_id_));
228 24 : if (state) {
229 24 : vrf->ClearState(vrf->get_table_partition()->parent(),
230 : vrf_table_listener_id_);
231 : }
232 24 : return true;
233 : }
234 :
235 236 : void Icmpv6VrfState::RouteUpdate(DBTablePartBase *part, DBEntryBase *entry) {
236 236 : InetUnicastRouteEntry *route = static_cast<InetUnicastRouteEntry *>(entry);
237 :
238 : Icmpv6RouteState *state = static_cast<Icmpv6RouteState *>
239 236 : (entry->GetState(part->parent(), route_table_listener_id_));
240 :
241 : #if 0
242 : // This is the code for sending unsolicited NA for vhost0 but it should
243 : // be taken care of by linux itself
244 : const InterfaceNH *intf_nh = dynamic_cast<const InterfaceNH *>(
245 : route->GetActiveNextHop());
246 : const Interface *intf = (intf_nh) ?
247 : static_cast<const Interface *>(intf_nh->GetInterface()) : NULL;
248 :
249 : NdpKey key(route->prefix_address().to_v6(), route->vrf());
250 : NdpEntry *ndpentry = icmp_proto_->UnsolNaEntry(key, intf);
251 : if (route->vrf()->GetName() == agent_->fabric_vrf_name()) {
252 : ndpentry = icmp_proto_->UnsolNaEntry(key, icmp_proto_->ip_fabric_interface());
253 : }
254 : #endif
255 236 : if (entry->IsDeleted() || deleted_) {
256 78 : if (state) {
257 : //icmp_proto_->DeleteUnsolNaEntry(ndpentry);
258 78 : entry->ClearState(part->parent(), route_table_listener_id_);
259 78 : delete state;
260 : }
261 78 : return;
262 : }
263 :
264 158 : if (!state) {
265 78 : state = new Icmpv6RouteState(this, route->vrf_id(), route->prefix_address(),
266 78 : route->prefix_length());
267 78 : entry->SetState(part->parent(), route_table_listener_id_, state);
268 : }
269 :
270 : #if 0
271 : // May not be needed since kernel can take care of sending unsolicited NA
272 : if (route->vrf()->GetName() == agent_->fabric_vrf_name() &&
273 : route->GetActiveNextHop()->GetType() == NextHop::RECEIVE &&
274 : icmp_proto_->agent()->router_id6() == route->prefix_address().to_v6()) {
275 : //Send unsolicited NA
276 : icmp_proto_->AddUnsolNaEntry(key);
277 : icmp_proto_->SendIcmpv6Ipc(Icmpv6Proto::NDP_SEND_UNSOL_NA,
278 : route->prefix_address().to_v6(), route->vrf(),
279 : icmp_proto_->ip_fabric_interface());
280 : }
281 : #endif
282 :
283 : //Check if there is a local VM path, if yes send a
284 : //Neighbor Solicit request, to trigger route preference state machine
285 316 : if (state && route->GetTableType() == Agent::INET6_UNICAST &&
286 158 : route->vrf()->GetName() != agent_->fabric_vrf_name()) {
287 108 : state->SendNeighborSolicitForAllIntf(route);
288 : }
289 : }
290 :
291 174 : void Icmpv6VrfState::EvpnRouteUpdate(DBTablePartBase *part, DBEntryBase *entry) {
292 174 : EvpnRouteEntry *route = static_cast<EvpnRouteEntry *>(entry);
293 :
294 : Icmpv6RouteState *state = static_cast<Icmpv6RouteState *>
295 174 : (entry->GetState(part->parent(), evpn_route_table_listener_id_));
296 :
297 174 : if (entry->IsDeleted() || deleted_) {
298 56 : if (state) {
299 56 : entry->ClearState(part->parent(), evpn_route_table_listener_id_);
300 56 : delete state;
301 : }
302 56 : return;
303 : }
304 :
305 118 : if (!state) {
306 56 : state = new Icmpv6RouteState(this, route->vrf_id(), route->prefix_address(),
307 56 : route->prefix_length());
308 56 : entry->SetState(part->parent(), evpn_route_table_listener_id_, state);
309 : }
310 :
311 : //Check if there is a local VM path, if yes send a
312 : //Neighbor Solicit request, to trigger route preference state machine
313 118 : if (state && route->vrf()->GetName() != agent_->fabric_vrf_name()) {
314 118 : state->SendNeighborSolicitForAllIntf(route);
315 : }
316 : }
317 :
318 0 : bool Icmpv6VrfState::DeleteRouteState(DBTablePartBase *part, DBEntryBase *ent) {
319 0 : RouteUpdate(part, ent);
320 0 : return true;
321 : }
322 :
323 0 : bool Icmpv6VrfState::DeleteEvpnRouteState(DBTablePartBase *part,
324 : DBEntryBase *ent) {
325 0 : EvpnRouteUpdate(part, ent);
326 0 : return true;
327 : }
328 :
329 122 : void Icmpv6VrfState::Delete() {
330 122 : if (managed_delete_walk_ref_.get() == NULL)
331 13 : return;
332 :
333 109 : rt_table_->WalkAgain(managed_delete_walk_ref_);
334 109 : if (evpn_walk_ref_.get())
335 95 : evpn_rt_table_->WalkAgain(evpn_walk_ref_);
336 109 : deleted_ = true;
337 : }
338 :
339 48 : bool Icmpv6VrfState::PreWalkDone(DBTableBase *partition) {
340 48 : if (icmp_proto_->ValidateAndClearVrfState(vrf_, this) == false) {
341 24 : return false;
342 : }
343 :
344 24 : rt_table_->Unregister(route_table_listener_id_);
345 24 : table_delete_ref_.Reset(NULL);
346 :
347 24 : evpn_rt_table_->Unregister(evpn_route_table_listener_id_);
348 24 : evpn_table_delete_ref_.Reset(NULL);
349 24 : return true;
350 : }
351 :
352 48 : void Icmpv6VrfState::WalkDone(DBTableBase *partition, Icmpv6VrfState *state) {
353 48 : if (partition == state->rt_table_) {
354 24 : state->rt_table_->ReleaseWalker(state->managed_delete_walk_ref_);
355 24 : state->managed_delete_walk_ref_ = NULL;
356 24 : state->l3_walk_completed_ = true;
357 : } else {
358 24 : state->evpn_rt_table_->ReleaseWalker(state->evpn_walk_ref_);
359 24 : state->evpn_walk_ref_ = NULL;
360 24 : state->evpn_walk_completed_ = true;
361 : }
362 :
363 48 : if (state->PreWalkDone(partition)) {
364 24 : delete state;
365 : }
366 48 : }
367 :
368 76 : Icmpv6PathPreferenceState* Icmpv6VrfState::Locate(const IpAddress &ip) {
369 76 : Icmpv6PathPreferenceState* ptr = icmpv6_path_preference_map_[ip];
370 76 : if (ptr == NULL) {
371 76 : ptr = new Icmpv6PathPreferenceState(this, vrf_->vrf_id(), ip, 128);
372 76 : icmpv6_path_preference_map_[ip] = ptr;
373 : }
374 76 : return ptr;
375 : }
376 :
377 0 : void Icmpv6PathPreferenceState::HandleNA(uint32_t itf) {
378 0 : WaitForTrafficIntfMap::iterator it = l3_wait_for_traffic_map_.find(itf);
379 0 : if (it == l3_wait_for_traffic_map_.end()) {
380 0 : return;
381 : }
382 0 : InterfaceIcmpv6PathPreferenceInfo &data = it->second;
383 :
384 : // resetting ns_try_count as interface sent NA
385 0 : data.ns_try_count = 0;
386 :
387 : }
388 :
389 0 : void Icmpv6Proto::HandlePathPreferenceNA(const VrfEntry *vrf, uint32_t itf,
390 : IpAddress sip) {
391 0 : if (!vrf) {
392 0 : return;
393 : }
394 0 : InetUnicastRouteEntry *rt = vrf->GetUcRoute(sip);
395 0 : if (!rt) {
396 0 : return;
397 : }
398 :
399 : Icmpv6VrfState *state = static_cast<Icmpv6VrfState *>
400 0 : (vrf->GetState(vrf->get_table_partition()->parent(),
401 : vrf_table_listener_id_));
402 0 : if (!state) {
403 0 : return;
404 : }
405 0 : Icmpv6PathPreferenceState *pstate = state->Get(sip);
406 0 : if (!pstate) {
407 0 : return;
408 : }
409 0 : pstate->HandleNA(itf);
410 : }
411 :
412 76 : void Icmpv6VrfState::Erase(const IpAddress &ip) {
413 76 : icmpv6_path_preference_map_.erase(ip);
414 76 : }
415 :
416 24 : Icmpv6VrfState::Icmpv6VrfState(Agent *agent_ptr, Icmpv6Proto *proto,
417 : VrfEntry *vrf_entry, AgentRouteTable *table,
418 24 : AgentRouteTable *evpn_rt_table):
419 24 : agent_(agent_ptr), icmp_proto_(proto), vrf_(vrf_entry), rt_table_(table),
420 24 : evpn_rt_table_(evpn_rt_table),
421 24 : route_table_listener_id_(DBTableBase::kInvalidId),
422 24 : evpn_route_table_listener_id_(DBTableBase::kInvalidId),
423 24 : table_delete_ref_(this, table->deleter()),
424 24 : evpn_table_delete_ref_(this, evpn_rt_table_->deleter()),
425 24 : deleted_(false),
426 48 : default_routes_added_(false), l3_walk_completed_(false),
427 48 : evpn_walk_completed_(false) {
428 48 : evpn_walk_ref_ = evpn_rt_table_->AllocWalker(
429 : boost::bind(&Icmpv6VrfState::DeleteEvpnRouteState, this, _1, _2),
430 24 : boost::bind(&Icmpv6VrfState::WalkDone, _2, this));
431 48 : managed_delete_walk_ref_ = table->AllocWalker(
432 : boost::bind(&Icmpv6VrfState::DeleteRouteState, this, _1, _2),
433 24 : boost::bind(&Icmpv6VrfState::WalkDone, _2, this));
434 24 : }
435 :
436 48 : Icmpv6VrfState::~Icmpv6VrfState() {
437 24 : assert(icmpv6_path_preference_map_.size() == 0);
438 48 : }
439 :
440 76 : void intrusive_ptr_add_ref(Icmpv6PathPreferenceState *ps) {
441 76 : ps->refcount_++;
442 76 : }
443 :
444 76 : void intrusive_ptr_release(Icmpv6PathPreferenceState *ps) {
445 76 : Icmpv6VrfState *state = ps->vrf_state();
446 76 : int prev = ps->refcount_.fetch_sub(1);
447 76 : if (prev == 1) {
448 76 : state->Erase(ps->ip());
449 76 : delete ps;
450 : }
451 76 : }
452 :
453 76 : Icmpv6PathPreferenceState::Icmpv6PathPreferenceState(
454 : Icmpv6VrfState *vrf_state, uint32_t vrf_id,
455 76 : IpAddress ip, uint8_t plen) :
456 76 : vrf_state_(vrf_state), ns_req_timer_(NULL), vrf_id_(vrf_id), vm_ip_(ip),
457 76 : plen_(plen), svc_ip_(Ip6Address()) {
458 76 : refcount_ = 0;
459 76 : }
460 :
461 76 : Icmpv6PathPreferenceState::~Icmpv6PathPreferenceState() {
462 76 : if (ns_req_timer_) {
463 0 : ns_req_timer_->Cancel();
464 0 : TimerManager::DeleteTimer(ns_req_timer_);
465 : }
466 76 : assert(refcount_ == 0);
467 76 : }
468 :
469 0 : bool Icmpv6PathPreferenceState::SendNeighborSolicit(WaitForTrafficIntfMap
470 : &wait_for_traffic_map,
471 : NDTransmittedIntfMap
472 : &nd_transmitted_map) {
473 0 : bool ret = false;
474 0 : boost::shared_ptr<PktInfo> pkt(new PktInfo(vrf_state_->agent(),
475 : ICMP_PKT_SIZE,
476 0 : PktHandler::ICMPV6, 0));
477 0 : Icmpv6Handler handler(vrf_state_->agent(), pkt,
478 0 : *(vrf_state_->agent()->event_manager()->io_service()));
479 :
480 0 : WaitForTrafficIntfMap::iterator it = wait_for_traffic_map.begin();
481 0 : for (;it != wait_for_traffic_map.end(); it++) {
482 :
483 : VmInterface *vm_intf = static_cast<VmInterface *>(
484 0 : vrf_state_->agent()->interface_table()->FindInterface(it->first));
485 0 : if (!vm_intf) {
486 0 : continue;
487 : }
488 0 : InterfaceIcmpv6PathPreferenceInfo &data = it->second;
489 0 : bool inserted = nd_transmitted_map.insert(it->first).second;
490 0 : ++data.ns_retry_count;
491 0 : if (inserted == false) {
492 0 : continue;
493 : }
494 :
495 0 : MacAddress mil_mac = vrf_state_->agent()->mac_learning_proto()->
496 : GetMacIpLearningTable()->GetPairedMacAddress(
497 0 : vm_intf->vrf_id(), ip());
498 0 : if (mil_mac != MacAddress()) {
499 0 : ++data.ns_try_count;
500 0 : if (data.ns_try_count == kNSTryCount) {
501 0 : IpAddress ip = vm_ip_;
502 0 : MacAddress mac = mil_mac;
503 0 : vrf_state_->agent()->mac_learning_proto()->
504 0 : GetMacIpLearningTable()->MacIpEntryUnreachable(
505 : vm_intf->vrf_id(), ip, mac);
506 0 : return true;
507 : }
508 : }
509 :
510 0 : Ip6Address src_addr;
511 0 : if (svc_ip_.is_unspecified() == false && svc_ip_.is_v6())
512 0 : src_addr = svc_ip_.to_v6();
513 0 : handler.SendNeighborSolicit(src_addr, vm_ip_.to_v6(), vm_intf, vrf_id_);
514 :
515 0 : vrf_state_->icmp_proto()->IncrementStatsNeighborSolicit(vm_intf);
516 0 : ++data.ns_send_count;
517 :
518 : // reduce the frequency of NS requests after some tries
519 0 : if (data.ns_send_count >= kMaxRetry) {
520 : // change frequency only if not in gateway mode with remote VMIs and
521 : // learnt mac is not present
522 0 : if (vm_intf->vmi_type() != VmInterface::REMOTE_VM
523 0 : && mil_mac == MacAddress()) {
524 0 : ns_req_timer_->Reschedule(kTimeout * kTimeoutMultiplier);
525 : }
526 : }
527 :
528 0 : ret = true;
529 : }
530 0 : return ret;
531 0 : }
532 :
533 0 : bool Icmpv6PathPreferenceState::SendNeighborSolicit() {
534 0 : if (l3_wait_for_traffic_map_.size() == 0 &&
535 0 : evpn_wait_for_traffic_map_.size() == 0) {
536 0 : return false;
537 : }
538 :
539 0 : bool ret = false;
540 0 : NDTransmittedIntfMap nd_transmitted_map;
541 0 : if (SendNeighborSolicit(l3_wait_for_traffic_map_, nd_transmitted_map)) {
542 0 : ret = true;
543 : }
544 :
545 0 : if (SendNeighborSolicit(evpn_wait_for_traffic_map_, nd_transmitted_map)) {
546 0 : ret = true;
547 : }
548 0 : return ret;
549 0 : }
550 :
551 0 : void Icmpv6PathPreferenceState::StartTimer() {
552 0 : if (ns_req_timer_ == NULL) {
553 0 : ns_req_timer_ = TimerManager::CreateTimer(
554 0 : *(vrf_state_->agent()->event_manager()->io_service()),
555 : "Neighbor Solicit Request timer for VM",
556 : TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
557 : PktHandler::ICMPV6);
558 : }
559 0 : ns_req_timer_->Start(kTimeout,
560 : boost::bind(&Icmpv6PathPreferenceState::
561 : SendNeighborSolicit,
562 : this));
563 0 : }
564 :
565 134 : Icmpv6RouteState::Icmpv6RouteState(Icmpv6VrfState *vrf_state,
566 : uint32_t vrf_id, IpAddress ip,
567 134 : uint8_t plen) {
568 134 : if (plen == Address::kMaxV6PrefixLen) {
569 76 : icmpv6_path_preference_state_ = vrf_state->Locate(ip);
570 : }
571 134 : }
572 :
573 268 : Icmpv6RouteState::~Icmpv6RouteState() {
574 134 : icmpv6_path_preference_state_.reset(NULL);
575 268 : }
576 :
577 226 : void Icmpv6RouteState::SendNeighborSolicitForAllIntf(const AgentRoute *route) {
578 226 : if (icmpv6_path_preference_state_.get()) {
579 108 : icmpv6_path_preference_state_->SendNeighborSolicitForAllIntf(route);
580 : }
581 226 : }
582 :
583 : //Send Neighbor Solicit request on interface in Active-BackUp mode
584 : //So that preference of route can be incremented if the VM replies with
585 : //Neighbor Advertisement
586 108 : void Icmpv6PathPreferenceState::SendNeighborSolicitForAllIntf
587 : (const AgentRoute *route) {
588 :
589 108 : WaitForTrafficIntfMap wait_for_traffic_map = evpn_wait_for_traffic_map_;
590 108 : if (dynamic_cast<const InetUnicastRouteEntry *>(route)) {
591 108 : wait_for_traffic_map = l3_wait_for_traffic_map_;
592 : }
593 :
594 108 : WaitForTrafficIntfMap new_wait_for_traffic_map;
595 216 : for (Route::PathList::const_iterator it = route->GetPathList().begin();
596 432 : it != route->GetPathList().end(); it++) {
597 108 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
598 216 : if (path->peer() &&
599 108 : path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
600 0 : const NextHop *nh = path->ComputeNextHop(vrf_state_->agent());
601 0 : if (nh->GetType() != NextHop::INTERFACE) {
602 0 : continue;
603 : }
604 :
605 0 : const InterfaceNH *intf_nh =
606 : static_cast<const InterfaceNH *>(nh);
607 : const Interface *intf =
608 0 : static_cast<const Interface *>(intf_nh->GetInterface());
609 0 : if (intf->type() != Interface::VM_INTERFACE) {
610 : //Ignore non vm interface nexthop
611 0 : continue;
612 : }
613 0 : if (dynamic_cast<const InetUnicastRouteEntry *>(route)) {
614 0 : const VmInterface *vm_intf =
615 : static_cast<const VmInterface *>(intf);
616 0 : if (vm_intf->primary_ip6_addr().is_unspecified() == false) {
617 0 : svc_ip_ = vm_intf->GetServiceIp(vm_intf->primary_ip6_addr());
618 : }
619 : }
620 :
621 0 : if (path->path_preference().IsDependentRt() == true) {
622 0 : continue;
623 : }
624 :
625 0 : uint32_t intf_id = intf->id();
626 : WaitForTrafficIntfMap::const_iterator wait_for_traffic_it =
627 0 : wait_for_traffic_map.find(intf_id);
628 0 : if (wait_for_traffic_it == wait_for_traffic_map.end()) {
629 0 : InterfaceIcmpv6PathPreferenceInfo data;
630 0 : new_wait_for_traffic_map.insert(std::make_pair(intf_id, data));
631 : } else {
632 0 : new_wait_for_traffic_map.insert(std::make_pair(intf_id,
633 0 : wait_for_traffic_it->second));
634 : }
635 : }
636 : }
637 :
638 :
639 108 : if (dynamic_cast<const InetUnicastRouteEntry *>(route)) {
640 108 : l3_wait_for_traffic_map_ = new_wait_for_traffic_map;
641 : } else {
642 0 : evpn_wait_for_traffic_map_ = new_wait_for_traffic_map;
643 : }
644 108 : if (new_wait_for_traffic_map.size() > 0) {
645 0 : SendNeighborSolicit();
646 0 : StartTimer();
647 : }
648 108 : }
649 :
650 0 : Icmpv6Proto::Icmpv6Stats *Icmpv6Proto::VmiToIcmpv6Stats(VmInterface *i) {
651 0 : VmInterfaceMap::iterator it = vm_interfaces_.find(i);
652 0 : if (it == vm_interfaces_.end()) {
653 0 : return NULL;
654 : }
655 0 : return &it->second;
656 : }
657 :
658 0 : void Icmpv6Proto::IncrementStatsRouterSolicit(VmInterface *vmi) {
659 0 : stats_.icmpv6_router_solicit_++;
660 0 : Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
661 0 : if (stats) {
662 0 : stats->icmpv6_router_solicit_++;
663 : }
664 0 : }
665 :
666 0 : void Icmpv6Proto::IncrementStatsRouterAdvert(VmInterface *vmi) {
667 0 : stats_.icmpv6_router_advert_++;
668 0 : Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
669 0 : if (stats) {
670 0 : stats->icmpv6_router_advert_++;
671 : }
672 0 : }
673 :
674 0 : void Icmpv6Proto::IncrementStatsPingRequest(VmInterface *vmi) {
675 0 : stats_.icmpv6_ping_request_++;
676 0 : Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
677 0 : if (stats) {
678 0 : stats->icmpv6_ping_request_++;
679 : }
680 0 : }
681 :
682 0 : void Icmpv6Proto::IncrementStatsPingResponse(VmInterface *vmi) {
683 0 : stats_.icmpv6_ping_response_++;
684 0 : Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
685 0 : if (stats) {
686 0 : stats->icmpv6_ping_response_++;
687 : }
688 0 : }
689 :
690 0 : void Icmpv6Proto::IncrementStatsNeighborSolicit(VmInterface *vmi) {
691 0 : stats_.icmpv6_neighbor_solicit_++;
692 0 : Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
693 0 : if (stats) {
694 0 : stats->icmpv6_neighbor_solicit_++;
695 : }
696 0 : }
697 :
698 0 : void Icmpv6Proto::IncrementStatsNeighborSolicited(VmInterface *vmi) {
699 0 : stats_.icmpv6_neighbor_solicited_++;
700 0 : Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
701 0 : if (stats) {
702 0 : stats->icmpv6_neighbor_solicited_++;
703 : }
704 0 : }
705 :
706 0 : void Icmpv6Proto::IncrementStatsNeighborAdvertSolicited(VmInterface *vmi) {
707 0 : stats_.icmpv6_neighbor_advert_solicited_++;
708 0 : Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
709 0 : if (stats) {
710 0 : stats->icmpv6_neighbor_advert_solicited_++;
711 : }
712 0 : }
713 :
714 0 : void Icmpv6Proto::IncrementStatsNeighborAdvertUnSolicited(VmInterface *vmi) {
715 0 : stats_.icmpv6_neighbor_advert_unsolicited_++;
716 0 : Icmpv6Stats *stats = VmiToIcmpv6Stats(vmi);
717 0 : if (stats) {
718 0 : stats->icmpv6_neighbor_advert_unsolicited_++;
719 : }
720 0 : }
721 :
722 0 : NdpEntry* Icmpv6Proto::FindUnsolNaEntry(NdpKey &key) {
723 0 : Icmpv6Proto::UnsolNaIterator iter = unsol_na_cache_.find(key);
724 0 : if (iter == unsol_na_cache_.end()) {
725 0 : return NULL;
726 : }
727 0 : return *iter->second.begin();
728 : }
729 :
730 0 : void Icmpv6Proto::AddUnsolNaEntry(NdpKey &key) {
731 0 : NdpEntrySet empty_set;
732 0 : unsol_na_cache_.insert(UnsolNaCachePair(key, empty_set));
733 0 : }
734 :
735 0 : void Icmpv6Proto::DeleteUnsolNaEntry(NdpEntry *entry) {
736 0 : if (!entry)
737 0 : return ;
738 :
739 0 : Icmpv6Proto::UnsolNaIterator iter = unsol_na_cache_.find(entry->key());
740 0 : if (iter == unsol_na_cache_.end()) {
741 0 : return;
742 : }
743 :
744 0 : iter->second.erase(entry);
745 0 : delete entry;
746 0 : if (iter->second.empty()) {
747 0 : unsol_na_cache_.erase(iter);
748 : }
749 : }
750 :
751 : NdpEntry *
752 0 : Icmpv6Proto::UnsolNaEntry(const NdpKey &key, const Interface *intf) {
753 0 : Icmpv6Proto::UnsolNaIterator it = unsol_na_cache_.find(key);
754 0 : if (it == unsol_na_cache_.end())
755 0 : return NULL;
756 :
757 0 : for (NdpEntrySet::iterator sit = it->second.begin();
758 0 : sit != it->second.end(); sit++) {
759 0 : NdpEntry *entry = *sit;
760 0 : if (entry->get_interface() == intf)
761 0 : return *sit;
762 : }
763 :
764 0 : return NULL;
765 : }
766 :
767 : Icmpv6Proto::UnsolNaIterator
768 0 : Icmpv6Proto::UnsolNaEntryIterator(const NdpKey &key, bool *key_valid) {
769 0 : Icmpv6Proto::UnsolNaIterator it = unsol_na_cache_.find(key);
770 0 : if (it == unsol_na_cache_.end())
771 0 : return it;
772 0 : const VrfEntry *vrf = key.vrf;
773 0 : if (!vrf)
774 0 : return it;
775 : const Icmpv6VrfState *state = static_cast<const Icmpv6VrfState *>
776 0 : (vrf->GetState(vrf->get_table_partition()->parent(),
777 : vrf_table_listener_id_));
778 : // If VRF is delete marked, do not add Ndp entries to cache
779 0 : if (state == NULL || state->deleted() == true)
780 0 : return it;
781 0 : *key_valid = true;
782 0 : return it;
783 : }
784 :
785 0 : bool Icmpv6Proto::AddNdpEntry(NdpEntry *entry) {
786 0 : const VrfEntry *vrf = entry->key().vrf;
787 : const Icmpv6VrfState *state = static_cast<const Icmpv6VrfState *>
788 0 : (vrf->GetState(vrf->get_table_partition()->parent(),
789 : vrf_table_listener_id_));
790 : // If VRF is delete marked, do not add Ndp entries to cache
791 0 : if (state == NULL || state->deleted() == true)
792 0 : return false;
793 :
794 0 : bool ret = ndp_cache_.insert(NdpCachePair(entry->key(), entry)).second;
795 0 : uint32_t intf_id = entry->get_interface()->id();
796 0 : InterfaceNdpMap::iterator it = interface_ndp_map_.find(intf_id);
797 0 : if (it == interface_ndp_map_.end()) {
798 0 : InterfaceNdpInfo intf_entry;
799 0 : intf_entry.ndp_key_list.insert(entry->key());
800 0 : interface_ndp_map_.insert(InterfaceNdpPair(intf_id, intf_entry));
801 0 : } else {
802 0 : InterfaceNdpInfo &intf_entry = it->second;
803 0 : NdpKeySet::iterator key_it = intf_entry.ndp_key_list.find(entry->key());
804 0 : if (key_it == intf_entry.ndp_key_list.end()) {
805 0 : intf_entry.ndp_key_list.insert(entry->key());
806 : }
807 : }
808 0 : return ret;
809 : }
810 :
811 0 : bool Icmpv6Proto::DeleteNdpEntry(NdpEntry *entry) {
812 0 : if (!entry)
813 0 : return false;
814 :
815 0 : Icmpv6Proto::NdpIterator iter = ndp_cache_.find(entry->key());
816 0 : if (iter == ndp_cache_.end()) {
817 0 : return false;
818 : }
819 :
820 0 : DeleteNdpEntry(iter);
821 0 : return true;
822 : }
823 :
824 : Icmpv6Proto::NdpIterator
825 0 : Icmpv6Proto::DeleteNdpEntry(Icmpv6Proto::NdpIterator iter) {
826 0 : NdpEntry *entry = iter->second;
827 0 : ndp_cache_.erase(iter++);
828 0 : delete entry;
829 0 : return iter;
830 : }
831 :
832 0 : NdpEntry *Icmpv6Proto::FindNdpEntry(const NdpKey &key) {
833 0 : NdpIterator it = ndp_cache_.find(key);
834 0 : if (it == ndp_cache_.end())
835 0 : return NULL;
836 0 : return it->second;
837 : }
|