From 34e89ba96113d3ad1995d2218122014dd6d7c008 Mon Sep 17 00:00:00 2001 From: Jing Zhang Date: Tue, 25 Nov 2025 01:50:51 +0800 Subject: [PATCH 1/2] [vnetorch] missing handling of rx and tx interval of monitoring session (#3878) What I did Adding rx_monitor_timer and tx_monitor_timer handling per HLD: https://github.com/sonic-net/SONiC/blob/master/doc/vxlan/Overlay%20ECMP%20ehancements.md sign-off: Jing Zhang zhangjing@microsoft.com Why I did it It's needed for SSW HA scenario as DPU side bfd is a software solution, interval must be set to a reasonable value. Signed-off-by: Jing Zhang --- orchagent/vnetorch.cpp | 50 ++++++++++++++++++++++++++++++--------- orchagent/vnetorch.h | 12 ++++++---- tests/test_vnet.py | 53 +++++++++++++++++++++++++++++++++++++++++- tests/vnet_lib.py | 12 +++++++--- 4 files changed, 108 insertions(+), 19 deletions(-) diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 89e98c31a67..c5128b2439a 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -1015,6 +1015,8 @@ bool VNetRouteOrch::selectNextHopGroup(const string& vnet, NextHopGroupKey& nexthops_primary, NextHopGroupKey& nexthops_secondary, const string& monitoring, + const int32_t rx_monitor_timer, + const int32_t tx_monitor_timer, IpPrefix& ipPrefix, VNetVrfObject *vrf_obj, NextHopGroupKey& nexthops_selected, @@ -1033,18 +1035,18 @@ bool VNetRouteOrch::selectNextHopGroup(const string& vnet, auto it_route = syncd_tunnel_routes_[vnet].find(ipPrefix); if (it_route == syncd_tunnel_routes_[vnet].end()) { - setEndpointMonitor(vnet, monitors, nexthops_primary, monitoring, ipPrefix); - setEndpointMonitor(vnet, monitors, nexthops_secondary, monitoring, ipPrefix); + setEndpointMonitor(vnet, monitors, nexthops_primary, monitoring, rx_monitor_timer, tx_monitor_timer, ipPrefix); + setEndpointMonitor(vnet, monitors, nexthops_secondary, monitoring, rx_monitor_timer, tx_monitor_timer, ipPrefix); } else { if (it_route->second.primary != nexthops_primary) { - setEndpointMonitor(vnet, monitors, nexthops_primary, monitoring, ipPrefix); + setEndpointMonitor(vnet, monitors, nexthops_primary, monitoring, rx_monitor_timer, tx_monitor_timer, ipPrefix); } if (it_route->second.secondary != nexthops_secondary) { - setEndpointMonitor(vnet, monitors, nexthops_secondary, monitoring, ipPrefix); + setEndpointMonitor(vnet, monitors, nexthops_secondary, monitoring, rx_monitor_timer, tx_monitor_timer, ipPrefix); } nexthops_selected = it_route->second.nhg_key; return true; @@ -1103,7 +1105,7 @@ bool VNetRouteOrch::selectNextHopGroup(const string& vnet, else if (!hasNextHopGroup(vnet, nexthops_primary)) { SWSS_LOG_INFO("Creating next hop group %s", nexthops_primary.to_string().c_str()); - setEndpointMonitor(vnet, monitors, nexthops_primary, monitoring, ipPrefix); + setEndpointMonitor(vnet, monitors, nexthops_primary, monitoring, rx_monitor_timer, tx_monitor_timer, ipPrefix); if (!createNextHopGroup(vnet, nexthops_primary, vrf_obj, monitoring)) { delEndpointMonitor(vnet, nexthops_primary, ipPrefix); @@ -1117,7 +1119,10 @@ bool VNetRouteOrch::selectNextHopGroup(const string& vnet, template<> bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipPrefix, NextHopGroupKey& nexthops, string& op, string& profile, - const string& monitoring, NextHopGroupKey& nexthops_secondary, + const string& monitoring, + const int32_t rx_monitor_timer, + const int32_t tx_monitor_timer, + NextHopGroupKey& nexthops_secondary, const IpPrefix& adv_prefix, const map& monitors) { @@ -1158,7 +1163,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP { sai_object_id_t nh_id = SAI_NULL_OBJECT_ID; NextHopGroupKey active_nhg("", true); - if (!selectNextHopGroup(vnet, nexthops, nexthops_secondary, monitoring, ipPrefix, vrf_obj, active_nhg, monitors)) + if (!selectNextHopGroup(vnet, nexthops, nexthops_secondary, monitoring, rx_monitor_timer, tx_monitor_timer, ipPrefix, vrf_obj, active_nhg, monitors)) { return true; } @@ -1981,7 +1986,7 @@ void VNetRouteOrch::delRoute(const IpPrefix& ipPrefix) syncd_routes_.erase(route_itr); } -void VNetRouteOrch::createBfdSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& monitor_addr) +void VNetRouteOrch::createBfdSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& monitor_addr, const int32_t rx_monitor_timer, const int32_t tx_monitor_timer) { SWSS_LOG_ENTER(); @@ -2012,6 +2017,19 @@ void VNetRouteOrch::createBfdSession(const string& vnet, const NextHopKey& endpo // 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; } @@ -2116,7 +2134,7 @@ void VNetRouteOrch::removeMonitoringSession(const string& vnet, const NextHopKey monitor_info_[vnet][ipPrefix].erase(monitor_addr); } -void VNetRouteOrch::setEndpointMonitor(const string& vnet, const map& monitors, NextHopGroupKey& nexthops, const string& monitoring, IpPrefix& ipPrefix) +void VNetRouteOrch::setEndpointMonitor(const string& vnet, const map& monitors, NextHopGroupKey& nexthops, const string& monitoring, const int32_t rx_monitor_timer, const int32_t tx_monitor_timer, IpPrefix& ipPrefix) { SWSS_LOG_ENTER(); @@ -2145,7 +2163,7 @@ void VNetRouteOrch::setEndpointMonitor(const string& vnet, const map primary_list; vector secondary_list; string monitoring; + int32_t rx_monitor_timer = -1; + int32_t tx_monitor_timer = -1; swss::IpPrefix adv_prefix; bool has_priority_ep = false; bool has_adv_pfx = false; @@ -2910,6 +2930,14 @@ bool VNetRouteOrch::handleTunnel(const Request& request) { check_directly_connected = request.getAttrBool(name); } + else if (name == "rx_monitor_timer") + { + rx_monitor_timer = static_cast(request.getAttrUint(name)); + } + else if (name == "tx_monitor_timer") + { + tx_monitor_timer = static_cast(request.getAttrUint(name)); + } else { SWSS_LOG_INFO("Unknown attribute: %s", name.c_str()); @@ -3045,7 +3073,7 @@ bool VNetRouteOrch::handleTunnel(const Request& request) } if (vnet_orch_->isVnetExecVrf()) { - return doRouteTask(vnet_name, ip_pfx, (has_priority_ep == true) ? nhg_primary : nhg, op, profile, monitoring, nhg_secondary, adv_prefix, monitors); + return doRouteTask(vnet_name, ip_pfx, (has_priority_ep == true) ? nhg_primary : nhg, op, profile, monitoring, rx_monitor_timer, tx_monitor_timer, nhg_secondary, adv_prefix, monitors); } return true; diff --git a/orchagent/vnetorch.h b/orchagent/vnetorch.h index ab7b6dfa9bf..5cd38b89ac9 100644 --- a/orchagent/vnetorch.h +++ b/orchagent/vnetorch.h @@ -311,6 +311,8 @@ const request_description_t vnet_route_description = { { "monitoring", REQ_T_STRING }, { "adv_prefix", REQ_T_IP_PREFIX }, { "check_directly_connected", REQ_T_BOOL }, + { "rx_monitor_timer", REQ_T_UINT }, + { "tx_monitor_timer", REQ_T_UINT }, }, { } }; @@ -479,16 +481,17 @@ class VNetRouteOrch : public Orch2, public Subject, public Observer const string& monitoring); NextHopGroupKey getActiveNHSet(const string&, NextHopGroupKey&, const IpPrefix& ); - bool selectNextHopGroup(const string&, NextHopGroupKey&, NextHopGroupKey&, const string&, IpPrefix&, + bool selectNextHopGroup(const string&, NextHopGroupKey&, NextHopGroupKey&, const string&, const int32_t, const int32_t, IpPrefix&, VNetVrfObject *vrf_obj, NextHopGroupKey&, const std::map& monitors=std::map()); - void createBfdSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& ipAddr); + 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 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, - const string& monitoring, IpPrefix& ipPrefix); + const string& monitoring, const int32_t rx_monitor_timer, const int32_t tx_monitor_timer, + IpPrefix& ipPrefix); void delEndpointMonitor(const string& vnet, NextHopGroupKey& nexthops, IpPrefix& ipPrefix); void postRouteState(const string& vnet, IpPrefix& ipPrefix, NextHopGroupKey& nexthops, string& profile); void removeRouteState(const string& vnet, IpPrefix& ipPrefix); @@ -506,7 +509,8 @@ class VNetRouteOrch : public Orch2, public Subject, public Observer template bool doRouteTask(const string& vnet, IpPrefix& ipPrefix, NextHopGroupKey& nexthops, string& op, string& profile, - const string& monitoring, NextHopGroupKey& nexthops_secondary, const IpPrefix& adv_prefix, + const string& monitoring, const int32_t rx_monitor_timer, const int32_t tx_monitor_timer, + NextHopGroupKey& nexthops_secondary, const IpPrefix& adv_prefix, const std::map& monitors=std::map()); template diff --git a/tests/test_vnet.py b/tests/test_vnet.py index 51beed43949..950c9e65ccd 100644 --- a/tests/test_vnet.py +++ b/tests/test_vnet.py @@ -3120,7 +3120,58 @@ 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. + ''' + def test_vnet_orch_30(self, dvs, dvs_acl, testlog): + self.setup_db(dvs) + self.clear_srv_config(dvs) + + vnet_obj = self.get_vnet_obj() + tunnel_name = 'tunnel_32' + 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") + + 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(dvs, tunnel_name, '9.9.9.9') + + # create l3 interface + self.create_l3_intf("Ethernet8", "") + + # set ip address + self.add_ip_address("Ethernet8", "9.1.0.1/32") + + # bring up interface + self.set_admin_status("Ethernet8", "up") + + # add neighbor for directly connected endpoint + self.add_neighbor("Ethernet8", "9.1.0.1", "00:01:02:03:04:05") + + 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) + + # Remove tunnel route 1 + delete_vnet_routes(dvs, "100.100.1.1/32", vnet_name) + + 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") + + 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.set_admin_status("Ethernet8", "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(): - pass + pass \ No newline at end of file diff --git a/tests/vnet_lib.py b/tests/vnet_lib.py index 81f23b321ab..2eb0162194c 100644 --- a/tests/vnet_lib.py +++ b/tests/vnet_lib.py @@ -140,11 +140,11 @@ def delete_vnet_local_routes(dvs, prefix, vnet_name): time.sleep(2) -def create_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", adv_prefix="", check_directly_connected=False): - set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac=mac, vni=vni, ep_monitor=ep_monitor, profile=profile, primary=primary, monitoring=monitoring, adv_prefix=adv_prefix, check_directly_connected=check_directly_connected) +def create_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", rx_monitor_timer=-1, tx_monitor_timer=-1, adv_prefix="", check_directly_connected=False): + set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac=mac, vni=vni, ep_monitor=ep_monitor, profile=profile, primary=primary, monitoring=monitoring, rx_monitor_timer=rx_monitor_timer, tx_monitor_timer=tx_monitor_timer, adv_prefix=adv_prefix, check_directly_connected=check_directly_connected) -def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", adv_prefix="", check_directly_connected=False): +def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", rx_monitor_timer=-1, tx_monitor_timer=-1, adv_prefix="", check_directly_connected=False): conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) attrs = [ @@ -175,6 +175,12 @@ def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor= if check_directly_connected: attrs.append(('check_directly_connected', 'true')) + if rx_monitor_timer != -1: + attrs.append(('rx_monitor_timer', str(rx_monitor_timer))) + + if tx_monitor_timer != -1: + attrs.append(('tx_monitor_timer', str(tx_monitor_timer))) + tbl = swsscommon.Table(conf_db, "VNET_ROUTE_TUNNEL") fvs = swsscommon.FieldValuePairs(attrs) tbl.set("%s|%s" % (vnet_name, prefix), fvs) From 56078b327d1a5b8a03e02a54e99da927c27154f1 Mon Sep 17 00:00:00 2001 From: Jing Zhang Date: Tue, 9 Dec 2025 09:27:45 +0800 Subject: [PATCH 2/2] [ssw][ha] introducing `custom_bfd` and BfdMonitorOrch to support primary/secondary NHG switchover (#3922) What I did Today vnetorch only supports: custom monitoring sessions with primary & secondary NHG. bfd monitoring with primary NHG only. To make HA work we need bfd monitoring to support primary+secondary. This PR is to introduce a new monitoring type custom_bfd for that purpose. It will: create bfd sessions for both primary & secondary endpoints listen on state db for bfd session state update ignore update call from bfdorch switch and update nhg based on bfd session state It's not an elegant design to introduce a new bfd monitoring type. But the intention is to not break current functionality of vnetorch. Refactor of the code will be needed in future. Signed-off-by: Jing Zhang --- orchagent/orchdaemon.cpp | 5 +- orchagent/vnetorch.cpp | 242 +++++++++++++++++++++++++++++++++++---- orchagent/vnetorch.h | 46 ++++++++ tests/test_vnet.py | 128 +++++++++++++++++++-- 4 files changed, 385 insertions(+), 36 deletions(-) diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 0502ccbeb50..8cc859ea698 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 c5128b2439a..f41c4af135d 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(); @@ -3448,3 +3643,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 950c9e65ccd..d9449f54255 100644 --- a/tests/test_vnet.py +++ b/tests/test_vnet.py @@ -3120,57 +3120,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():