diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index f23af282ce..484c1b96d5 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -425,6 +425,7 @@ bool VNetOrch::addOperation(const Request& request) uint32_t vni=0; string tunnel; string scope; + swss::MacAddress overlay_dmac; for (const auto& name: request.getAttrFieldNames()) { @@ -456,6 +457,10 @@ bool VNetOrch::addOperation(const Request& request) { advertise_prefix = request.getAttrBool("advertise_prefix"); } + else if (name == "overlay_dmac") + { + overlay_dmac = request.getAttrMacAddress("overlay_dmac"); + } else { SWSS_LOG_INFO("Unknown attribute: %s", name.c_str()); @@ -482,7 +487,7 @@ bool VNetOrch::addOperation(const Request& request) if (it == std::end(vnet_table_)) { - VNetInfo vnet_info = { tunnel, vni, peer_list, scope, advertise_prefix }; + VNetInfo vnet_info = { tunnel, vni, peer_list, scope, advertise_prefix, overlay_dmac }; obj = createObject(vnet_name, vnet_info, attrs); create = true; @@ -673,8 +678,11 @@ VNetRouteOrch::VNetRouteOrch(DBConnector *db, vector &tableNames, VNetOr handler_map_.insert(handler_pair(APP_VNET_RT_TUNNEL_TABLE_NAME, &VNetRouteOrch::handleTunnel)); state_db_ = shared_ptr(new DBConnector("STATE_DB", 0)); + app_db_ = shared_ptr(new DBConnector("APPL_DB", 0)); + state_vnet_rt_tunnel_table_ = unique_ptr(new Table(state_db_.get(), STATE_VNET_RT_TUNNEL_TABLE_NAME)); state_vnet_rt_adv_table_ = unique_ptr
(new Table(state_db_.get(), STATE_ADVERTISE_NETWORK_TABLE_NAME)); + monitor_session_producer_ = unique_ptr
(new Table(app_db_.get(), APP_VNET_MONITOR_TABLE_NAME)); gBfdOrch->attach(this); } @@ -843,6 +851,7 @@ bool VNetRouteOrch::removeNextHopGroup(const string& vnet, const NextHopGroupKey template<> bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipPrefix, NextHopGroupKey& nexthops, string& op, string& profile, + const string& monitoring, const map& monitors) { SWSS_LOG_ENTER(); @@ -883,7 +892,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP sai_object_id_t nh_id; if (!hasNextHopGroup(vnet, nexthops)) { - setEndpointMonitor(vnet, monitors, nexthops); + setEndpointMonitor(vnet, monitors, nexthops, monitoring, ipPrefix); if (nexthops.getSize() == 1) { NextHopKey nexthop(nexthops.to_string(), true); @@ -900,7 +909,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP { if (!addNextHopGroup(vnet, nexthops, vrf_obj)) { - delEndpointMonitor(vnet, nexthops); + delEndpointMonitor(vnet, nexthops, ipPrefix); SWSS_LOG_ERROR("Failed to create next hop group %s", nexthops.to_string().c_str()); return false; } @@ -974,7 +983,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP NextHopKey nexthop(nhg.to_string(), true); vrf_obj->removeTunnelNextHop(nexthop); } - delEndpointMonitor(vnet, nhg); + delEndpointMonitor(vnet, nhg, ipPrefix); } else { @@ -1034,7 +1043,7 @@ bool VNetRouteOrch::doRouteTask(const string& vnet, IpPrefix& ipP NextHopKey nexthop(nhg.to_string(), true); vrf_obj->removeTunnelNextHop(nexthop); } - delEndpointMonitor(vnet, nhg); + delEndpointMonitor(vnet, nhg, ipPrefix); } else { @@ -1552,7 +1561,55 @@ void VNetRouteOrch::removeBfdSession(const string& vnet, const NextHopKey& endpo bfd_sessions_.erase(monitor_addr); } -void VNetRouteOrch::setEndpointMonitor(const string& vnet, const map& monitors, NextHopGroupKey& nexthops) +void VNetRouteOrch::createMonitoringSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& monitor_addr, IpPrefix& ipPrefix) +{ + SWSS_LOG_ENTER(); + + IpAddress endpoint_addr = endpoint.ip_address; + if (monitor_info_[vnet].find(ipPrefix) != monitor_info_[vnet].end() && + monitor_info_[vnet][ipPrefix].find(endpoint) != monitor_info_[vnet][ipPrefix].end()) + { + SWSS_LOG_NOTICE("Monitoring session for prefix %s endpoint %s already exist", ipPrefix.to_string().c_str(), endpoint_addr.to_string().c_str()); + return; + } + else + { + vector data; + auto *vnet_obj = vnet_orch_->getTypePtr(vnet); + + auto overlay_dmac = vnet_obj->getOverlayDMac(); + string key = ipPrefix.to_string() + ":" + monitor_addr.to_string(); + FieldValueTuple fvTuple1("packet_type", "vxlan"); + data.push_back(fvTuple1); + + FieldValueTuple fvTuple3("overlay_dmac", overlay_dmac.to_string()); + data.push_back(fvTuple3); + + monitor_session_producer_->set(key, data); + + MonitorSessionInfo& info = monitor_info_[vnet][ipPrefix][endpoint]; + info.monitor = monitor_addr; + info.state = MONITOR_SESSION_STATE::MONITOR_SESSION_STATE_DOWN; + } +} + +void VNetRouteOrch::removeMonitoringSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& monitor_addr, IpPrefix& ipPrefix) +{ + SWSS_LOG_ENTER(); + + IpAddress endpoint_addr = endpoint.ip_address; + if (monitor_info_[vnet].find(ipPrefix) == monitor_info_[vnet].end() || + monitor_info_[vnet][ipPrefix].find(endpoint) == monitor_info_[vnet][ipPrefix].end()) + { + SWSS_LOG_NOTICE("Monitor session for prefix %s endpoint %s does not exist", ipPrefix.to_string().c_str(), endpoint_addr.to_string().c_str()); + } + + string key = ipPrefix.to_string() + ":" + monitor_addr.to_string(); + monitor_session_producer_->del(key); + monitor_info_[vnet][ipPrefix].erase(endpoint); +} + +void VNetRouteOrch::setEndpointMonitor(const string& vnet, const map& monitors, NextHopGroupKey& nexthops, const string& monitoring, IpPrefix& ipPrefix) { SWSS_LOG_ENTER(); @@ -1560,31 +1617,62 @@ void VNetRouteOrch::setEndpointMonitor(const string& vnet, const map nhks = nexthops.getNextHops(); + bool is_custom_monitoring = false; + if (monitor_info_[vnet].find(ipPrefix) != monitor_info_[vnet].end()) + { + is_custom_monitoring = true; + } for (auto nhk: nhks) { IpAddress ip = nhk.ip_address; - if (nexthop_info_[vnet].find(ip) != nexthop_info_[vnet].end()) { - if (--nexthop_info_[vnet][ip].ref_count == 0) + if (is_custom_monitoring) + { + if ( monitor_info_[vnet][ipPrefix].find(nhk) != monitor_info_[vnet][ipPrefix].end()) { - IpAddress monitor_addr = nexthop_info_[vnet][ip].monitor_addr; - removeBfdSession(vnet, nhk, monitor_addr); + removeMonitoringSession(vnet, nhk, monitor_info_[vnet][ipPrefix][nhk].monitor, ipPrefix); + } + } + else + { + if (nexthop_info_[vnet].find(ip) != nexthop_info_[vnet].end()) { + if (--nexthop_info_[vnet][ip].ref_count == 0) + { + IpAddress monitor_addr = nexthop_info_[vnet][ip].monitor_addr; + { + removeBfdSession(vnet, nhk, monitor_addr); + } + } } } } + if (is_custom_monitoring) + { + monitor_info_[vnet].erase(ipPrefix); + } } void VNetRouteOrch::postRouteState(const string& vnet, IpPrefix& ipPrefix, NextHopGroupKey& nexthops, string& profile) @@ -1845,7 +1933,9 @@ bool VNetRouteOrch::handleTunnel(const Request& request) vector vni_list; vector monitor_list; string profile = ""; - + vector primary_list; + string monitoring; + swss::IpPrefix adv_prefix; for (const auto& name: request.getAttrFieldNames()) { if (name == "endpoint") @@ -1870,6 +1960,18 @@ bool VNetRouteOrch::handleTunnel(const Request& request) { profile = request.getAttrString(name); } + else if (name == "primary") + { + primary_list = request.getAttrIPList(name); + } + else if (name == "monitoring") + { + monitoring = request.getAttrString(name); + } + else if (name == "adv_prefix") + { + adv_prefix = request.getAttrIpPrefix(name); + } else { SWSS_LOG_INFO("Unknown attribute: %s", name.c_str()); @@ -1933,7 +2035,7 @@ bool VNetRouteOrch::handleTunnel(const Request& request) if (vnet_orch_->isVnetExecVrf()) { - return doRouteTask(vnet_name, ip_pfx, nhg, op, profile, monitors); + return doRouteTask(vnet_name, ip_pfx, nhg, op, profile, monitoring, monitors); } return true; diff --git a/orchagent/vnetorch.h b/orchagent/vnetorch.h index f7e134f665..dc5c56f23d 100644 --- a/orchagent/vnetorch.h +++ b/orchagent/vnetorch.h @@ -25,6 +25,12 @@ extern sai_object_id_t gVirtualRouterId; +enum class MONITOR_SESSION_STATE +{ + MONITOR_SESSION_STATE_UP, + MONITOR_SESSION_STATE_DOWN, + MONITOR_SESSION_STATE_UNKNOWN, +}; const request_description_t vnet_request_description = { { REQ_T_STRING }, { @@ -35,6 +41,8 @@ const request_description_t vnet_request_description = { { "guid", REQ_T_STRING }, { "scope", REQ_T_STRING }, { "advertise_prefix", REQ_T_BOOL}, + { "overlay_dmac", REQ_T_MAC_ADDRESS}, + }, { "vxlan_tunnel", "vni" } // mandatory attributes }; @@ -60,6 +68,7 @@ struct VNetInfo set peers; string scope; bool advertise_prefix; + swss::MacAddress overlay_dmac; }; typedef map vrid_list_t; @@ -87,7 +96,8 @@ class VNetObject peer_list_(vnetInfo.peers), vni_(vnetInfo.vni), scope_(vnetInfo.scope), - advertise_prefix_(vnetInfo.advertise_prefix) + advertise_prefix_(vnetInfo.advertise_prefix), + overlay_dmac_(vnetInfo.overlay_dmac) { } virtual bool updateObj(vector&) = 0; @@ -122,6 +132,11 @@ class VNetObject return advertise_prefix_; } + swss::MacAddress getOverlayDMac() const + { + return overlay_dmac_; + } + virtual ~VNetObject() noexcept(false) {}; private: @@ -130,6 +145,7 @@ class VNetObject uint32_t vni_; string scope_; bool advertise_prefix_; + swss::MacAddress overlay_dmac_; }; struct nextHop @@ -277,6 +293,9 @@ const request_description_t vnet_route_description = { { "mac_address", REQ_T_STRING }, { "endpoint_monitor", REQ_T_IP_LIST }, { "profile", REQ_T_STRING }, + { "primary", REQ_T_IP_LIST }, + { "monitoring", REQ_T_STRING }, + { "adv_prefix", REQ_T_IP_PREFIX }, }, { } }; @@ -321,9 +340,16 @@ struct BfdSessionInfo NextHopKey endpoint; }; +struct MonitorSessionInfo +{ + MONITOR_SESSION_STATE state; + IpAddress monitor; +}; + typedef std::map VNetNextHopGroupInfoTable; typedef std::map VNetTunnelRouteTable; typedef std::map BfdSessionTable; +typedef std::map> MonitorSessionTable; typedef std::map VNetEndpointInfoTable; class VNetRouteOrch : public Orch2, public Subject, public Observer @@ -356,8 +382,11 @@ class VNetRouteOrch : public Orch2, public Subject, public Observer void createBfdSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& ipAddr); void removeBfdSession(const string& vnet, const NextHopKey& endpoint, const IpAddress& ipAddr); - void setEndpointMonitor(const string& vnet, const map& monitors, NextHopGroupKey& nexthops); - void delEndpointMonitor(const string& vnet, NextHopGroupKey& nexthops); + 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); + 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); void addRouteAdvertisement(IpPrefix& ipPrefix, string& profile); @@ -368,6 +397,7 @@ 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, const std::map& monitors=std::map()); template @@ -382,9 +412,12 @@ class VNetRouteOrch : public Orch2, public Subject, public Observer std::map syncd_nexthop_groups_; std::map syncd_tunnel_routes_; BfdSessionTable bfd_sessions_; + std::map monitor_info_; std::map nexthop_info_; ProducerStateTable bfd_session_producer_; + unique_ptr
monitor_session_producer_; shared_ptr state_db_; + shared_ptr app_db_; unique_ptr
state_vnet_rt_tunnel_table_; unique_ptr
state_vnet_rt_adv_table_; }; diff --git a/tests/test_vnet.py b/tests/test_vnet.py index 1ec778f011..705a4b331c 100644 --- a/tests/test_vnet.py +++ b/tests/test_vnet.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=""): - set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac=mac, vni=vni, ep_monitor=ep_monitor, profile=profile) +def create_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", adv_prefix=""): + 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) -def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile=""): +def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor="", profile="", primary="", monitoring="", adv_prefix=""): conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) attrs = [ @@ -163,6 +163,15 @@ def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor= if profile: attrs.append(('profile', profile)) + if primary: + attrs.append(('primary', primary)) + + if monitoring: + attrs.append(('monitoring', monitoring)) + + if adv_prefix: + attrs.append(('adv_prefix', adv_prefix)) + tbl = swsscommon.Table(conf_db, "VNET_ROUTE_TUNNEL") fvs = swsscommon.FieldValuePairs(attrs) tbl.set("%s|%s" % (vnet_name, prefix), fvs) @@ -317,7 +326,7 @@ def delete_phy_interface(dvs, ifname, ipaddr): time.sleep(2) -def create_vnet_entry(dvs, name, tunnel, vni, peer_list, scope="", advertise_prefix=False): +def create_vnet_entry(dvs, name, tunnel, vni, peer_list, scope="", advertise_prefix=False, overlay_dmac=""): conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) @@ -333,6 +342,9 @@ def create_vnet_entry(dvs, name, tunnel, vni, peer_list, scope="", advertise_pre if advertise_prefix: attrs.append(('advertise_prefix', 'true')) + if overlay_dmac: + attrs.append(('overlay_dmac', overlay_dmac)) + # create the VXLAN tunnel Term entry in Config DB create_entry_tbl( conf_db, @@ -534,6 +546,7 @@ class VnetVxlanVrfTunnel(object): ASIC_NEXT_HOP_GROUP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP" ASIC_NEXT_HOP_GROUP_MEMBER = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER" ASIC_BFD_SESSION = "ASIC_STATE:SAI_OBJECT_TYPE_BFD_SESSION" + APP_VNET_MONITOR = "VNET_MONITOR_TABLE" tunnel_map_ids = set() tunnel_map_entry_ids = set() @@ -939,7 +952,22 @@ def _access_function(): return True + def check_custom_monitor_app_db(self, dvs, prefix, endpoint, packet_type, overlay_dmac): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + key = prefix + ':' + endpoint + check_object(app_db, self.APP_VNET_MONITOR, key, + { + "packet_type": packet_type, + "overlay_dmac" : overlay_dmac + } + ) + return True + def check_custom_monitor_deleted(self, dvs, prefix, endpoint): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + key = prefix + ':' + endpoint + check_deleted_object(app_db, self.APP_VNET_MONITOR, key) + class TestVnetOrch(object): def get_vnet_obj(self): @@ -2395,6 +2423,37 @@ def test_vnet_orch_17(self, dvs, testlog): delete_vnet_entry(dvs, 'Vnet17') vnet_obj.check_del_vnet_entry(dvs, 'Vnet17') + ''' + Test 18 - Test for vxlan custom monitoring config. + ''' + def test_vnet_orch_18(self, dvs, testlog): + vnet_obj = self.get_vnet_obj() + + tunnel_name = 'tunnel_18' + + vnet_obj.fetch_exist_entries(dvs) + + create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') + create_vnet_entry(dvs, 'Vnet18', tunnel_name, '10009', "", overlay_dmac="22:33:33:44:44:66") + + vnet_obj.check_vnet_entry(dvs, 'Vnet18') + vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, 'Vnet18', '10009') + + vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9') + + vnet_obj.fetch_exist_entries(dvs) + create_vnet_routes(dvs, "100.100.1.1/32", 'Vnet18', '9.0.0.1,9.0.0.2,9.0.0.3', ep_monitor='9.1.0.1,9.1.0.2,9.1.0.3',primary ='9.0.0.1',monitoring='custom', adv_prefix='100.100.1.1/27') + + vnet_obj.check_custom_monitor_app_db(dvs, "100.100.1.1/32", "9.1.0.1", "vxlan", "22:33:33:44:44:66") + vnet_obj.check_custom_monitor_app_db(dvs, "100.100.1.1/32", "9.1.0.2", "vxlan", "22:33:33:44:44:66") + vnet_obj.check_custom_monitor_app_db(dvs, "100.100.1.1/32", "9.1.0.3", "vxlan", "22:33:33:44:44:66") + + delete_vnet_routes(dvs, "100.100.1.1/32", 'Vnet18') + + vnet_obj.check_custom_monitor_deleted(dvs, "100.100.1.1/32", "9.1.0.1") + vnet_obj.check_custom_monitor_deleted(dvs, "100.100.1.1/32", "9.1.0.2") + vnet_obj.check_custom_monitor_deleted(dvs, "100.100.1.1/32", "9.1.0.3") + # 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():