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>
12 #include "services/services_types.h"
19 using std::ostringstream;
22 namespace mpl = boost::mpl;
23 namespace sc = boost::statechart;
28 #define SM_LOG(level, _Msg) \
32 if (LoggingDisabled()) break; \
33 ICMPV6_TRACE(Trace, _Msg); \
41 static const char *
Name() {
42 return "EvTestStateChange";
55 static const char *
Name() {
66 static const char *
Name() {
67 return "EvDelayTimerExpired";
77 static const char *
Name() {
78 return "EvRetransmitTimerExpired";
88 static const char *
Name() {
89 return "EvReachableTimerExpired";
131 return "EvUnsolNaIn";
151 struct NoState : sc::state<NoState, NdpEntry> {
153 sc::custom_reaction<EvNsIn>,
154 sc::custom_reaction<EvPktOut>,
155 sc::custom_reaction<EvTestStateChange>
158 explicit NoState(my_context ctx) : my_base(ctx) {
159 NdpEntry *state_machine = &context<NdpEntry>();
168 NdpEntry *state_machine = &context<NdpEntry>();
170 return transit<Stale>();
175 NdpEntry *state_machine = &context<NdpEntry>();
180 return transit<Incomplete>();
185 NdpEntry *state_machine = &context<NdpEntry>();
195 default:
return discard_event();
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>
212 NdpEntry *state_machine = &context<NdpEntry>();
222 NdpEntry *state_machine = &context<NdpEntry>();
223 if (state_machine->
mac() !=
event.mac_) {
224 state_machine->
mac() =
event.mac_;
225 return transit<Stale>();
227 return discard_event();
232 NdpEntry *state_machine = &context<NdpEntry>();
233 if (state_machine->
mac() !=
event.mac_) {
234 state_machine->
mac() =
event.mac_;
236 return transit<Reachable>();
241 NdpEntry *state_machine = &context<NdpEntry>();
242 state_machine->
mac() =
event.mac_;
243 return transit<Stale>();
250 NdpEntry *state_machine = &context<NdpEntry>();
259 return discard_event();
261 return discard_event();
266 NdpEntry *state_machine = &context<NdpEntry>();
276 default:
return discard_event();
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>
291 NdpEntry *state_machine = &context<NdpEntry>();
301 NdpEntry *state_machine = &context<NdpEntry>();
302 if (state_machine->
mac() !=
event.mac_) {
303 state_machine->
mac() =
event.mac_;
304 return transit<Stale>();
306 return discard_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_) {
316 return transit<Stale>();
319 return discard_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>();
332 if (state_machine->
mac() !=
event.mac_) {
336 return discard_event();
341 return transit<Stale>();
346 NdpEntry *state_machine = &context<NdpEntry>();
356 default:
return discard_event();
363 struct Stale : sc::state<Stale, NdpEntry> {
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>
374 explicit Stale(my_context ctx) : my_base(ctx) {
375 NdpEntry *state_machine = &context<NdpEntry>();
386 NdpEntry *state_machine = &context<NdpEntry>();
387 if (state_machine->
mac() !=
event.mac_) {
390 return discard_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_) {
399 return transit<Stale>();
402 return discard_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_) {
413 return transit<Reachable>();
415 return discard_event();
420 NdpEntry *state_machine = &context<NdpEntry>();
422 return transit<Delay>();
427 NdpEntry *state_machine = &context<NdpEntry>();
438 default:
return discard_event();
446 struct Delay : sc::state<Delay, NdpEntry> {
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>
455 explicit Delay(my_context ctx) : my_base(ctx) {
456 NdpEntry *state_machine = &context<NdpEntry>();
466 NdpEntry *state_machine = &context<NdpEntry>();
467 if (state_machine->
mac() !=
event.mac_) {
469 return transit<Stale>();
471 return discard_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_) {
481 return transit<Stale>();
484 return discard_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_) {
495 return transit<Reachable>();
497 return discard_event();
502 NdpEntry *state_machine = &context<NdpEntry>();
507 return transit<Probe>();
512 NdpEntry *state_machine = &context<NdpEntry>();
522 default:
return discard_event();
530 struct Probe : sc::state<Probe, NdpEntry> {
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>
539 explicit Probe(my_context ctx) : my_base(ctx) {
540 NdpEntry *state_machine = &context<NdpEntry>();
550 NdpEntry *state_machine = &context<NdpEntry>();
551 if (state_machine->
mac() !=
event.mac_) {
553 return transit<Stale>();
555 return discard_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_) {
565 return transit<Stale>();
568 return discard_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_) {
579 return transit<Reachable>();
581 return discard_event();
586 NdpEntry *state_machine = &context<NdpEntry>();
591 return discard_event();
595 return discard_event();
597 return discard_event();
602 NdpEntry *state_machine = &context<NdpEntry>();
612 default:
return discard_event();
621 : work_queue_(
TaskScheduler::GetInstance()->GetTaskId(
"Agent::Services"),
623 boost::bind(&
NdpEntry::DequeueEvent, this, _1)),
629 io,
"Retransmit timer",
633 io,
"Reachable timer",
636 retransmit_time_(1000),
638 reachable_time_(30000),
642 last_state_(NOSTATE),
643 io_(io), key_(key), nh_vrf_(vrf), handler_(handler), interface_(itf) {
721 if (na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED) {
775 template <
typename Ev>
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);
783 template <
typename Ev,
bool has_val
idate>
790 template <
typename Ev>
793 return boost::bind(&Ev::validate, event, _1);
797 template <
typename Ev>
801 ec.
event =
event.intrusive_from_this();
803 static_cast<const Ev *>(ec.
event.get()));
811 SM_LOG(log_level, msg <<
" " << event_name <<
" in state " <<
StateName());
818 process_event(*ec.
event);
836 const string &reason) {
844 const string &reason) {
894 vmi, vrf_id, send_unicast);
912 if (!gw_ip.is_unspecified() && gw_ip.is_v6()) {
917 if (!dns_ip.is_unspecified() && dns_ip.is_v6() && dns_ip != gw_ip) {
954 FindActiveEntry(&nh_key));
956 if (ndp_nh && ndp_nh->GetResolveState() &&
964 handler_->agent()->local_peer(), vrf_name, ip, 32);
966 FindActiveEntry(rt_key);
983 if (entry && (nh = entry->GetActiveNextHop()) != NULL) {
985 sg = entry->GetActivePath()->sg_list();
986 tag = entry->GetActivePath()->tag_list();
987 vn_list = entry->GetActivePath()->dest_vn_list();
999 handler_->agent()->fabric_inet4_unicast_table()->NdpRoute(
1014 FindActiveEntry(&nh_key));
1026 handler_->agent()->fabric_inet4_unicast_table()->NdpRoute(
1040 handler_->agent()->fabric_inet4_unicast_table()->NdpRoute(
1043 32, policy, vnlist, sg, tag);
bool EnqueueDelayTimerExpired()
EvNsIn(nd_neighbor_solicit *ns, MacAddress mac)
boost::intrusive_ptr< Icmpv6Handler > handler_
#define NDP_TRACE(obj,...)
uint64_t last_notification_in_at_
sc::result react(const EvReachableTimerExpired &event)
const std::string & LastStateName() const
IpAddress GetDnsFromIpam(const IpAddress &ip) const
const MacAddress & vm_mac() const
sc::result react(const EvSolNaIn &event)
std::pair< int, int > last_notification_out_
EvValidate operator()(const Ev *event)
sc::result react(const EvTestStateChange &event)
static const char * Name()
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
static const char * Name()
InetUnicastRouteEntry * FindLPM(const IpAddress &ip)
bool validate(NdpEntry *state_machine) const
std::string last_notification_in_error_
void Shutdown(bool delete_entries=true)
WorkQueue< EventContainer > work_queue_
sc::result react(const EvUnsolNaIn &event)
bool validate(NdpEntry *state_machine) const
sc::result react(const EvUnsolNaIn &event)
const uint32_t id() const
sc::result react(const EvTestStateChange &event)
void SendNeighborSolicit(bool send_unicast=false)
sc::result react(const EvUnsolNaIn &event)
uint32_t ip_fabric_interface_index() const
sc::result react(const EvPktOut &event)
Incomplete(my_context ctx)
std::ostream & operator<<(std::ostream &out, BFDState state)
EvValidate operator()(const Ev *event)
boost::asio::ip::address IpAddress
const MacAddress & GetVifMac(const Agent *) const
static const char * Name()
uint64_t last_notification_out_at_
std::vector< int > SecurityGroupList
void StartReachableTimer()
NdpEntry(boost::asio::io_context &io, Icmpv6Handler *handler, NdpKey &key, const VrfEntry *vrf, const Interface *itf)
std::string last_notification_out_error_
const std::string last_state_change_at() const
InetUnicastAgentRouteTable * GetInet4UnicastRouteTable() const
bool RetransmitTimerExpired()
sc::result react(const EvTestStateChange &event)
void set_mac(MacAddress mac)
bool validate(NdpEntry *state_machine) const
void set_last_notification_out(int code, int subcode, const std::string &reason)
sc::result react(const EvSolNaIn &event)
Reachable(my_context ctx)
InetUnicastAgentRouteTable * GetInet6UnicastRouteTable() const
const string & GetName() const
bool validate(NdpEntry *state_machine) const
void Resync(bool policy, const VnListType &vnlist, const SecurityGroupList &sg, const TagList &tag)
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvRetransmitTimerExpired >, sc::custom_reaction< EvTestStateChange > > reactions
static const char * Name()
sc::result react(const EvSolNaIn &event)
sc::result react(const EvNsIn &event)
EvUnsolNaIn(nd_neighbor_advert *na, MacAddress mac)
bool EnqueueUnsolNaIn(nd_neighbor_advert *na, MacAddress mac)
bool validate(NdpEntry *state_machine) const
Base class for all Route entries in agent.
static const int kMaxRetries
bool validate(NdpEntry *state_machine) const
boost::function< bool(StateMachine *)> EvValidate
EvRetransmitTimerExpired()
bool validate(NdpEntry *state_machine) const
std::string ToString() const
EvSolNaIn(nd_neighbor_advert *na, MacAddress mac)
sc::result react(const EvNsIn &event)
sc::result react(const EvNsIn &event)
sc::result react(const EvTestStateChange &event)
static void Delete(const Peer *peer, const string &vrf_name, const IpAddress &addr, uint8_t plen)
sc::result react(const EvSolNaIn &event)
void AddNdpRoute(bool resolved)
bool EnqueueNsIn(nd_neighbor_solicit *ns, MacAddress mac)
bool Enqueue(const Ev &event)
static const std::string integerToString(const NumberType &num)
bool EnqueueRetransmitTimerExpired()
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvPktOut >, sc::custom_reaction< EvTestStateChange > > reactions
sc::result react(const EvNsIn &event)
void StartRetransmitTimer()
sc::result react(const EvTestStateChange &event)
sc::result react(const EvRetransmitTimerExpired &event)
sc::result react(const EvUnsolNaIn &event)
boost::asio::ip::address_v6 Ip6Address
void set_state(State state)
int CompareTo(const MacAddress &rhs, int len=0) const
static const char * Name()
sc::result react(const EvTestStateChange &event)
static boost::posix_time::ptime UTCUsecToPTime(uint64_t tusec)
static const char * Name()
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvDelayTimerExpired >, sc::custom_reaction< EvTestStateChange > > reactions
const Interface * get_interface() const
void SendNeighborAdvert(bool solicited)
bool EnqueueTestStateChange(State state, int retry_count)
uint64_t last_state_change_at_
static const std::set< std::string > & NullStringList()
const uint32_t vrf_id() const
std::set< std::string > VnListType
bool DequeueEvent(EventContainer ec)
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvRetransmitTimerExpired >, sc::custom_reaction< EvTestStateChange > > reactions
bool EnqueueSolNaIn(nd_neighbor_advert *na, MacAddress mac)
IpAddress router_id6() const
sc::result react(const EvRetransmitTimerExpired &event)
void HandleNsRequest(nd_neighbor_solicit *ns, MacAddress mac)
void set_last_event(const std::string &event)
void retry_count_set(int rc)
sc::result react(const EvDelayTimerExpired &event)
static const int kMaxUnicastRetries
static char Test(SFINAE< T,&T::validate > *)
EvTestStateChange(NdpEntry::State state, int retry)
static uint64_t UTCTimestampUsec()
VmInterface::VmiType vmi_type() const
std::pair< int, int > last_notification_in_
const uint64_t last_state_change_usecs_at() const
sc::result react(const EvNsIn &event)
sc::result react(const EvNsIn &event)
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
boost::intrusive_ptr< const sc::event_base > event
static const string state_names[]
Icmpv6Proto * icmpv6_proto() const
static const uint32_t kInvalidIndex
InterfaceConstRef interface_
const MacAddress & ip_fabric_interface_mac() const
static const char * Name()
bool PolicyEnabled() const
nd_neighbor_solicit * ns_
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvPktOut >, sc::custom_reaction< EvTestStateChange > > reactions
static const char * Name()
mpl::list< sc::custom_reaction< EvNsIn >, sc::custom_reaction< EvUnsolNaIn >, sc::custom_reaction< EvSolNaIn >, sc::custom_reaction< EvReachableTimerExpired >, sc::custom_reaction< EvTestStateChange > > reactions
sc::result react(const EvSolNaIn &event)
#define SM_LOG(level, _Msg)
Timer * retransmit_timer_
EvReachableTimerExpired()
bool Enqueue(QueueEntryT entry)
void LogEvent(std::string event_name, std::string msg, SandeshLevel::type log_level=SandeshLevel::SYS_DEBUG)
InterfaceList parent_list() const
void set_last_notification_in(int code, int subcode, const std::string &reason)
void DequeueEventDone(bool done)
bool ReachableTimerExpired()
bool EnqueueNaIn(nd_neighbor_advert *na, MacAddress mac)
sc::result react(const EvPktOut &event)
bool validate(NdpEntry *state_machine) const
const std::string & StateName() const
IpAddress GetGatewayFromIpam(const IpAddress &ip) const
static bool DeleteTimer(Timer *Timer)
std::vector< int > TagList
sc::result react(const EvUnsolNaIn &event)