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