OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ndp_entry.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "base/os.h"
6 #include <boost/statechart/custom_reaction.hpp>
7 #include <boost/statechart/state.hpp>
8 #include <boost/statechart/state_machine.hpp>
9 #include <boost/statechart/transition.hpp>
10 
11 #include "services/ndp_entry.h"
12 #include "services/services_types.h"
13 #include "services/icmpv6_proto.h"
14 //#include "services/services_sandesh.h"
15 #include "services/services_init.h"
16 #include "oper/route_common.h"
17 
18 using std::ostream;
19 using std::ostringstream;
20 using std::string;
21 
22 namespace mpl = boost::mpl;
23 namespace sc = boost::statechart;
24 
25 const int NdpEntry::kMaxRetries = 3;
26 const int NdpEntry::kMaxUnicastRetries = 3;
27 
28 #define SM_LOG(level, _Msg) \
29  do { \
30  ostringstream out; \
31  out << _Msg; \
32  if (LoggingDisabled()) break; \
33  ICMPV6_TRACE(Trace, _Msg); \
34  } while (false)
35 
36 namespace fsm {
37 
38 struct EvTestStateChange : sc::event<EvTestStateChange> {
39  EvTestStateChange(NdpEntry::State state, int retry) :state_(state),
40  retry_(retry) {}
41  static const char *Name() {
42  return "EvTestStateChange";
43  }
44  bool validate(NdpEntry *state_machine) const {
45  return true;
46  }
47 
49  int retry_;
50 };
51 
52 struct EvPktOut : sc::event<EvPktOut> {
54  }
55  static const char *Name() {
56  return "EvPktOut";
57  }
58  bool validate(NdpEntry *state_machine) const {
59  return true;
60  }
61 };
62 
63 struct EvDelayTimerExpired : sc::event<EvDelayTimerExpired> {
64  explicit EvDelayTimerExpired() {
65  }
66  static const char *Name() {
67  return "EvDelayTimerExpired";
68  }
69  bool validate(NdpEntry *state_machine) const {
70  return true;
71  }
72 };
73 
74 struct EvRetransmitTimerExpired : sc::event<EvRetransmitTimerExpired> {
76  }
77  static const char *Name() {
78  return "EvRetransmitTimerExpired";
79  }
80  bool validate(NdpEntry *state_machine) const {
81  return true;
82  }
83 };
84 
85 struct EvReachableTimerExpired : sc::event<EvReachableTimerExpired> {
87  }
88  static const char *Name() {
89  return "EvReachableTimerExpired";
90  }
91  bool validate(NdpEntry *state_machine) const {
92  return true;
93  }
94 };
95 
96 struct EvNsIn : sc::event<EvNsIn> {
97  explicit EvNsIn(nd_neighbor_solicit *ns, MacAddress mac) :
98  mac_(mac), ns_(ns) {
99  }
100  static const char *Name() {
101  return "EvNsIn";
102  }
103  bool validate(NdpEntry *state_machine) const {
104  return true;
105  }
106 
108  nd_neighbor_solicit *ns_;
109 };
110 
111 struct EvSolNaIn : sc::event<EvSolNaIn> {
112  explicit EvSolNaIn(nd_neighbor_advert *na, MacAddress mac) :
113  mac_(mac), na_(na) {
114  }
115  static const char *Name() {
116  return "EvSolNaIn";
117  }
118  bool validate(NdpEntry *state_machine) const {
119  return true;
120  }
121 
123  nd_neighbor_advert *na_;
124 };
125 
126 struct EvUnsolNaIn : sc::event<EvUnsolNaIn> {
127  explicit EvUnsolNaIn(nd_neighbor_advert *na, MacAddress mac) :
128  mac_(mac), na_(na) {
129  }
130  static const char *Name() {
131  return "EvUnsolNaIn";
132  }
133  bool validate(NdpEntry *state_machine) const {
134  return true;
135  }
136 
138  nd_neighbor_advert *na_;
139 };
140 
141 // States for the NDP state machine.
142 struct NoState;
143 struct Incomplete;
144 struct Reachable;
145 struct Stale;
146 struct Delay;
147 struct Probe;
148 
149 //
150 //
151 struct NoState : sc::state<NoState, NdpEntry> {
152  typedef mpl::list<
153  sc::custom_reaction<EvNsIn>,
154  sc::custom_reaction<EvPktOut>,
155  sc::custom_reaction<EvTestStateChange>
157 
158  explicit NoState(my_context ctx) : my_base(ctx) {
159  NdpEntry *state_machine = &context<NdpEntry>();
160  state_machine->set_state(NdpEntry::NOSTATE);
161  }
162 
164  }
165 
166  // copy the mac and move to stale
167  sc::result react(const EvNsIn &event) {
168  NdpEntry *state_machine = &context<NdpEntry>();
169  state_machine->set_mac(event.mac_);
170  return transit<Stale>();
171  }
172 
173  // Send multicast NS probe and start retransmit timer
174  sc::result react(const EvPktOut &event) {
175  NdpEntry *state_machine = &context<NdpEntry>();
176  // In UTs, ndp_entry may not be there
177  if (state_machine->get_interface())
178  state_machine->SendNeighborSolicit();
179  state_machine->StartRetransmitTimer();
180  return transit<Incomplete>();
181  }
182 
183  sc::result react(const EvTestStateChange &event) {
184  NdpEntry::State state = event.state_;
185  NdpEntry *state_machine = &context<NdpEntry>();
186  state_machine->set_state(state);
187  state_machine->set_mac(MacAddress());
188  switch (state) {
189  case NdpEntry::NOSTATE: return transit<NoState>();
190  case NdpEntry::INCOMPLETE: return transit<Incomplete>();
191  case NdpEntry::REACHABLE: return transit<Reachable>();
192  case NdpEntry::STALE: return transit<Stale>();
193  case NdpEntry::DELAY: return transit<Delay>();
194  case NdpEntry::PROBE: return transit<Probe>();
195  default: return discard_event();
196  }
197  }
198 };
199 
200 //
201 //
202 struct Incomplete : sc::state<Incomplete, NdpEntry> {
203  typedef mpl::list<
204  sc::custom_reaction<EvNsIn>,
205  sc::custom_reaction<EvUnsolNaIn>,
206  sc::custom_reaction<EvSolNaIn>,
207  sc::custom_reaction<EvRetransmitTimerExpired>,
208  sc::custom_reaction<EvTestStateChange>
210 
211  explicit Incomplete(my_context ctx) : my_base(ctx) {
212  NdpEntry *state_machine = &context<NdpEntry>();
213  state_machine->retry_count_clear();
214  state_machine->set_state(NdpEntry::INCOMPLETE);
215  }
216 
218  }
219 
220  // If different mac then move to stale
221  sc::result react(const EvNsIn &event) {
222  NdpEntry *state_machine = &context<NdpEntry>();
223  if (state_machine->mac() != event.mac_) {
224  state_machine->mac() = event.mac_;
225  return transit<Stale>();
226  }
227  return discard_event();
228  }
229 
230  // move to reachable
231  sc::result react(const EvSolNaIn &event) {
232  NdpEntry *state_machine = &context<NdpEntry>();
233  if (state_machine->mac() != event.mac_) {
234  state_machine->mac() = event.mac_;
235  }
236  return transit<Reachable>();
237  }
238 
239  // move to stale
240  sc::result react(const EvUnsolNaIn &event) {
241  NdpEntry *state_machine = &context<NdpEntry>();
242  state_machine->mac() = event.mac_;
243  return transit<Stale>();
244  }
245 
246 
247  // If less than N retransmissions then retransmit and restart timer
248  // Else discard entry and send icmp error
249  sc::result react(const EvRetransmitTimerExpired &event) {
250  NdpEntry *state_machine = &context<NdpEntry>();
251  if (state_machine->retry_count() < NdpEntry::kMaxRetries) {
252  // In UTs, ndp_entry may not be there
253  if (state_machine->get_interface())
254  state_machine->SendNeighborSolicit();
255  state_machine->StartRetransmitTimer();
256  } else {
257  state_machine->retry_count_clear();
258  if (state_machine->DeleteNdpRoute())
259  return discard_event();
260  }
261  return discard_event();
262  }
263 
264  sc::result react(const EvTestStateChange &event) {
265  NdpEntry::State state = event.state_;
266  NdpEntry *state_machine = &context<NdpEntry>();
267  state_machine->set_state(state);
268  state_machine->set_mac(MacAddress());
269  switch (state) {
270  case NdpEntry::NOSTATE: return transit<NoState>();
271  case NdpEntry::INCOMPLETE: return transit<Incomplete>();
272  case NdpEntry::REACHABLE: return transit<Reachable>();
273  case NdpEntry::STALE: return transit<Stale>();
274  case NdpEntry::DELAY: return transit<Delay>();
275  case NdpEntry::PROBE: return transit<Probe>();
276  default: return discard_event();
277  }
278  }
279 };
280 
281 struct Reachable : sc::state<Reachable, NdpEntry> {
282  typedef mpl::list<
283  sc::custom_reaction<EvNsIn>,
284  sc::custom_reaction<EvUnsolNaIn>,
285  sc::custom_reaction<EvSolNaIn>,
286  sc::custom_reaction<EvReachableTimerExpired>,
287  sc::custom_reaction<EvTestStateChange>
289 
290  explicit Reachable(my_context ctx) : my_base(ctx) {
291  NdpEntry *state_machine = &context<NdpEntry>();
292  state_machine->set_state(NdpEntry::REACHABLE);
293  state_machine->StartReachableTimer();
294  }
295 
297  }
298 
299  // If different mac then move to stale
300  sc::result react(const EvNsIn &event) {
301  NdpEntry *state_machine = &context<NdpEntry>();
302  if (state_machine->mac() != event.mac_) {
303  state_machine->mac() = event.mac_;
304  return transit<Stale>();
305  }
306  return discard_event();
307  }
308 
309 
310  // If different mac then move to stale else unchanged
311  sc::result react(const EvUnsolNaIn &event) {
312  NdpEntry *state_machine = &context<NdpEntry>();
313  if (event.na_->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE) {
314  if (state_machine->mac() != event.mac_) {
315  state_machine->set_mac(event.mac_);
316  return transit<Stale>();
317  }
318  }
319  return discard_event();
320  }
321 
322 
323  // If non override and diff mac then move to stale
324  // if override then update mac
325  sc::result react(const EvSolNaIn &event) {
326  NdpEntry *state_machine = &context<NdpEntry>();
327  if (!(event.na_->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE)) {
328  if (state_machine->mac() != event.mac_) {
329  return transit<Stale>();
330  }
331  } else {
332  if (state_machine->mac() != event.mac_) {
333  state_machine->set_mac(event.mac_);
334  }
335  }
336  return discard_event();
337  }
338 
339  // move to stale
340  sc::result react(const EvReachableTimerExpired &event) {
341  return transit<Stale>();
342  }
343 
344  sc::result react(const EvTestStateChange &event) {
345  NdpEntry::State state = event.state_;
346  NdpEntry *state_machine = &context<NdpEntry>();
347  state_machine->set_state(state);
348  state_machine->set_mac(MacAddress());
349  switch (state) {
350  case NdpEntry::NOSTATE: return transit<NoState>();
351  case NdpEntry::INCOMPLETE: return transit<Incomplete>();
352  case NdpEntry::REACHABLE: return transit<Reachable>();
353  case NdpEntry::STALE: return transit<Stale>();
354  case NdpEntry::DELAY: return transit<Delay>();
355  case NdpEntry::PROBE: return transit<Probe>();
356  default: return discard_event();
357  }
358  }
359 };
360 
361 //
362 //
363 struct Stale : sc::state<Stale, NdpEntry> {
364  typedef mpl::list<
365  sc::custom_reaction<EvNsIn>,
366  sc::custom_reaction<EvUnsolNaIn>,
367  sc::custom_reaction<EvSolNaIn>,
368  sc::custom_reaction<EvPktOut>,
369  sc::custom_reaction<EvTestStateChange>
371 
372  // Send a KEEPALIVE and start the keepalive timer on the peer. Also start
373  // the hold timer based on the negotiated hold time value.
374  explicit Stale(my_context ctx) : my_base(ctx) {
375  NdpEntry *state_machine = &context<NdpEntry>();
376  state_machine->set_state(NdpEntry::STALE);
377  }
378 
379  // Cancel the hold timer. If we go to Established, the timer will get
380  // started again from the constructor for that state.
381  ~Stale() {
382  }
383 
384  // If different mac then move to stale
385  sc::result react(const EvNsIn &event) {
386  NdpEntry *state_machine = &context<NdpEntry>();
387  if (state_machine->mac() != event.mac_) {
388  state_machine->set_mac(event.mac_);
389  }
390  return discard_event();
391  }
392 
393  // If different mac then move to stale else unchanged
394  sc::result react(const EvUnsolNaIn &event) {
395  NdpEntry *state_machine = &context<NdpEntry>();
396  if (event.na_->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE) {
397  if (state_machine->mac() != event.mac_) {
398  state_machine->set_mac(event.mac_);
399  return transit<Stale>();
400  }
401  }
402  return discard_event();
403  }
404 
405 
406  // If same mac then move to reachable else unchanged
407  sc::result react(const EvSolNaIn &event) {
408  NdpEntry *state_machine = &context<NdpEntry>();
409  if (event.na_->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE) {
410  if (state_machine->mac() != event.mac_) {
411  state_machine->set_mac(event.mac_);
412  }
413  return transit<Reachable>();
414  }
415  return discard_event();
416  }
417 
418  // start delay timer and move to delay
419  sc::result react(const EvPktOut &event) {
420  NdpEntry *state_machine = &context<NdpEntry>();
421  state_machine->StartDelayTimer();
422  return transit<Delay>();
423  }
424 
425  sc::result react(const EvTestStateChange &event) {
426  NdpEntry::State state = event.state_;
427  NdpEntry *state_machine = &context<NdpEntry>();
428  state_machine->set_state(state);
429  state_machine->set_mac(MacAddress());
430  state_machine->retry_count_set(event.retry_);
431  switch (state) {
432  case NdpEntry::NOSTATE: return transit<NoState>();
433  case NdpEntry::INCOMPLETE: return transit<Incomplete>();
434  case NdpEntry::REACHABLE: return transit<Reachable>();
435  case NdpEntry::STALE: return transit<Stale>();
436  case NdpEntry::DELAY: return transit<Delay>();
437  case NdpEntry::PROBE: return transit<Probe>();
438  default: return discard_event();
439  }
440  }
441 };
442 
443 //
444 // Established is the final state for an operation peer.
445 //
446 struct Delay : sc::state<Delay, NdpEntry> {
447  typedef mpl::list<
448  sc::custom_reaction<EvNsIn>,
449  sc::custom_reaction<EvUnsolNaIn>,
450  sc::custom_reaction<EvSolNaIn>,
451  sc::custom_reaction<EvDelayTimerExpired>,
452  sc::custom_reaction<EvTestStateChange>
454 
455  explicit Delay(my_context ctx) : my_base(ctx) {
456  NdpEntry *state_machine = &context<NdpEntry>();
457  state_machine->retry_count_clear();
458  state_machine->set_state(NdpEntry::DELAY);
459  }
460 
461  ~Delay() {
462  }
463 
464  // If different mac then move to stale
465  sc::result react(const EvNsIn &event) {
466  NdpEntry *state_machine = &context<NdpEntry>();
467  if (state_machine->mac() != event.mac_) {
468  state_machine->set_mac(event.mac_);
469  return transit<Stale>();
470  }
471  return discard_event();
472  }
473 
474 
475  // If different mac then move to stale else unchanged
476  sc::result react(const EvUnsolNaIn &event) {
477  NdpEntry *state_machine = &context<NdpEntry>();
478  if (event.na_->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE) {
479  if (state_machine->mac() != event.mac_) {
480  state_machine->set_mac(event.mac_);
481  return transit<Stale>();
482  }
483  }
484  return discard_event();
485  }
486 
487 
488  // If same mac then move to reachable else unchanged
489  sc::result react(const EvSolNaIn &event) {
490  NdpEntry *state_machine = &context<NdpEntry>();
491  if (event.na_->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE) {
492  if (state_machine->mac() != event.mac_) {
493  state_machine->set_mac(event.mac_);
494  }
495  return transit<Reachable>();
496  }
497  return discard_event();
498  }
499 
500  // Send unicast NS probe and start retransmit timer
501  sc::result react(const EvDelayTimerExpired &event) {
502  NdpEntry *state_machine = &context<NdpEntry>();
503  // In UTs, ndp_entry may not be there
504  if (state_machine->get_interface())
505  state_machine->SendNeighborSolicit();
506  state_machine->StartRetransmitTimer();
507  return transit<Probe>();
508  }
509 
510  sc::result react(const EvTestStateChange &event) {
511  NdpEntry::State state = event.state_;
512  NdpEntry *state_machine = &context<NdpEntry>();
513  state_machine->set_state(state);
514  state_machine->set_mac(MacAddress());
515  switch (state) {
516  case NdpEntry::NOSTATE: return transit<NoState>();
517  case NdpEntry::INCOMPLETE: return transit<Incomplete>();
518  case NdpEntry::REACHABLE: return transit<Reachable>();
519  case NdpEntry::STALE: return transit<Stale>();
520  case NdpEntry::DELAY: return transit<Delay>();
521  case NdpEntry::PROBE: return transit<Probe>();
522  default: return discard_event();
523  }
524  }
525 };
526 
527 //
528 // Established is the final state for an operation peer.
529 //
530 struct Probe : sc::state<Probe, NdpEntry> {
531  typedef mpl::list<
532  sc::custom_reaction<EvNsIn>,
533  sc::custom_reaction<EvUnsolNaIn>,
534  sc::custom_reaction<EvSolNaIn>,
535  sc::custom_reaction<EvRetransmitTimerExpired>,
536  sc::custom_reaction<EvTestStateChange>
538 
539  explicit Probe(my_context ctx) : my_base(ctx) {
540  NdpEntry *state_machine = &context<NdpEntry>();
541  state_machine->retry_count_clear();
542  state_machine->set_state(NdpEntry::PROBE);
543  }
544 
545  ~Probe() {
546  }
547 
548  // If different mac then move to stale
549  sc::result react(const EvNsIn &event) {
550  NdpEntry *state_machine = &context<NdpEntry>();
551  if (state_machine->mac() != event.mac_) {
552  state_machine->set_mac(event.mac_);
553  return transit<Stale>();
554  }
555  return discard_event();
556  }
557 
558 
559  // If different mac then move to stale else unchanged
560  sc::result react(const EvUnsolNaIn &event) {
561  NdpEntry *state_machine = &context<NdpEntry>();
562  if (event.na_->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE) {
563  if (state_machine->mac() != event.mac_) {
564  state_machine->set_mac(event.mac_);
565  return transit<Stale>();
566  }
567  }
568  return discard_event();
569  }
570 
571 
572  // If same mac then move to reachable else unchanged
573  sc::result react(const EvSolNaIn &event) {
574  if (event.na_->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE) {
575  NdpEntry *state_machine = &context<NdpEntry>();
576  if (state_machine->mac() != event.mac_) {
577  state_machine->set_mac(event.mac_);
578  }
579  return transit<Reachable>();
580  }
581  return discard_event();
582  }
583 
584  // If more than N then stale
585  sc::result react(const EvRetransmitTimerExpired &event) {
586  NdpEntry *state_machine = &context<NdpEntry>();
587  if (state_machine->retry_count() < NdpEntry::kMaxUnicastRetries) {
588  if (state_machine->get_interface())
589  state_machine->SendNeighborSolicit();
590  state_machine->StartRetransmitTimer();
591  return discard_event();
592  } else {
593  state_machine->retry_count_clear();
594  if (state_machine->DeleteNdpRoute())
595  return discard_event();
596  }
597  return discard_event();
598  }
599 
600  sc::result react(const EvTestStateChange &event) {
601  NdpEntry::State state = event.state_;
602  NdpEntry *state_machine = &context<NdpEntry>();
603  state_machine->set_state(state);
604  state_machine->set_mac(MacAddress());
605  switch (state) {
606  case NdpEntry::NOSTATE: return transit<NoState>();
607  case NdpEntry::INCOMPLETE: return transit<Incomplete>();
608  case NdpEntry::REACHABLE: return transit<Reachable>();
609  case NdpEntry::STALE: return transit<Stale>();
610  case NdpEntry::DELAY: return transit<Delay>();
611  case NdpEntry::PROBE: return transit<Probe>();
612  default: return discard_event();
613  }
614  }
615 };
616 
617 } // namespace fsm
618 
619 NdpEntry::NdpEntry(boost::asio::io_context &io, Icmpv6Handler *handler,
620  NdpKey &key, const VrfEntry *vrf, const Interface *itf)
621  : work_queue_(TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
622  NULL,
623  boost::bind(&NdpEntry::DequeueEvent, this, _1)),
624  delay_timer_(TimerManager::CreateTimer(
625  io, "Delay timer",
626  TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
627  PktHandler::ICMPV6)),
628  retransmit_timer_(TimerManager::CreateTimer(
629  io, "Retransmit timer",
630  TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
631  PktHandler::ICMPV6)),
632  reachable_timer_(TimerManager::CreateTimer(
633  io, "Reachable timer",
634  TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
635  PktHandler::ICMPV6)),
636  retransmit_time_(1000),
637  delay_time_(5000),
638  reachable_time_(30000),
639  retry_count_(0),
640  deleted_(false),
641  state_(NOSTATE),
642  last_state_(NOSTATE),
643  io_(io), key_(key), nh_vrf_(vrf), handler_(handler), interface_(itf) {
644  initiate();
645 }
646 
649  terminate();
650  DeleteAllTimers();
651  if (handler_.get())
652  handler_.reset(NULL);
653 }
654 
659 }
660 
662  if (delay_time_ <= 0)
663  return;
664 
665  delay_timer_->Cancel();
667  boost::bind(&NdpEntry::DelayTimerExpired, this), NULL);
668 }
669 
671  if (reachable_time_ <= 0)
672  return;
673 
676  boost::bind(&NdpEntry::ReachableTimerExpired, this), NULL);
677 }
678 
681  return false;
682 }
683 
685  if (retransmit_time_ <= 0)
686  return;
687 
688  retry_count_inc();
691  boost::bind(&NdpEntry::RetransmitTimerExpired, this), NULL);
692 }
693 
696  return false;
697 }
698 
701  return false;
702 }
703 
706  return false;
707 }
710  return false;
711 }
714  return false;
715 }
716 bool NdpEntry::EnqueueNsIn(nd_neighbor_solicit *ns, MacAddress mac) {
717  Enqueue(fsm::EvNsIn(ns, mac));
718  return false;
719 }
720 bool NdpEntry::EnqueueNaIn(nd_neighbor_advert *na, MacAddress mac) {
721  if (na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED) {
722  Enqueue(fsm::EvSolNaIn(na, mac));
723  } else {
724  Enqueue(fsm::EvUnsolNaIn(na, mac));
725  }
726  return false;
727 }
728 
729 bool NdpEntry::EnqueueUnsolNaIn(nd_neighbor_advert *na, MacAddress mac) {
730  Enqueue(fsm::EvUnsolNaIn(na, mac));
731  return false;
732 }
733 
734 bool NdpEntry::EnqueueSolNaIn(nd_neighbor_advert *na, MacAddress mac) {
735  Enqueue(fsm::EvSolNaIn(na, mac));
736  return false;
737 }
738 
739 bool NdpEntry::EnqueueTestStateChange(State state, int retry_count) {
740  Enqueue(fsm::EvTestStateChange(state, retry_count));
741  return false;
742 }
743 
744 static const string state_names[] = {
745  "NoState",
746  "Incomplete",
747  "Reachable",
748  "Stale",
749  "Delay",
750  "Probe"
751 };
752 
753 const string &NdpEntry::StateName() const {
754  return state_names[state_];
755 }
756 
757 const string &NdpEntry::LastStateName() const {
758  return state_names[last_state_];
759 }
760 
761 const string NdpEntry::last_state_change_at() const {
763 }
764 
765 const uint64_t NdpEntry::last_state_change_usecs_at() const {
766  return last_state_change_at_;
767 }
768 
769 ostream &operator<<(ostream &out, const NdpEntry::State &state) {
770  out << state_names[state];
771  return out;
772 }
773 
774 // This class determines whether a given class has a method called 'validate'.
775 template <typename Ev>
776 struct HasValidate {
777  template <typename T, bool (T::*)(NdpEntry *) const> struct SFINAE {};
778  template <typename T> static char Test(SFINAE<T, &T::validate>*);
779  template <typename T> static int Test(...);
780  static const bool Has = sizeof(Test<Ev>(0)) == sizeof(char);
781 };
782 
783 template <typename Ev, bool has_validate>
784 struct ValidateFn {
785  EvValidate operator()(const Ev *event) {
786  return NULL;
787  }
788 };
789 
790 template <typename Ev>
791 struct ValidateFn<Ev, true> {
792  EvValidate operator()(const Ev *event) {
793  return boost::bind(&Ev::validate, event, _1);
794  }
795 };
796 
797 template <typename Ev>
798 bool NdpEntry::Enqueue(const Ev &event) {
799  LogEvent(TYPE_NAME(event), "Enqueue");
800  EventContainer ec;
801  ec.event = event.intrusive_from_this();
803  static_cast<const Ev *>(ec.event.get()));
804  work_queue_.Enqueue(ec);
805 
806  return true;
807 }
808 
809 void NdpEntry::LogEvent(string event_name, string msg,
810  SandeshLevel::type log_level) {
811  SM_LOG(log_level, msg << " " << event_name << " in state " << StateName());
812 }
813 
816  if (ec.validate.empty() || ec.validate(this)) {
817  LogEvent(TYPE_NAME(*ec.event), "Dequeue");
818  process_event(*ec.event);
819  } else {
820  LogEvent(TYPE_NAME(*ec.event), "Discard", SandeshLevel::SYS_INFO);
821  }
822  ec.event.reset();
823 
824  return true;
825 }
826 
827 void NdpEntry::DequeueEventDone(bool done) {
828 }
829 
830 void NdpEntry::set_last_event(const std::string &event) {
831  last_event_ = event;
833 }
834 
835 void NdpEntry::set_last_notification_out(int code, int subcode,
836  const string &reason) {
837  last_notification_out_ = std::make_pair(code, subcode);
840 
841 }
842 
843 void NdpEntry::set_last_notification_in(int code, int subcode,
844  const string &reason) {
845  last_notification_in_ = std::make_pair(code, subcode);
848 
849 }
850 
852  if (state == state_)
853  return;
854  last_state_ = state_; state_ = state;
856 
857 }
858 
860  last_notification_in_ = std::make_pair(0, 0);
862  last_notification_in_error_ = std::string();
863  last_notification_out_ = std::make_pair(0, 0);
865  last_notification_out_error_ = std::string();
867  last_event_ = "";
869  last_event_at_ = 0;
870 
871 }
873  return (get_state() != (NdpEntry::NOSTATE) &&
875 }
876 
878  return false;
879  if (key_.vrf != nh_vrf_) {
880  return true;
881  }
882  return false;
883 }
884 
885 void NdpEntry::SendNeighborSolicit(bool send_unicast) {
886  assert(!IsDerived());
887  IpAddress ip = handler_->agent()->router_id6();
888  uint32_t vrf_id = get_interface()->vrf_id();
889 
890  const VmInterface *vmi = dynamic_cast<const VmInterface *>(get_interface());
891  if (vrf_id != VrfEntry::kInvalidIndex) {
892  if (ip.is_v6()) {
893  handler_->SendNeighborSolicit(ip.to_v6(), key_.ip,
894  vmi, vrf_id, send_unicast);
895  }
896  }
897 }
898 
899 void NdpEntry::SendNeighborAdvert(bool solicited) {
900  assert(!IsDerived());
901  Agent *agent = handler_->agent();
902  IpAddress ip;
903  const VmInterface *vmi = NULL;
904  if (interface_->type() == Interface::VM_INTERFACE) {
905  vmi = static_cast<const VmInterface *>(interface_.get());
906  MacAddress smac = vmi->GetVifMac(agent);
907  if (key_.vrf && key_.vrf->vn()) {
909  (Ip6Address(key_.ip));
910  IpAddress dns_ip = key_.vrf->vn()->GetDnsFromIpam
911  (Ip6Address(key_.ip));
912  if (!gw_ip.is_unspecified() && gw_ip.is_v6()) {
913  handler_->SendNeighborAdvert(gw_ip.to_v6(), key_.ip,
914  smac, vmi->vm_mac(), vmi->id(),
915  key_.vrf->vrf_id(), solicited);
916  }
917  if (!dns_ip.is_unspecified() && dns_ip.is_v6() && dns_ip != gw_ip) {
918  handler_->SendNeighborAdvert(dns_ip.to_v6(), key_.ip,
919  smac, vmi->vm_mac(), vmi->id(),
920  key_.vrf->vrf_id(), solicited);
921  }
922  }
923  } else {
924  if (agent->router_id6().is_v6()) {
925  handler_->SendNeighborAdvert(agent->router_id6().to_v6(), key_.ip,
927  MacAddress(),
929  key_.vrf->vrf_id(), solicited);
930  }
931  }
932 }
933 
934 void NdpEntry::HandleNsRequest(nd_neighbor_solicit *ns, MacAddress mac) {
935  if (IsResolved())
936  AddNdpRoute(true);
937  else {
938  AddNdpRoute(false);
939  }
940  EnqueueNsIn(ns, mac);
941 }
942 
943 void NdpEntry::AddNdpRoute(bool resolved) {
944  if (key_.vrf->GetName() == handler_->agent()->linklocal_vrf_name()) {
945  // Do not squash existing route entry.
946  // should be smarter and not replace an existing route.
947  return;
948  }
949 
950  Ip6Address ip(key_.ip);
951  const string& vrf_name = key_.vrf->GetName();
952  NdpNHKey nh_key(nh_vrf_->GetName(), ip, false);
953  NdpNH *ndp_nh = static_cast<NdpNH *>(handler_->agent()->nexthop_table()->
954  FindActiveEntry(&nh_key));
955 
956  if (ndp_nh && ndp_nh->GetResolveState() &&
957  mac().CompareTo(ndp_nh->GetMac()) == 0) {
958  // MAC address unchanged, ignore
959  if (!IsDerived()) {
960  return;
961  } else {
962  /* Return if the route is already existing */
964  handler_->agent()->local_peer(), vrf_name, ip, 32);
966  FindActiveEntry(rt_key);
967  delete rt_key;
968  if (entry) {
969  return;
970  }
971  resolved = true;
972  }
973  }
974 
975  NDP_TRACE(Trace, "Add", ip.to_string(), vrf_name, mac().ToString());
977 
978  bool policy = false;
980  TagList tag;
981  VnListType vn_list;
982  const NextHop *nh;
983  if (entry && (nh = entry->GetActiveNextHop()) != NULL) {
984  policy = nh->PolicyEnabled();
985  sg = entry->GetActivePath()->sg_list();
986  tag = entry->GetActivePath()->tag_list();
987  vn_list = entry->GetActivePath()->dest_vn_list();
988  }
989 
990  const Interface *itf = handler_->agent()->icmpv6_proto()->ip_fabric_interface();
991  if (interface_->type() == Interface::VM_INTERFACE) {
992  const VmInterface *vintf =
993  static_cast<const VmInterface *>(interface_.get());
994  if (vintf->vmi_type() == VmInterface::VHOST) {
995  itf = vintf->parent_list()[0];
996  }
997  }
998 
999  handler_->agent()->fabric_inet4_unicast_table()->NdpRoute(
1000  DBRequest::DB_ENTRY_ADD_CHANGE, vrf_name, ip, mac(),
1001  nh_vrf_->GetName(), *itf, resolved, 128, policy,
1002  vn_list, sg, tag);
1003 }
1004 
1006  if (key_.vrf->GetName() == handler_->agent()->linklocal_vrf_name()) {
1007  return true;
1008  }
1009 
1010  Ip6Address ip(key_.ip);
1011  const string& vrf_name = key_.vrf->GetName();
1012  NdpNHKey nh_key(nh_vrf_->GetName(), ip, false);
1013  NdpNH *ndp_nh = static_cast<NdpNH *>(handler_->agent()->nexthop_table()->
1014  FindActiveEntry(&nh_key));
1015  if (!ndp_nh)
1016  return true;
1017 
1018  NDP_TRACE(Trace, "Delete", ip.to_string(), vrf_name, mac().ToString());
1019  if (IsDerived()) {
1020  //Just enqueue a delete, no need to mark nexthop invalid
1021  InetUnicastAgentRouteTable::Delete(handler_->agent()->local_peer(),
1022  vrf_name, ip, 32);
1023  return true;
1024  }
1025 
1026  handler_->agent()->fabric_inet4_unicast_table()->NdpRoute(
1027  DBRequest::DB_ENTRY_DELETE, vrf_name, ip, mac(),
1028  nh_vrf_->GetName(), *interface_, false, 128, false,
1030  return false;
1031 }
1032 
1033 void NdpEntry::Resync(bool policy, const VnListType &vnlist,
1034  const SecurityGroupList &sg,
1035  const TagList &tag) {
1036  Ip6Address ip(key_.ip);
1037  const string& vrf_name = key_.vrf->GetName();
1038  NDP_TRACE(Trace, "Resync", ip.to_string(), vrf_name,
1039  mac().ToString());
1040  handler_->agent()->fabric_inet4_unicast_table()->NdpRoute(
1043  32, policy, vnlist, sg, tag);
1044 }
bool EnqueueDelayTimerExpired()
Definition: ndp_entry.cc:712
EvNsIn(nd_neighbor_solicit *ns, MacAddress mac)
Definition: ndp_entry.cc:97
boost::intrusive_ptr< Icmpv6Handler > handler_
Definition: ndp_entry.h:156
#define NDP_TRACE(obj,...)
Definition: icmpv6_proto.h:17
uint64_t last_notification_in_at_
Definition: ndp_entry.h:149
sc::result react(const EvReachableTimerExpired &event)
Definition: ndp_entry.cc:340
const std::string & LastStateName() const
Definition: ndp_entry.cc:757
IpAddress GetDnsFromIpam(const IpAddress &ip) const
Definition: vn.cc:668
MacAddress mac_
Definition: ndp_entry.cc:137
const MacAddress & vm_mac() const
bool DeleteNdpRoute()
Definition: ndp_entry.cc:1005
sc::result react(const EvSolNaIn &event)
Definition: ndp_entry.cc:325
Ip6Address ip
Definition: ndp_entry.h:30
std::pair< int, int > last_notification_out_
Definition: ndp_entry.h:150
EvValidate operator()(const Ev *event)
Definition: ndp_entry.cc:792
sc::result react(const EvTestStateChange &event)
Definition: ndp_entry.cc:183
static const char * Name()
Definition: ndp_entry.cc:66
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:178
Definition: vrf.h:86
static const char * Name()
Definition: ndp_entry.cc:41
InetUnicastRouteEntry * FindLPM(const IpAddress &ip)
bool validate(NdpEntry *state_machine) const
Definition: ndp_entry.cc:69
std::string last_notification_in_error_
Definition: ndp_entry.h:148
void Shutdown(bool delete_entries=true)
Definition: queue_task.h:152
WorkQueue< EventContainer > work_queue_
Definition: ndp_entry.h:132
sc::result react(const EvUnsolNaIn &event)
Definition: ndp_entry.cc:394
bool validate(NdpEntry *state_machine) const
Definition: ndp_entry.cc:118
sc::result react(const EvUnsolNaIn &event)
Definition: ndp_entry.cc:240
const uint32_t id() const
Definition: interface.h:123
sc::result react(const EvTestStateChange &event)
Definition: ndp_entry.cc:344
void SendNeighborSolicit(bool send_unicast=false)
Definition: ndp_entry.cc:885
sc::result react(const EvUnsolNaIn &event)
Definition: ndp_entry.cc:476
uint32_t ip_fabric_interface_index() const
Definition: icmpv6_proto.h:126
sc::result react(const EvPktOut &event)
Definition: ndp_entry.cc:419
Incomplete(my_context ctx)
Definition: ndp_entry.cc:211
std::ostream & operator<<(std::ostream &out, BFDState state)
Definition: bfd_common.cc:23
int retry_count() const
Definition: ndp_entry.h:73
EvValidate operator()(const Ev *event)
Definition: ndp_entry.cc:785
boost::asio::ip::address IpAddress
Definition: address.h:13
const MacAddress & GetVifMac(const Agent *) const
static const char * Name()
Definition: ndp_entry.cc:130
uint64_t last_notification_out_at_
Definition: ndp_entry.h:152
std::vector< int > SecurityGroupList
Definition: agent.h:201
void StartReachableTimer()
Definition: ndp_entry.cc:670
void StartDelayTimer()
Definition: ndp_entry.cc:661
NdpKey key_
Definition: ndp_entry.h:154
NdpEntry(boost::asio::io_context &io, Icmpv6Handler *handler, NdpKey &key, const VrfEntry *vrf, const Interface *itf)
Definition: ndp_entry.cc:619
std::string last_notification_out_error_
Definition: ndp_entry.h:151
const std::string last_state_change_at() const
Definition: ndp_entry.cc:761
uint64_t last_event_at_
Definition: ndp_entry.h:145
State get_state() const
Definition: ndp_entry.h:84
InetUnicastAgentRouteTable * GetInet4UnicastRouteTable() const
Definition: vrf.cc:319
bool IsResolved()
Definition: ndp_entry.cc:872
bool RetransmitTimerExpired()
Definition: ndp_entry.cc:694
bool EnqueuePktOut()
Definition: ndp_entry.cc:704
sc::result react(const EvTestStateChange &event)
Definition: ndp_entry.cc:264
void set_mac(MacAddress mac)
Definition: ndp_entry.h:90
bool validate(NdpEntry *state_machine) const
Definition: ndp_entry.cc:133
void set_last_notification_out(int code, int subcode, const std::string &reason)
Definition: ndp_entry.cc:835
sc::result react(const EvSolNaIn &event)
Definition: ndp_entry.cc:573
Reachable(my_context ctx)
Definition: ndp_entry.cc:290
InetUnicastAgentRouteTable * GetInet6UnicastRouteTable() const
Definition: vrf.cc:338
const string & GetName() const
Definition: vrf.h:100
bool validate(NdpEntry *state_machine) const
Definition: ndp_entry.cc:58
nd_neighbor_advert * na_
Definition: ndp_entry.cc:123
void Resync(bool policy, const VnListType &vnlist, const SecurityGroupList &sg, const TagList &tag)
Definition: ndp_entry.cc:1033
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvRetransmitTimerExpired >, sc::custom_reaction< EvTestStateChange > > reactions
Definition: ndp_entry.cc:537
static const char * Name()
Definition: ndp_entry.cc:100
sc::result react(const EvSolNaIn &event)
Definition: ndp_entry.cc:489
State last_state_
Definition: ndp_entry.h:142
sc::result react(const EvNsIn &event)
Definition: ndp_entry.cc:300
EvUnsolNaIn(nd_neighbor_advert *na, MacAddress mac)
Definition: ndp_entry.cc:127
NoState(my_context ctx)
Definition: ndp_entry.cc:158
bool EnqueueUnsolNaIn(nd_neighbor_advert *na, MacAddress mac)
Definition: ndp_entry.cc:729
bool validate(NdpEntry *state_machine) const
Definition: ndp_entry.cc:44
Timer * reachable_timer_
Definition: ndp_entry.h:135
Base class for all Route entries in agent.
Definition: agent_route.h:224
static const int kMaxRetries
Definition: ndp_entry.h:45
bool validate(NdpEntry *state_machine) const
Definition: ndp_entry.cc:103
boost::function< bool(StateMachine *)> EvValidate
Definition: state_machine.h:33
bool validate(NdpEntry *state_machine) const
Definition: ndp_entry.cc:91
std::string ToString() const
Definition: mac_address.cc:53
EvSolNaIn(nd_neighbor_advert *na, MacAddress mac)
Definition: ndp_entry.cc:112
static const bool Has
sc::result react(const EvNsIn &event)
Definition: ndp_entry.cc:465
sc::result react(const EvNsIn &event)
Definition: ndp_entry.cc:549
sc::result react(const EvTestStateChange &event)
Definition: ndp_entry.cc:600
MacAddress mac_
Definition: ndp_entry.cc:122
static void Delete(const Peer *peer, const string &vrf_name, const IpAddress &addr, uint8_t plen)
sc::result react(const EvSolNaIn &event)
Definition: ndp_entry.cc:407
void AddNdpRoute(bool resolved)
Definition: ndp_entry.cc:943
bool EnqueueNsIn(nd_neighbor_solicit *ns, MacAddress mac)
Definition: ndp_entry.cc:716
bool Enqueue(const Ev &event)
Definition: ndp_entry.cc:798
void reset_last_info()
Definition: ndp_entry.cc:859
uint8_t type
Definition: load_balance.h:109
static const std::string integerToString(const NumberType &num)
Definition: string_util.h:19
bool EnqueueRetransmitTimerExpired()
Definition: ndp_entry.cc:708
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvPktOut >, sc::custom_reaction< EvTestStateChange > > reactions
Definition: ndp_entry.cc:156
sc::result react(const EvNsIn &event)
Definition: ndp_entry.cc:221
Definition: agent.h:358
void StartRetransmitTimer()
Definition: ndp_entry.cc:684
uint32_t vrf_id() const
Definition: interface.cc:621
sc::result react(const EvTestStateChange &event)
Definition: ndp_entry.cc:425
Timer * delay_timer_
Definition: ndp_entry.h:133
std::string last_event_
Definition: ndp_entry.h:144
void DeleteAllTimers()
Definition: ndp_entry.cc:655
sc::result react(const EvRetransmitTimerExpired &event)
Definition: ndp_entry.cc:585
NdpEntry::State state_
Definition: ndp_entry.cc:48
Stale(my_context ctx)
Definition: ndp_entry.cc:374
int delay_time_
Definition: ndp_entry.h:137
sc::result react(const EvUnsolNaIn &event)
Definition: ndp_entry.cc:560
boost::asio::ip::address_v6 Ip6Address
Definition: address.h:15
void set_state(State state)
Definition: ndp_entry.cc:851
int CompareTo(const MacAddress &rhs, int len=0) const
Definition: mac_address.cc:87
Probe(my_context ctx)
Definition: ndp_entry.cc:539
State state_
Definition: ndp_entry.h:141
static const char * Name()
Definition: ndp_entry.cc:88
sc::result react(const EvTestStateChange &event)
Definition: ndp_entry.cc:510
const VrfEntry * vrf
Definition: ndp_entry.h:31
Definition: nexthop.h:909
Definition: trace.h:220
static boost::posix_time::ptime UTCUsecToPTime(uint64_t tusec)
Definition: time_util.h:38
MacAddress mac_
Definition: ndp_entry.cc:107
static const char * Name()
Definition: ndp_entry.cc:115
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvDelayTimerExpired >, sc::custom_reaction< EvTestStateChange > > reactions
Definition: ndp_entry.cc:453
const Interface * get_interface() const
Definition: ndp_entry.h:58
void SendNeighborAdvert(bool solicited)
Definition: ndp_entry.cc:899
bool EnqueueTestStateChange(State state, int retry_count)
Definition: ndp_entry.cc:739
uint64_t last_state_change_at_
Definition: ndp_entry.h:146
static const std::set< std::string > & NullStringList()
Definition: agent.h:438
bool IsDerived()
Definition: ndp_entry.cc:877
const uint32_t vrf_id() const
Definition: vrf.h:99
std::set< std::string > VnListType
Definition: agent.h:212
bool DequeueEvent(EventContainer ec)
Definition: ndp_entry.cc:814
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvRetransmitTimerExpired >, sc::custom_reaction< EvTestStateChange > > reactions
Definition: ndp_entry.cc:209
bool EnqueueSolNaIn(nd_neighbor_advert *na, MacAddress mac)
Definition: ndp_entry.cc:734
IpAddress router_id6() const
Definition: agent.h:667
sc::result react(const EvRetransmitTimerExpired &event)
Definition: ndp_entry.cc:249
void retry_count_inc()
Definition: ndp_entry.h:74
bool Cancel()
Definition: timer.cc:150
void HandleNsRequest(nd_neighbor_solicit *ns, MacAddress mac)
Definition: ndp_entry.cc:934
void set_last_event(const std::string &event)
Definition: ndp_entry.cc:830
void retry_count_set(int rc)
Definition: ndp_entry.h:76
sc::result react(const EvDelayTimerExpired &event)
Definition: ndp_entry.cc:501
static const int kMaxUnicastRetries
Definition: ndp_entry.h:46
#define TYPE_NAME(_type)
Definition: logging.h:31
static char Test(SFINAE< T,&T::validate > *)
EvTestStateChange(NdpEntry::State state, int retry)
Definition: ndp_entry.cc:39
MacAddress mac() const
Definition: ndp_entry.h:89
bool DelayTimerExpired()
Definition: ndp_entry.cc:699
virtual ~NdpEntry()
Definition: ndp_entry.cc:647
static uint64_t UTCTimestampUsec()
Definition: time_util.h:13
VmInterface::VmiType vmi_type() const
std::pair< int, int > last_notification_in_
Definition: ndp_entry.h:147
const uint64_t last_state_change_usecs_at() const
Definition: ndp_entry.cc:765
sc::result react(const EvNsIn &event)
Definition: ndp_entry.cc:385
sc::result react(const EvNsIn &event)
Definition: ndp_entry.cc:167
int retransmit_time_
Definition: ndp_entry.h:136
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:108
boost::intrusive_ptr< const sc::event_base > event
Definition: ndp_entry.h:69
VnEntry * vn() const
Definition: vrf.h:101
static const string state_names[]
Definition: ndp_entry.cc:744
Icmpv6Proto * icmpv6_proto() const
Definition: agent.h:996
static const uint32_t kInvalidIndex
Definition: vrf.h:88
InterfaceConstRef interface_
Definition: ndp_entry.h:157
const MacAddress & ip_fabric_interface_mac() const
Definition: icmpv6_proto.h:129
static const char * Name()
Definition: ndp_entry.cc:55
bool PolicyEnabled() const
Definition: nexthop.h:407
nd_neighbor_solicit * ns_
Definition: ndp_entry.cc:108
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvPktOut >, sc::custom_reaction< EvTestStateChange > > reactions
Definition: ndp_entry.cc:370
static const char * Name()
Definition: ndp_entry.cc:77
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvReachableTimerExpired >, sc::custom_reaction< EvTestStateChange > > reactions
Definition: ndp_entry.cc:288
sc::result react(const EvSolNaIn &event)
Definition: ndp_entry.cc:231
#define SM_LOG(level, _Msg)
Definition: ndp_entry.cc:28
int reachable_time_
Definition: ndp_entry.h:138
Timer * retransmit_timer_
Definition: ndp_entry.h:134
bool Enqueue(QueueEntryT entry)
Definition: queue_task.h:248
const VrfEntry * nh_vrf_
Definition: ndp_entry.h:155
nd_neighbor_advert * na_
Definition: ndp_entry.cc:138
void LogEvent(std::string event_name, std::string msg, SandeshLevel::type log_level=SandeshLevel::SYS_DEBUG)
Definition: ndp_entry.cc:809
InterfaceList parent_list() const
void set_last_notification_in(int code, int subcode, const std::string &reason)
Definition: ndp_entry.cc:843
void DequeueEventDone(bool done)
Definition: ndp_entry.cc:827
bool ReachableTimerExpired()
Definition: ndp_entry.cc:679
void retry_count_clear()
Definition: ndp_entry.h:75
bool EnqueueNaIn(nd_neighbor_advert *na, MacAddress mac)
Definition: ndp_entry.cc:720
sc::result react(const EvPktOut &event)
Definition: ndp_entry.cc:174
bool validate(NdpEntry *state_machine) const
Definition: ndp_entry.cc:80
Delay(my_context ctx)
Definition: ndp_entry.cc:455
const std::string & StateName() const
Definition: ndp_entry.cc:753
IpAddress GetGatewayFromIpam(const IpAddress &ip) const
Definition: vn.cc:660
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:222
std::vector< int > TagList
Definition: agent.h:202
sc::result react(const EvUnsolNaIn &event)
Definition: ndp_entry.cc:311