diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index dbb0ee4a0d1..e46c2618ec9 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -63,6 +63,7 @@ Srv6Orch *gSrv6Orch; FlowCounterRouteOrch *gFlowCounterRouteOrch; DebugCounterOrch *gDebugCounterOrch; MonitorOrch *gMonitorOrch; +BfdMonitorOrch *gBfdMonitorOrch; TunnelDecapOrch *gTunneldecapOrch; StpOrch *gStpOrch; MuxOrch *gMuxOrch; @@ -260,6 +261,8 @@ bool OrchDaemon::init() gDirectory.set(vrf_orch); gMonitorOrch = new MonitorOrch(m_stateDb, STATE_VNET_MONITOR_TABLE_NAME); gDirectory.set(gMonitorOrch); + gBfdMonitorOrch = new BfdMonitorOrch(m_stateDb, STATE_BFD_SESSION_TABLE_NAME); + gDirectory.set(gBfdMonitorOrch); const vector chassis_frontend_tables = { CFG_PASS_THROUGH_ROUTE_TABLE_NAME, @@ -471,7 +474,7 @@ bool OrchDaemon::init() * when iterating ConsumerMap. This is ensured implicitly by the order of keys in ordered map. * For cases when Orch has to process tables in specific order, like PortsOrch during warm start, it has to override Orch::doTask() */ - m_orchList = { gSwitchOrch, gCrmOrch, gPortsOrch, gBufferOrch, gFlowCounterRouteOrch, gIntfsOrch, gNeighOrch, gNhgMapOrch, gNhgOrch, gCbfNhgOrch, gFgNhgOrch, gRouteOrch, gCoppOrch, gQosOrch, wm_orch, gPolicerOrch, gTunneldecapOrch, sflow_orch, gDebugCounterOrch, gMacsecOrch, bgp_global_state_orch, gBfdOrch, gIcmpOrch, gSrv6Orch, gMuxOrch, mux_cb_orch, gMonitorOrch, gStpOrch}; + m_orchList = { gSwitchOrch, gCrmOrch, gPortsOrch, gBufferOrch, gFlowCounterRouteOrch, gIntfsOrch, gNeighOrch, gNhgMapOrch, gNhgOrch, gCbfNhgOrch, gFgNhgOrch, gRouteOrch, gCoppOrch, gQosOrch, wm_orch, gPolicerOrch, gTunneldecapOrch, sflow_orch, gDebugCounterOrch, gMacsecOrch, bgp_global_state_orch, gBfdOrch, gIcmpOrch, gSrv6Orch, gMuxOrch, mux_cb_orch, gMonitorOrch, gBfdMonitorOrch, gStpOrch}; bool initialize_dtel = false; if (platform == BFN_PLATFORM_SUBSTRING || platform == VS_PLATFORM_SUBSTRING) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index d7403da4028..cf5a8739aac 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -778,7 +778,7 @@ bool VNetRouteOrch::addNextHopGroup(const string& vnet, const NextHopGroupKey &n for (auto it : next_hop_set) { nh_seq_id_in_nhgrp[it] = ++seq_id; - if (monitoring != "custom" && nexthop_info_[vnet].find(it.ip_address) != nexthop_info_[vnet].end() && nexthop_info_[vnet][it.ip_address].bfd_state != SAI_BFD_SESSION_STATE_UP) + if (monitoring != VNET_MONITORING_TYPE_CUSTOM && monitoring != VNET_MONITORING_TYPE_CUSTOM_BFD && nexthop_info_[vnet].find(it.ip_address) != nexthop_info_[vnet].end() && nexthop_info_[vnet][it.ip_address].bfd_state != SAI_BFD_SESSION_STATE_UP) { continue; } @@ -960,7 +960,7 @@ bool VNetRouteOrch::createNextHopGroup(const string& vnet, next_hop_group_entry.ref_count = 0; } - if (monitoring == "custom" || nexthop_info_[vnet].find(nexthop.ip_address) == nexthop_info_[vnet].end() || nexthop_info_[vnet][nexthop.ip_address].bfd_state == SAI_BFD_SESSION_STATE_UP) + if (monitoring == VNET_MONITORING_TYPE_CUSTOM || monitoring == VNET_MONITORING_TYPE_CUSTOM_BFD || nexthop_info_[vnet].find(nexthop.ip_address) == nexthop_info_[vnet].end() || nexthop_info_[vnet][nexthop.ip_address].bfd_state == SAI_BFD_SESSION_STATE_UP) { SWSS_LOG_INFO("Adding nexthop: %s to the active group", nexthop.ip_address.to_string().c_str()); next_hop_group_entry.active_members[nexthop] = SAI_NULL_OBJECT_ID; @@ -997,12 +997,18 @@ NextHopGroupKey VNetRouteOrch::getActiveNHSet(const string& vnet, { if (monitor.second.endpoint == it) { - if (monitor.second.state == MONITOR_SESSION_STATE_UP) + if (monitor.second.monitoring_type == VNET_MONITORING_TYPE_CUSTOM && monitor.second.state == MONITOR_SESSION_STATE_UP) { // monitor session exists and is up nhg_custom.add(it); } + + if (monitor.second.monitoring_type == VNET_MONITORING_TYPE_CUSTOM_BFD && monitor.second.custom_bfd_state == SAI_BFD_SESSION_STATE_UP) + { + // BFD session exists and is up + nhg_custom.add(it); + } continue; } } @@ -1030,7 +1036,8 @@ bool VNetRouteOrch::selectNextHopGroup(const string& vnet, // depending on the endpoint monitor state. If no NHG from primary is created, we attempt // the same for secondary. - if(nexthops_secondary.getSize() != 0 && monitoring == "custom") + if(nexthops_secondary.getSize() != 0 && + (monitoring == VNET_MONITORING_TYPE_CUSTOM || monitoring == VNET_MONITORING_TYPE_CUSTOM_BFD)) { auto it_route = syncd_tunnel_routes_[vnet].find(ipPrefix); if (it_route == syncd_tunnel_routes_[vnet].end()) @@ -1240,11 +1247,11 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP bool priority_route_updated = false; if (it_route != syncd_tunnel_routes_[vnet].end() && ((monitoring == "" && it_route->second.nhg_key != nexthops) || - (monitoring == "custom" && (it_route->second.primary != nexthops || it_route->second.secondary != nexthops_secondary)))) + ((monitoring == VNET_MONITORING_TYPE_CUSTOM || monitoring == VNET_MONITORING_TYPE_CUSTOM_BFD) && (it_route->second.primary != nexthops || it_route->second.secondary != nexthops_secondary)))) { route_updated = true; NextHopGroupKey nhg = it_route->second.nhg_key; - if (monitoring == "custom") + if (monitoring == VNET_MONITORING_TYPE_CUSTOM || monitoring == VNET_MONITORING_TYPE_CUSTOM_BFD) { // if the previously active NHG is same as the newly created active NHG.case of primary secondary swap or //when primary is active and secondary is changed or vice versa. In these cases we dont remove the NHG @@ -1284,7 +1291,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP } } } - if (monitoring != "custom") + if (monitoring != VNET_MONITORING_TYPE_CUSTOM && monitoring != VNET_MONITORING_TYPE_CUSTOM_BFD) { delEndpointMonitor(vnet, nhg, ipPrefix); } @@ -2057,9 +2064,7 @@ void VNetRouteOrch::removeBfdSession(const string& vnet, const NextHopKey& endpo nexthop_info_[vnet].erase(endpoint_addr); string key = "default:default:" + monitor_addr.to_string(); - bfd_session_producer_.del(key); - bfd_sessions_.erase(monitor_addr); } @@ -2118,6 +2123,58 @@ void VNetRouteOrch::createMonitoringSession(const string& vnet, const NextHopKey } +void VNetRouteOrch::createCustomBFDMonitoringSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& monitor_addr, IpPrefix& ipPrefix, const int32_t rx_monitor_timer, const int32_t tx_monitor_timer) +{ + SWSS_LOG_ENTER(); + + if (bfd_sessions_.find(monitor_addr) == bfd_sessions_.end()) + { + vector data; + string key = "default:default:" + monitor_addr.to_string(); + + auto tun_name = vnet_orch_->getTunnelName(vnet); + VxlanTunnelOrch* vxlan_orch = gDirectory.get(); + auto tunnel_obj = vxlan_orch->getVxlanTunnel(tun_name); + /* + Even for local endpoints, we will use tunnel source IP as local_addr of BFD session. + */ + IpAddress src_ip = tunnel_obj->getSrcIP(); + + FieldValueTuple fvTuple("local_addr", src_ip.to_string()); + data.push_back(fvTuple); + data.emplace_back("multihop", "true"); + // The BFD sessions established by the Vnet routes with monitoring need to be brought down + // when the device goes into TSA. The following parameter ensures that these session are + // brought down while transitioning to TSA and brought back up when transitioning to TSB. + data.emplace_back("shutdown_bfd_during_tsa", "true"); + + if (rx_monitor_timer >= 0) + { + FieldValueTuple fv_rx("rx_interval", to_string(rx_monitor_timer)); + data.push_back(fv_rx); + } + + if (tx_monitor_timer >= 0) + { + FieldValueTuple fv_tx("tx_interval", to_string(tx_monitor_timer)); + data.push_back(fv_tx); + } + + bfd_session_producer_.set(key, data); + bfd_sessions_[monitor_addr].bfd_state = SAI_BFD_SESSION_STATE_DOWN; + bfd_sessions_[monitor_addr].vnet = vnet; + bfd_sessions_[monitor_addr].endpoint = endpoint; + bfd_sessions_[monitor_addr].custom_bfd = true; + } + + MonitorSessionInfo info = monitor_info_[vnet][ipPrefix][monitor_addr]; + info.endpoint = endpoint; + info.ref_count = 1; + info.monitoring_type = VNET_MONITORING_TYPE_CUSTOM_BFD; + info.custom_bfd_state = SAI_BFD_SESSION_STATE_DOWN; + monitor_info_[vnet][ipPrefix][monitor_addr] = info; +} + void VNetRouteOrch::removeMonitoringSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& monitor_addr, IpPrefix& ipPrefix) { SWSS_LOG_ENTER(); @@ -2128,9 +2185,18 @@ void VNetRouteOrch::removeMonitoringSession(const string& vnet, const NextHopKey SWSS_LOG_NOTICE("Monitor session for prefix %s endpoint %s does not exist", ipPrefix.to_string().c_str(), endpoint.to_string().c_str()); } - string key = monitor_addr.to_string() + ":" + ipPrefix.to_string(); + if (monitor_info_[vnet][ipPrefix][monitor_addr].monitoring_type == VNET_MONITORING_TYPE_CUSTOM_BFD) + { + string key = "default:default:" + monitor_addr.to_string(); + bfd_session_producer_.del(key); + bfd_sessions_.erase(monitor_addr); + } + else + { + string key = monitor_addr.to_string() + ":" + ipPrefix.to_string(); + monitor_session_producer_->del(key); + } - monitor_session_producer_->del(key); monitor_info_[vnet][ipPrefix].erase(monitor_addr); } @@ -2145,12 +2211,24 @@ void VNetRouteOrch::setEndpointMonitor(const string& vnet, const map next_hop_set = nexthops.getNextHops(); if (next_hop_set.find(nh) != next_hop_set.end()) { - if (monitoring == "custom") + if (!monitoring.empty()) { if (monitor_info_[vnet].find(ipPrefix) == monitor_info_[vnet].end() || monitor_info_[vnet][ipPrefix].find(monitor_ip) == monitor_info_[vnet][ipPrefix].end()) { - createMonitoringSession(vnet, nh, monitor_ip, ipPrefix); + if (monitoring == VNET_MONITORING_TYPE_CUSTOM) + { + createMonitoringSession(vnet, nh, monitor_ip, ipPrefix); + } + else if (monitoring == VNET_MONITORING_TYPE_CUSTOM_BFD) + { + /* + * Current BFD monitoring doesn't support the failover between primary and secondary NHG. + * To avoid the complexity/regression, we temporarily introduce custom_bfd monitoring type. + * It will be same behavior as custom monitoring type, except that it will create BFD session. + */ + createCustomBFDMonitoringSession(vnet, nh, monitor_ip, ipPrefix, rx_monitor_timer, tx_monitor_timer); + } } else { @@ -2168,6 +2246,11 @@ void VNetRouteOrch::setEndpointMonitor(const string& vnet, const mapsecond; + bfd_info.bfd_state = sai_state; + string vnet = bfd_info.vnet; + NextHopKey endpoint = bfd_info.endpoint; + + if (monitor_info_.find(vnet) == monitor_info_.end()) + { + SWSS_LOG_WARN("No custom monitoring session info for vnet %s", vnet.c_str()); + return; + } + + for (auto iter : monitor_info_[vnet]) + { + auto prefix = iter.first; + if (monitor_info_[vnet][prefix].find(monitoring_ip) != monitor_info_[vnet][prefix].end() && + monitor_info_[vnet][prefix][monitoring_ip].endpoint == endpoint) + { + if ((sai_state == SAI_BFD_SESSION_STATE_UP || sai_state == SAI_BFD_SESSION_STATE_DOWN) && + monitor_info_[vnet][prefix][monitoring_ip].custom_bfd_state != sai_state) + { + SWSS_LOG_NOTICE("Custom BFD Monitor session state for %s:%s, endpoint:%s, monitoring_ip:%s changed to %s", + vnet.c_str(), + prefix.to_string().c_str(), + endpoint.ip_address.to_string().c_str(), + monitoring_ip.to_string().c_str(), + state.c_str()); + + struct MonitorUpdate status_update; + status_update.monitoring_type = VNET_MONITORING_TYPE_CUSTOM_BFD; + status_update.custom_bfd_state = sai_state; + status_update.prefix = prefix; + status_update.monitor = monitoring_ip; + status_update.vnet = vnet; + updateVnetTunnelCustomMonitor(status_update); + } + } + } +} + void VNetRouteOrch::updateMonitorState(string& op, const IpPrefix& prefix, const IpAddress& monitor, string state) { SWSS_LOG_ENTER(); @@ -2414,6 +2562,13 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update) } BfdSessionInfo& bfd_info = it_peer->second; + + if (bfd_info.custom_bfd) + { + SWSS_LOG_DEBUG("Skip single NHG BFD state update for custom BFD session %s", peer_address.to_string().c_str()); + return; + } + bfd_info.bfd_state = state; string vnet = bfd_info.vnet; @@ -2627,21 +2782,32 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) // MONITOR_SESSION_STATE_UNKNOWN and config_update and updateRoute are set to true. // This function should never recieve MONITOR_SESSION_STATE_UNKNOWN from MonitorOrch. + auto monitoring_type = update.monitoring_type; + auto custom_bfd_state = update.custom_bfd_state; auto prefix = update.prefix; auto state = update.state; auto monitor = update.monitor; auto vnet = update.vnet; bool updateRoute = false; bool config_update = false; - if (state != MONITOR_SESSION_STATE_UNKNOWN) + + if (monitoring_type == VNET_MONITORING_TYPE_CUSTOM) { - monitor_info_[vnet][prefix][monitor].state = state; + if (state != MONITOR_SESSION_STATE_UNKNOWN) + { + monitor_info_[vnet][prefix][monitor].state = state; + } + else + { + // we are coming here as a result of route config update. We need to repost the route if applicable. + updateRoute = true; + config_update = true; + } } - else + + if(monitoring_type == VNET_MONITORING_TYPE_CUSTOM_BFD) { - // we are coming here as a result of route config update. We need to repost the route if applicable. - updateRoute = true; - config_update = true; + monitor_info_[vnet][prefix][monitor].custom_bfd_state = custom_bfd_state; } auto route = syncd_tunnel_routes_[vnet].find(prefix); @@ -2678,7 +2844,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) { if (!hasNextHopGroup(vnet, nhg_custom_primary)) { - if (!createNextHopGroup(vnet, nhg_custom_primary, vrf_obj, "custom")) + if (!createNextHopGroup(vnet, nhg_custom_primary, vrf_obj, monitoring_type)) { SWSS_LOG_WARN("Failed to create primary based custom next hop group. Cannot proceed."); return; @@ -2697,9 +2863,9 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update) { if (!hasNextHopGroup(vnet, nhg_custom_secondary)) { - if (!createNextHopGroup(vnet, nhg_custom_secondary, vrf_obj, "custom")) + if (!createNextHopGroup(vnet, nhg_custom_secondary, vrf_obj, monitoring_type)) { - SWSS_LOG_WARN("Failed to create primary based custom next hop group. Cannot proceed."); + SWSS_LOG_WARN("Failed to create secondary based custom next hop group. Cannot proceed."); return; } } @@ -3274,7 +3440,7 @@ bool MonitorOrch::addOperation(const Request& request) string op = SET_COMMAND; VNetRouteOrch* vnet_route_orch = gDirectory.get(); - vnet_route_orch->updateMonitorState(op ,ip_Prefix, monitor, session_state ); + vnet_route_orch->updateMonitorState(op, ip_Prefix, monitor, session_state); return true; } @@ -3293,6 +3459,35 @@ bool MonitorOrch::delOperation(const Request& request) return true; } +BfdMonitorOrch::BfdMonitorOrch(DBConnector *db, std::string tableName): + Orch2(db, tableName, request_) +{ + SWSS_LOG_ENTER(); +} + +BfdMonitorOrch::~BfdMonitorOrch(void) +{ + SWSS_LOG_ENTER(); +} + +bool BfdMonitorOrch::addOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + auto monitor = request.getKeyIpAddress(2); + auto session_state = request.getAttrString("state"); + + VNetRouteOrch* vnet_route_orch = gDirectory.get(); + vnet_route_orch->updateCustomBfdState(monitor, session_state); + + return true; +} + +bool BfdMonitorOrch::delOperation(const Request& request) +{ + return true; +} + VNetTunnelTermAcl::VNetTunnelTermAcl(DBConnector *cfgDb, DBConnector *appDb) { SWSS_LOG_ENTER(); @@ -3442,3 +3637,4 @@ bool VNetTunnelTermAcl::getAclRule(const string vnet_name, const swss::IpPrefix& return false; } + diff --git a/orchagent/vnetorch.h b/orchagent/vnetorch.h index 5cd38b89ac9..f51ad970976 100644 --- a/orchagent/vnetorch.h +++ b/orchagent/vnetorch.h @@ -24,6 +24,9 @@ #define VXLAN_ENCAP_TTL 128 #define VNET_BITMAP_RIF_MTU 9100 +#define VNET_MONITORING_TYPE_CUSTOM "custom" +#define VNET_MONITORING_TYPE_CUSTOM_BFD "custom_bfd" + extern sai_object_id_t gVirtualRouterId; @@ -325,6 +328,22 @@ const request_description_t monitor_state_request_description = { { "state" } }; +const request_description_t custom_bfd_request_description = { + { REQ_T_STRING, REQ_T_STRING, REQ_T_IP, }, + { + { "type", REQ_T_STRING }, + { "async_active", REQ_T_STRING }, + { "local_discriminator", REQ_T_STRING }, + { "local_addr", REQ_T_IP }, + { "tx_interval", REQ_T_UINT }, + { "rx_interval", REQ_T_UINT }, + { "multiplier", REQ_T_UINT }, + { "multihop", REQ_T_BOOL }, + { "state", REQ_T_STRING }, + }, + { } +}; + class MonitorStateRequest : public Request { public: @@ -344,6 +363,25 @@ class MonitorOrch : public Orch2 MonitorStateRequest request_; }; +class CustomBfdRequest : public Request +{ +public: + CustomBfdRequest() : Request(custom_bfd_request_description, '|') { } +}; + +class BfdMonitorOrch : public Orch2 +{ +public: + BfdMonitorOrch(swss::DBConnector *db, std::string tableName); + virtual ~BfdMonitorOrch(void); + +private: + virtual bool addOperation(const Request& request); + virtual bool delOperation(const Request& request); + + CustomBfdRequest request_; +}; + class VNetRouteRequest : public Request { public: @@ -382,10 +420,14 @@ struct BfdSessionInfo sai_bfd_session_state_t bfd_state; std::string vnet; NextHopKey endpoint; + + bool custom_bfd = false; }; struct MonitorSessionInfo { + std::string monitoring_type = VNET_MONITORING_TYPE_CUSTOM; + sai_bfd_session_state_t custom_bfd_state; monitor_session_state_t state; NextHopKey endpoint; int ref_count; @@ -393,6 +435,8 @@ struct MonitorSessionInfo struct MonitorUpdate { + std::string monitoring_type = VNET_MONITORING_TYPE_CUSTOM; + sai_bfd_session_state_t custom_bfd_state; monitor_session_state_t state; IpAddress monitor; IpPrefix prefix; @@ -460,6 +504,7 @@ class VNetRouteOrch : public Orch2, public Subject, public Observer void update(SubjectType, void *); void updateMonitorState(string& op, const IpPrefix& prefix , const IpAddress& endpoint, string state); + void updateCustomBfdState(const IpAddress& monitoring_ip, const string& state); void updateAllMonitoringSession(const string& vnet); private: @@ -487,6 +532,7 @@ class VNetRouteOrch : public Orch2, public Subject, public Observer void createBfdSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& ipAddr, const int32_t rx_monitor_timer, const int32_t tx_monitor_timer); void removeBfdSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& ipAddr); + void createCustomBFDMonitoringSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& monitor_addr, IpPrefix& ipPrefix, const int32_t rx_monitor_timer, const int32_t tx_monitor_timer); void createMonitoringSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& ipAddr, IpPrefix& ipPrefix); void removeMonitoringSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& ipAddr, IpPrefix& ipPrefix); void setEndpointMonitor(const string& vnet, const map& monitors, NextHopGroupKey& nexthops, diff --git a/tests/test_vnet.py b/tests/test_vnet.py index 3a8f6435183..9d68d9e4cbe 100644 --- a/tests/test_vnet.py +++ b/tests/test_vnet.py @@ -3112,57 +3112,161 @@ def test_vnet_local_route_ecmp(self, dvs, testlog): delete_vxlan_tunnel(dvs, tunnel_name) vnet_obj.check_del_vxlan_tunnel(dvs) + ''' - Test 32 - Test for priority vnet tunnel routes with local endpoint + bfd monitoring + rx and tx timer. + Test 32 - Test for priority vnet tunnel routes with ECMP nexthop group and local nhg. test primary secondary switchover + bfd monitoring + rx and tx timer. ''' - def test_vnet_orch_30(self, dvs, dvs_acl, testlog): + def test_vnet_orch_32(self, dvs, testlog): self.setup_db(dvs) - self.clear_srv_config(dvs) vnet_obj = self.get_vnet_obj() tunnel_name = 'tunnel_32' - vnet_name = 'Vnet32' + vnet_name = 'vnet32' asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) vnet_obj.fetch_exist_entries(dvs) create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') - create_vnet_entry(dvs, vnet_name, tunnel_name, '10028', "", advertise_prefix=True, overlay_dmac="22:33:33:44:44:66") + create_vnet_entry(dvs, vnet_name, tunnel_name, '10029', "", advertise_prefix=True, overlay_dmac="22:33:33:44:44:66") vnet_obj.check_vnet_entry(dvs, vnet_name) - vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '10028') + vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '10029') + vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') # create l3 interface self.create_l3_intf("Ethernet8", "") + self.create_l3_intf("Ethernet12", "") # set ip address - self.add_ip_address("Ethernet8", "9.1.0.1/32") + self.add_ip_address("Ethernet8", "9.1.0.3/32") + self.add_ip_address("Ethernet12", "9.1.0.4/32") # bring up interface self.set_admin_status("Ethernet8", "up") + self.set_admin_status("Ethernet12", "up") # add neighbor for directly connected endpoint - self.add_neighbor("Ethernet8", "9.1.0.1", "00:01:02:03:04:05") + self.add_neighbor("Ethernet8", "9.1.0.3", "00:01:02:03:04:05") + self.add_neighbor("Ethernet12", "9.1.0.4", "00:01:02:03:04:06") vnet_obj.fetch_exist_entries(dvs) - create_vnet_routes(dvs, "100.100.1.1/32", vnet_name, '9.1.0.1,9.1.0.2', ep_monitor='9.1.0.1,9.1.0.2', primary ='9.1.0.1', profile="Test_profile", monitoring='', rx_monitor_timer=100, tx_monitor_timer=100, adv_prefix='100.100.1.0/24', check_directly_connected=True) + create_vnet_routes(dvs, "100.100.1.1/32", vnet_name, '9.1.0.1,9.1.0.2,9.1.0.3,9.1.0.4', ep_monitor='9.1.0.1,9.1.0.2,9.1.0.3,9.1.0.4', primary ='9.1.0.1,9.1.0.2', monitoring='custom_bfd', adv_prefix='100.100.1.0/24', check_directly_connected=True, rx_monitor_timer=100, tx_monitor_timer=100) + + # default monitor status is down, route should not be programmed in this status + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["100.100.1.1/32"]) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", []) + check_remove_routes_advertisement(dvs, "100.100.1.0/24") + + # Route should be properly configured when all monitor session states go up. Only primary Endpoints should be in use. + update_bfd_session_state(dvs, '9.1.0.1', 'Up') + update_bfd_session_state(dvs, '9.1.0.2', 'Up') + update_bfd_session_state(dvs, '9.1.0.3', 'Up') + update_bfd_session_state(dvs, '9.1.0.4', 'Up') + time.sleep(2) + route1 = vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.1.0.1','9.1.0.2'], tunnel_name) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.1','9.1.0.2']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") + + # Remove second primary endpoint from group. + update_bfd_session_state(dvs, '9.1.0.2', 'Down') + + time.sleep(2) + route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.1.0.1'], tunnel_name, route_ids=route1) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.1']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") + + # Switch to secondary if both primary down + update_bfd_session_state(dvs, '9.1.0.1', 'Down') + time.sleep(2) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.3','9.1.0.4']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") + + # removing first endpoint of secondary. route should remain on secondary NHG + update_bfd_session_state(dvs, '9.1.0.3', 'Down') + time.sleep(2) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.4']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") + + # removing last endpoint of secondary. route should be removed + update_bfd_session_state(dvs, '9.1.0.4', 'Down') + time.sleep(2) + + new_nhgs = get_all_created_entries(asic_db, vnet_obj.ASIC_NEXT_HOP_GROUP, []) + assert len(new_nhgs) == 0 + check_remove_routes_advertisement(dvs, "100.100.1.0/24") + vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["100.100.1.1/32"]) + check_remove_state_db_routes(dvs, vnet_name, "100.100.1.1/32") + + # Route should come up with secondary endpoints. + update_bfd_session_state(dvs, '9.1.0.3', 'Up') + update_bfd_session_state(dvs, '9.1.0.4', 'Up') + + time.sleep(2) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.3','9.1.0.4']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") + + #Route should be switched to the primary endpoint. + update_bfd_session_state(dvs, '9.1.0.1', 'Up') + time.sleep(2) + route1= vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.1.0.1'], tunnel_name, route_ids=route1) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.1']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") + + #Route should be updated with the second primary endpoint. + update_bfd_session_state(dvs, '9.1.0.2', 'Up') + time.sleep(2) + route1 = vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.1.0.1','9.1.0.2'], tunnel_name, route_ids=route1) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.1','9.1.0.2']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") + + #Route should not be impacted by seconday endpoints going down. + update_bfd_session_state(dvs, '9.1.0.3', 'Down') + update_bfd_session_state(dvs, '9.1.0.4', 'Down') + time.sleep(2) + route1 = vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.1.0.1','9.1.0.2'], tunnel_name, route_ids=route1) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.1','9.1.0.2']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") + + #Route should not be impacted by seconday endpoints coming back up. + update_bfd_session_state(dvs, '9.1.0.3', 'Up') + update_bfd_session_state(dvs, '9.1.0.4', 'Up') + time.sleep(2) + route1 = vnet_obj.check_priority_vnet_ecmp_routes(dvs, vnet_name, ['9.1.0.1','9.1.0.2'], tunnel_name, route_ids=route1) + check_state_db_routes(dvs, vnet_name, "100.100.1.1/32", ['9.1.0.1','9.1.0.2']) + # The default Vnet setting does not advertise prefix + check_routes_advertisement(dvs, "100.100.1.0/24") # Remove tunnel route 1 delete_vnet_routes(dvs, "100.100.1.1/32", vnet_name) - + time.sleep(2) vnet_obj.check_del_vnet_routes(dvs, vnet_name, ["100.100.1.1/32"]) check_remove_state_db_routes(dvs, vnet_name, "100.100.1.1/32") check_remove_routes_advertisement(dvs, "100.100.1.0/24") + # Confirm the monitor sessions are removed + check_del_bfd_session(dvs, ['9.1.0.1', '9.1.0.2', '9.1.0.3', '9.1.0.4']) + delete_vnet_entry(dvs, vnet_name) vnet_obj.check_del_vnet_entry(dvs, vnet_name) delete_vxlan_tunnel(dvs, tunnel_name) - self.remove_neighbor("Ethernet8", "9.1.0.1") - self.remove_ip_address("Ethernet8", "9.1.0.1/32") + self.remove_neighbor("Ethernet8", "9.1.0.3") + self.remove_ip_address("Ethernet8", "9.1.0.3/32") self.set_admin_status("Ethernet8", "down") + self.remove_neighbor("Ethernet12", "9.1.0.4") + self.remove_ip_address("Ethernet12", "9.1.0.4/32") + self.set_admin_status("Ethernet12", "down") + # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying def test_nonflaky_dummy():