From 6dc5cb9e8cd912a94312fe1598fe6e7716e29d88 Mon Sep 17 00:00:00 2001 From: Nischal Sheth Date: Wed, 17 Jun 2015 09:52:25 -0700 Subject: [PATCH] Handle spurious route add/delete by closing xmpp connection This protects against bugs and/or race conditions in agent code. It allows both sides to recover cleanly, without getting the CN stuck. Change-Id: I785c45c201bf70b32bd2e120fcfacf4052df5bd1 Closes-Bug: 1466562 --- src/bgp/bgp_xmpp_channel.cc | 275 ++++++------------ src/bgp/bgp_xmpp_channel.h | 2 + src/bgp/test/bgp_xmpp_deferq_test.cc | 404 +++++++++++++++++++++++++++ 3 files changed, 490 insertions(+), 191 deletions(-) diff --git a/src/bgp/bgp_xmpp_channel.cc b/src/bgp/bgp_xmpp_channel.cc index f041ef219e4..ccaf00c5185 100644 --- a/src/bgp/bgp_xmpp_channel.cc +++ b/src/bgp/bgp_xmpp_channel.cc @@ -737,6 +737,7 @@ bool BgpXmppChannel::XmppDecodeAddress(int af, const string &address, // bool BgpXmppChannel::GetMembershipInfo(BgpTable *table, int *instance_id, RequestType *req_type) { + *instance_id = -1; RoutingTableMembershipRequestMap::iterator loc = routingtable_membership_request_map_.find(table->name()); if (loc != routingtable_membership_request_map_.end()) { @@ -756,17 +757,70 @@ bool BgpXmppChannel::GetMembershipInfo(BgpTable *table, // bool BgpXmppChannel::GetMembershipInfo(const string &vrf_name, int *instance_id) { + *instance_id = -1; VrfMembershipRequestMap::iterator loc = vrf_membership_request_map_.find(vrf_name); if (loc != vrf_membership_request_map_.end()) { *instance_id = loc->second; return true; } else { - *instance_id = -1; return false; } } +// +// Verify that there's a subscribe or pending subscribe for the table +// corresponding to the vrf and family. +// If there's a subscribe, populate the table and instance_id. +// If there's a pending subscribe, populate the instance_id. +// The subscribe_pending parameter is set appropriately. +// +// Return true if there's a subscribe or pending subscribe, false otherwise. +// +bool BgpXmppChannel::VerifyMembership(const string &vrf_name, + Address::Family family, BgpTable **table, + int *instance_id, bool *subscribe_pending) { + *table = NULL; + *subscribe_pending = false; + + RoutingInstanceMgr *instance_mgr = bgp_server_->routing_instance_mgr(); + RoutingInstance *rt_instance = instance_mgr->GetRoutingInstance(vrf_name); + if (rt_instance != NULL && !rt_instance->deleted()) { + *table = rt_instance->GetTable(family); + RequestType req_type; + if (GetMembershipInfo(*table, instance_id, &req_type)) { + // Bail if there's a pending unsubscribe. + if (req_type != SUBSCRIBE) { + BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, + SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, + "Received route after unsubscribe"); + return false; + } + *subscribe_pending = true; + } else { + // Bail if we are not subscribed to the table. + if (*instance_id < 0) { + BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, + SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, + "Received route without subscribe"); + return false; + } + } + } else { + // Bail if there's no pending subscribe. + if (GetMembershipInfo(vrf_name, instance_id)) { + *subscribe_pending = true; + } else { + BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, + SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, + "Received route without pending subscribe"); + return false; + } + } + + return true; +} + bool BgpXmppChannel::ProcessMcastItem(string vrf_name, const pugi::xml_node &node, bool add_change) { @@ -780,7 +834,6 @@ bool BgpXmppChannel::ProcessMcastItem(string vrf_name, return false; } - // NLRI ipaddress/mask if (item.entry.nlri.af != BgpAf::IPv4) { BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, "Unsupported address family:" << item.entry.nlri.af @@ -820,54 +873,16 @@ bool BgpXmppChannel::ProcessMcastItem(string vrf_name, } } - RoutingInstanceMgr *instance_mgr = bgp_server_->routing_instance_mgr(); - RoutingInstance *rt_instance = instance_mgr->GetRoutingInstance(vrf_name); - bool subscribe_pending = false; - int instance_id = -1; - BgpTable *table = NULL; - // Build the key to the Multicast DBTable - PeerRibMembershipManager *mgr = bgp_server_->membership_mgr(); - if (rt_instance != NULL && !rt_instance->deleted()) { - table = rt_instance->GetTable(Address::ERMVPN); - if (table == NULL) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Inet Multicast table not found"); - return false; - } - - RequestType req_type; - if (GetMembershipInfo(table, &instance_id, &req_type)) { - if (req_type != SUBSCRIBE) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Inet Multicast Route not processed " - "as no subscription pending"); - return false; - } - subscribe_pending = true; - } else { - // Bail if we are not subscribed to the table - if (instance_id < 0) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Inet Multicast Route not processed " - "as peer is not registered"); - return false; - } - } - } else { - // Check if Registration is pending before routing instance create - if (GetMembershipInfo(vrf_name, &instance_id)) { - subscribe_pending = true; - } else { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Inet Multicast Route not processed as no subscription pending"); - return false; - } + bool subscribe_pending; + int instance_id; + BgpTable *table; + if (!VerifyMembership(vrf_name, Address::ERMVPN, &table, &instance_id, + &subscribe_pending)) { + channel_->Close(); + return false; } + // Build the key to the Multicast DBTable RouteDistinguisher mc_rd(peer_->bgp_identifier(), instance_id); ErmVpnPrefix mc_prefix(ErmVpnPrefix::NativeRoute, mc_rd, grp_address.to_v4(), src_address.to_v4()); @@ -989,14 +1004,6 @@ bool BgpXmppChannel::ProcessMcastItem(string vrf_name, } assert(table); - if (mgr && !mgr->PeerRegistered(peer_.get(), table)) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, SandeshLevel::SYS_WARN, - BGP_LOG_FLAG_ALL, - "Peer:" << peer_.get() << " not subscribed to table " << - table->name()); - return false; - } - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE, "Inet Multicast Group" @@ -1044,52 +1051,13 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, return false; } - RoutingInstanceMgr *instance_mgr = bgp_server_->routing_instance_mgr(); - RoutingInstance *rt_instance = instance_mgr->GetRoutingInstance(vrf_name); - bool subscribe_pending = false; - int instance_id = -1; - BgpTable *table = NULL; - if (rt_instance != NULL && !rt_instance->deleted()) { - table = rt_instance->GetTable(Address::INET); - if (table == NULL) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Inet table not found"); - return false; - } - - RequestType req_type; - if (GetMembershipInfo(table, &instance_id, &req_type)) { - // We have rxed unregister request for a table and - // receiving route update for the same table - if (req_type != SUBSCRIBE) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Received route update after unregister req : " << - table->name()); - return false; - } - subscribe_pending = true; - } else { - // Bail if we are not subscribed to the table - if (instance_id < 0) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Peer:" << peer_.get() << " not subscribed to table " << - table->name()); - return false; - } - } - } else { - // Check if Registration is pending before routing instance create - if (GetMembershipInfo(vrf_name, &instance_id)) { - subscribe_pending = true; - } else { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Inet Route not processed as no subscription pending"); - return false; - } + bool subscribe_pending; + int instance_id; + BgpTable *table; + if (!VerifyMembership(vrf_name, Address::INET, &table, &instance_id, + &subscribe_pending)) { + channel_->Close(); + return false; } InetTable::RequestData::NextHops nexthops; @@ -1273,51 +1241,13 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, return false; } - RoutingInstanceMgr *instance_mgr = bgp_server_->routing_instance_mgr(); - RoutingInstance *rt_instance = instance_mgr->GetRoutingInstance(vrf_name); - bool subscribe_pending = false; - int instance_id = -1; - BgpTable *table = NULL; - if (rt_instance != NULL && !rt_instance->deleted()) { - table = rt_instance->GetTable(Address::INET6); - if (table == NULL) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, SandeshLevel::SYS_WARN, - BGP_LOG_FLAG_ALL, "Inet6 table not found"); - return false; - } - - RequestType req_type; - if (GetMembershipInfo(table, &instance_id, &req_type)) { - // We have rxed unregister request for a table and - // receiving route update for the same table - if (req_type != SUBSCRIBE) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Received route update after unregister req : " - << table->name()); - return false; - } - subscribe_pending = true; - } else { - if (instance_id < 0) { - // Bail if we are not subscribed to the table - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Peer:" << peer_.get() << " not subscribed to table " << - table->name()); - return false; - } - } - } else { - // Check if Registration is pending before routing instance create - if (GetMembershipInfo(vrf_name, &instance_id)) { - subscribe_pending = true; - } else { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Inet6 Route not processed as no subscription pending"); - return false; - } + bool subscribe_pending; + int instance_id; + BgpTable *table; + if (!VerifyMembership(vrf_name, Address::INET6, &table, &instance_id, + &subscribe_pending)) { + channel_->Close(); + return false; } Inet6Table::RequestData::NextHops nexthops; @@ -1553,50 +1483,13 @@ bool BgpXmppChannel::ProcessEnetItem(string vrf_name, } } - RoutingInstanceMgr *instance_mgr = bgp_server_->routing_instance_mgr(); - RoutingInstance *rt_instance = instance_mgr->GetRoutingInstance(vrf_name); - bool subscribe_pending = false; - int instance_id = -1; - BgpTable *table = NULL; - if (rt_instance != NULL && !rt_instance->deleted()) { - table = rt_instance->GetTable(Address::EVPN); - if (table == NULL) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, SandeshLevel::SYS_WARN, - BGP_LOG_FLAG_ALL, "Evpn table not found"); - return false; - } - - RequestType req_type; - if (GetMembershipInfo(table, &instance_id, &req_type)) { - // We have rxed unregister request for a table and - // receiving route update for the same table - if (req_type != SUBSCRIBE) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Received route update after unregister req : " - << table->name()); - return false; - } - subscribe_pending = true; - } else { - if (instance_id < 0) { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Peer:" << peer_.get() << " not subscribed to table " << - table->name()); - return false; - } - } - } else { - // Check if Registration is pending before routing instance create - if (GetMembershipInfo(vrf_name, &instance_id)) { - subscribe_pending = true; - } else { - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_WARN, BGP_LOG_FLAG_ALL, - "Evpn Route not processed as no subscription pending"); - return false; - } + bool subscribe_pending; + int instance_id; + BgpTable *table; + if (!VerifyMembership(vrf_name, Address::EVPN, &table, &instance_id, + &subscribe_pending)) { + channel_->Close(); + return false; } RouteDistinguisher rd; diff --git a/src/bgp/bgp_xmpp_channel.h b/src/bgp/bgp_xmpp_channel.h index 0e3cd0c4334..4100c361130 100644 --- a/src/bgp/bgp_xmpp_channel.h +++ b/src/bgp/bgp_xmpp_channel.h @@ -177,6 +177,8 @@ class BgpXmppChannel { int *instance_id, RequestType *req_type); virtual bool GetMembershipInfo(const std::string &vrf_name, int *instance_id); + bool VerifyMembership(const std::string &vrf_name, Address::Family family, + BgpTable **table, int *instance_id, bool *subscribe_pending); bool ProcessItem(std::string vrf_name, const pugi::xml_node &node, bool add_change); diff --git a/src/bgp/test/bgp_xmpp_deferq_test.cc b/src/bgp/test/bgp_xmpp_deferq_test.cc index 968ff73bc10..f17c4bf30ed 100644 --- a/src/bgp/test/bgp_xmpp_deferq_test.cc +++ b/src/bgp/test/bgp_xmpp_deferq_test.cc @@ -2157,6 +2157,410 @@ TEST_F(BgpXmppUnitTest, CreateRoutingInstanceWithPeerCloseInProgress2) { task_util::WaitForIdle(); } +TEST_F(BgpXmppUnitTest, AddDeleteInetRouteWithoutRegister1) { + ConfigureWithoutRoutingInstances(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Add a route without registering. + agent_a_->AddRoute("blue", "10.1.1.1/32"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteRoute("blue", "10.1.1.1/32"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteInetRouteWithoutRegister2) { + Configure(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Add a route without registering. + agent_a_->AddRoute("blue", "10.1.1.1/32"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteRoute("blue", "10.1.1.1/32"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteInetRouteWithoutRegister3) { + Configure(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Pause the peer membership manager. + PausePeerRibMembershipManager(); + + // Subscribe and unsubscribe to the blue instance. The requests will get + // enqueued in the membership manager, but won't be processed. + agent_a_->Subscribe("blue", 1); + agent_a_->Unsubscribe("blue", 1); + TASK_UTIL_EXPECT_TRUE( + PeerHasPendingMembershipRequests(bgp_channel_manager_->channel_)); + TASK_UTIL_EXPECT_TRUE( + PeerNotRegistered(bgp_channel_manager_->channel_, "blue")); + + // Add a route with pending unsubscribe. + agent_a_->AddRoute("blue", "10.1.1.1/32"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteRoute("blue", "10.1.1.1/32"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Resume the peer membership manager and bring down the session. + ResumePeerRibMembershipManager(); + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteInet6RouteWithoutRegister1) { + ConfigureWithoutRoutingInstances(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Add a route without registering. + agent_a_->AddInet6Route("blue", "cafe::1/128"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteInet6Route("blue", "cafe::1/128"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteInet6RouteWithoutRegister2) { + Configure(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Add a route without registering. + agent_a_->AddInet6Route("blue", "cafe::1/128"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteInet6Route("blue", "cafe::1/128"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteInet6RouteWithoutRegister3) { + Configure(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Pause the peer membership manager. + PausePeerRibMembershipManager(); + + // Subscribe and unsubscribe to the blue instance. The requests will get + // enqueued in the membership manager, but won't be processed. + agent_a_->Subscribe("blue", 1); + agent_a_->Unsubscribe("blue", 1); + TASK_UTIL_EXPECT_TRUE( + PeerHasPendingMembershipRequests(bgp_channel_manager_->channel_)); + TASK_UTIL_EXPECT_TRUE( + PeerNotRegistered(bgp_channel_manager_->channel_, "blue")); + + // Add a route with pending unsubscribe. + agent_a_->AddInet6Route("blue", "cafe::1/128"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteInet6Route("blue", "cafe::1/128"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Resume the peer membership manager and bring down the session. + ResumePeerRibMembershipManager(); + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteMcastRouteWithoutRegister1) { + ConfigureWithoutRoutingInstances(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Add a route without registering. + agent_a_->AddMcastRoute("blue", "225.0.0.1,90.1.1.1", "10.1.1.1", "10-20"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteMcastRoute("blue", "225.0.0.1,90.1.1.1"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteMcastRouteWithoutRegister2) { + Configure(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Add a route without registering. + agent_a_->AddMcastRoute("blue", "225.0.0.1,90.1.1.1", "10.1.1.1", "10-20"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteMcastRoute("blue", "225.0.0.1,90.1.1.1"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteMcastRouteWithoutRegister3) { + Configure(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Pause the peer membership manager. + PausePeerRibMembershipManager(); + + // Subscribe and unsubscribe to the blue instance. The requests will get + // enqueued in the membership manager, but won't be processed. + agent_a_->Subscribe("blue", 1); + agent_a_->Unsubscribe("blue", 1); + TASK_UTIL_EXPECT_TRUE( + PeerHasPendingMembershipRequests(bgp_channel_manager_->channel_)); + TASK_UTIL_EXPECT_TRUE( + PeerNotRegistered(bgp_channel_manager_->channel_, "blue")); + + // Add a route with pending unsubscribe. + agent_a_->AddMcastRoute("blue", "225.0.0.1,90.1.1.1", "10.1.1.1", "10-20"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteMcastRoute("blue", "225.0.0.1,90.1.1.1"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Resume the peer membership manager and bring down the session. + ResumePeerRibMembershipManager(); + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteEnetRouteWithoutRegister1) { + ConfigureWithoutRoutingInstances(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Add a route without registering. + agent_a_->AddEnetRoute("blue", "aa:0:0:0:0:01,10.1.1.1/32", "192.168.1.1"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteEnetRoute("blue", "aa:0:0:0:0:01,10.1.1.1/32"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteEnetRouteWithoutRegister2) { + Configure(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Add a route without registering. + agent_a_->AddEnetRoute("blue", "aa:0:0:0:0:01,10.1.1.1/32", "192.168.1.1"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteEnetRoute("blue", "aa:0:0:0:0:01,10.1.1.1/32"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + agent_a_->SessionDown(); +} + +TEST_F(BgpXmppUnitTest, AddDeleteEnetRouteWithoutRegister3) { + Configure(); + task_util::WaitForIdle(); + + // create an XMPP client in server A + agent_a_.reset( + new test::NetworkAgentMock(&evm_, SUB_ADDR, xs_a_->GetPort())); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + uint32_t old_flap_count = agent_a_->flap_count(); + + // Pause the peer membership manager. + PausePeerRibMembershipManager(); + + // Subscribe and unsubscribe to the blue instance. The requests will get + // enqueued in the membership manager, but won't be processed. + agent_a_->Subscribe("blue", 1); + agent_a_->Unsubscribe("blue", 1); + TASK_UTIL_EXPECT_TRUE( + PeerHasPendingMembershipRequests(bgp_channel_manager_->channel_)); + TASK_UTIL_EXPECT_TRUE( + PeerNotRegistered(bgp_channel_manager_->channel_, "blue")); + + // Add a route with pending unsubscribe. + agent_a_->AddEnetRoute("blue", "aa:0:0:0:0:01,10.1.1.1/32", "192.168.1.1"); + + // Make sure session on agent flapped. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Wait for the session to get established again. + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + old_flap_count = agent_a_->flap_count(); + + // Delete a route without registering. + agent_a_->DeleteEnetRoute("blue", "aa:0:0:0:0:01,10.1.1.1/32"); + + // Make sure session on agent flapped again. + TASK_UTIL_EXPECT_TRUE(agent_a_->flap_count() > old_flap_count); + + // Resume the peer membership manager and bring down the session. + ResumePeerRibMembershipManager(); + agent_a_->SessionDown(); +} + TEST_F(BgpXmppSerializeMembershipReqTest, SerializedMembershipReq1) { TaskScheduler *scheduler = TaskScheduler::GetInstance(); scheduler->Stop();