diff --git a/syncd/BestCandidateFinder.cpp b/syncd/BestCandidateFinder.cpp index 1ff05c3560..545029a1aa 100644 --- a/syncd/BestCandidateFinder.cpp +++ b/syncd/BestCandidateFinder.cpp @@ -24,6 +24,75 @@ BestCandidateFinder::BestCandidateFinder( // empty } +std::shared_ptr BestCandidateFinder::findCurrentBestMatchForVirtualRouter( + _In_ const std::shared_ptr &temporaryObj, + _In_ const std::vector &candidateObjects) +{ + SWSS_LOG_ENTER(); + + auto getVlanIds = []( + const AsicView& view, + sai_object_id_t virtualRouterId) + { + std::vector vlanIds; + + for (const auto& rif: view.getObjectsByObjectType(SAI_OBJECT_TYPE_ROUTER_INTERFACE)) + { + auto type = rif->tryGetSaiAttr(SAI_ROUTER_INTERFACE_ATTR_TYPE); + auto vr = rif->tryGetSaiAttr(SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID); + auto vlan = rif->tryGetSaiAttr(SAI_ROUTER_INTERFACE_ATTR_VLAN_ID); + + if (type == nullptr || vr == nullptr || vlan == nullptr || + type->getSaiAttr()->value.s32 != SAI_ROUTER_INTERFACE_TYPE_VLAN || + vr->getOid() != virtualRouterId) + { + continue; + } + + auto vlanObject = view.m_oOids.find(vlan->getOid()); + + if (vlanObject == view.m_oOids.end()) + continue; + + auto vlanId = vlanObject->second->tryGetSaiAttr(SAI_VLAN_ATTR_VLAN_ID); + + if (vlanId != nullptr) + vlanIds.push_back(vlanId->getSaiAttr()->value.u16); + } + + std::sort(vlanIds.begin(), vlanIds.end()); + + return vlanIds; + }; + + auto temporaryVlanIds = getVlanIds(m_temporaryView, temporaryObj->getVid()); + + if (temporaryVlanIds.empty()) + return nullptr; + + std::shared_ptr match = nullptr; + + for (const auto& candidate: candidateObjects) + { + if (getVlanIds(m_currentView, candidate.obj->getVid()) != temporaryVlanIds) + continue; + + if (match != nullptr) + return nullptr; + + match = candidate.obj; + } + + if (match != nullptr) + { + SWSS_LOG_NOTICE("matched virtual router %s to %s by VLAN interfaces", + temporaryObj->m_str_object_id.c_str(), + match->m_str_object_id.c_str()); + } + + return match; +} + std::shared_ptr BestCandidateFinder::findCurrentBestMatchForLag( _In_ const std::shared_ptr &temporaryObj, _In_ const std::vector &candidateObjects) @@ -1496,6 +1565,10 @@ std::shared_ptr BestCandidateFinder::findCurrentBestMatchForGenericObjec switch (temporaryObj->getObjectType()) { + case SAI_OBJECT_TYPE_VIRTUAL_ROUTER: + candidate = findCurrentBestMatchForVirtualRouter(temporaryObj, candidateObjects); + break; + case SAI_OBJECT_TYPE_LAG: candidate = findCurrentBestMatchForLag(temporaryObj, candidateObjects); break; diff --git a/syncd/BestCandidateFinder.h b/syncd/BestCandidateFinder.h index e1d8cd5980..31c969e089 100644 --- a/syncd/BestCandidateFinder.h +++ b/syncd/BestCandidateFinder.h @@ -47,6 +47,10 @@ namespace syncd _In_ const std::shared_ptr &temporaryObj, _In_ const std::vector &candidateObjects); + std::shared_ptr findCurrentBestMatchForVirtualRouter( + _In_ const std::shared_ptr &temporaryObj, + _In_ const std::vector &candidateObjects); + std::shared_ptr findCurrentBestMatchForNextHopGroup( _In_ const std::shared_ptr &temporaryObj, _In_ const std::vector &candidateObjects); diff --git a/unittest/syncd/TestBestCandidateFinder.cpp b/unittest/syncd/TestBestCandidateFinder.cpp index 2204e342c7..8e796df08d 100644 --- a/unittest/syncd/TestBestCandidateFinder.cpp +++ b/unittest/syncd/TestBestCandidateFinder.cpp @@ -1,6 +1,8 @@ #include "BestCandidateFinder.h" #include "MockableSaiSwitchInterface.h" +#include "meta/sai_serialize.h" + #include using namespace syncd; @@ -21,3 +23,106 @@ TEST(BestCandidateFinder, getSaiAttrFromDefaultValue) auto attr = BestCandidateFinder::getSaiAttrFromDefaultValue(av, sw, *meta); EXPECT_NE(attr, nullptr); } + +TEST(BestCandidateFinder, matchVirtualRoutersByVlanInterfaces) +{ + const sai_object_id_t switchId = 0x21000000000000; + const sai_object_id_t currentVrf1 = 0x3000000000001; + const sai_object_id_t currentVrf2 = 0x3000000000002; + const sai_object_id_t temporaryVrf1 = 0x3000000000101; + const sai_object_id_t temporaryVrf2 = 0x3000000000102; + const sai_object_id_t currentVlan1 = 0x26000000000001; + const sai_object_id_t currentVlan2 = 0x26000000000002; + const sai_object_id_t currentVlan3 = 0x26000000000003; + const sai_object_id_t currentVlan4 = 0x26000000000004; + const sai_object_id_t temporaryVlan1 = 0x26000000000101; + const sai_object_id_t temporaryVlan2 = 0x26000000000102; + const sai_object_id_t temporaryVlan3 = 0x26000000000103; + const sai_object_id_t temporaryVlan4 = 0x26000000000104; + const sai_object_id_t currentRif1 = 0x6000000000001; + const sai_object_id_t currentRif2 = 0x6000000000002; + const sai_object_id_t currentRif3 = 0x6000000000003; + const sai_object_id_t currentRif4 = 0x6000000000004; + const sai_object_id_t temporaryRif1 = 0x6000000000101; + const sai_object_id_t temporaryRif2 = 0x6000000000102; + const sai_object_id_t temporaryRif3 = 0x6000000000103; + const sai_object_id_t temporaryRif4 = 0x6000000000104; + + auto key = [](const std::string& objectType, sai_object_id_t objectId) + { + return objectType + ":" + sai_serialize_object_id(objectId); + }; + + swss::TableDump current = { + { key("SAI_OBJECT_TYPE_SWITCH", switchId), {} }, + { key("SAI_OBJECT_TYPE_VIRTUAL_ROUTER", currentVrf1), {} }, + { key("SAI_OBJECT_TYPE_VIRTUAL_ROUTER", currentVrf2), {} }, + { key("SAI_OBJECT_TYPE_VLAN", currentVlan1), + { { "SAI_VLAN_ATTR_VLAN_ID", "1001" } } }, + { key("SAI_OBJECT_TYPE_VLAN", currentVlan2), + { { "SAI_VLAN_ATTR_VLAN_ID", "1002" } } }, + { key("SAI_OBJECT_TYPE_VLAN", currentVlan3), + { { "SAI_VLAN_ATTR_VLAN_ID", "2001" } } }, + { key("SAI_OBJECT_TYPE_VLAN", currentVlan4), + { { "SAI_VLAN_ATTR_VLAN_ID", "2002" } } }, + { key("SAI_OBJECT_TYPE_ROUTER_INTERFACE", currentRif1), { + { "SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_VLAN" }, + { "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", sai_serialize_object_id(currentVrf1) }, + { "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", sai_serialize_object_id(currentVlan1) } } }, + { key("SAI_OBJECT_TYPE_ROUTER_INTERFACE", currentRif2), { + { "SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_VLAN" }, + { "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", sai_serialize_object_id(currentVrf1) }, + { "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", sai_serialize_object_id(currentVlan2) } } }, + { key("SAI_OBJECT_TYPE_ROUTER_INTERFACE", currentRif3), { + { "SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_VLAN" }, + { "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", sai_serialize_object_id(currentVrf2) }, + { "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", sai_serialize_object_id(currentVlan3) } } }, + { key("SAI_OBJECT_TYPE_ROUTER_INTERFACE", currentRif4), { + { "SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_VLAN" }, + { "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", sai_serialize_object_id(currentVrf2) }, + { "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", sai_serialize_object_id(currentVlan4) } } }, + }; + + swss::TableDump temporary = { + { key("SAI_OBJECT_TYPE_SWITCH", switchId), {} }, + { key("SAI_OBJECT_TYPE_VIRTUAL_ROUTER", temporaryVrf1), {} }, + { key("SAI_OBJECT_TYPE_VIRTUAL_ROUTER", temporaryVrf2), {} }, + { key("SAI_OBJECT_TYPE_VLAN", temporaryVlan1), + { { "SAI_VLAN_ATTR_VLAN_ID", "1001" } } }, + { key("SAI_OBJECT_TYPE_VLAN", temporaryVlan2), + { { "SAI_VLAN_ATTR_VLAN_ID", "1002" } } }, + { key("SAI_OBJECT_TYPE_VLAN", temporaryVlan3), + { { "SAI_VLAN_ATTR_VLAN_ID", "2001" } } }, + { key("SAI_OBJECT_TYPE_VLAN", temporaryVlan4), + { { "SAI_VLAN_ATTR_VLAN_ID", "2002" } } }, + { key("SAI_OBJECT_TYPE_ROUTER_INTERFACE", temporaryRif1), { + { "SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_VLAN" }, + { "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", sai_serialize_object_id(temporaryVrf1) }, + { "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", sai_serialize_object_id(temporaryVlan4) } } }, + { key("SAI_OBJECT_TYPE_ROUTER_INTERFACE", temporaryRif2), { + { "SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_VLAN" }, + { "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", sai_serialize_object_id(temporaryVrf1) }, + { "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", sai_serialize_object_id(temporaryVlan3) } } }, + { key("SAI_OBJECT_TYPE_ROUTER_INTERFACE", temporaryRif3), { + { "SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_VLAN" }, + { "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", sai_serialize_object_id(temporaryVrf2) }, + { "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", sai_serialize_object_id(temporaryVlan2) } } }, + { key("SAI_OBJECT_TYPE_ROUTER_INTERFACE", temporaryRif4), { + { "SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_VLAN" }, + { "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", sai_serialize_object_id(temporaryVrf2) }, + { "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", sai_serialize_object_id(temporaryVlan1) } } }, + }; + + AsicView currentView(current); + AsicView temporaryView(temporary); + auto sw = std::make_shared(0, 0); + BestCandidateFinder finder(currentView, temporaryView, sw); + + auto match1 = finder.findCurrentBestMatch(temporaryView.m_oOids.at(temporaryVrf1)); + auto match2 = finder.findCurrentBestMatch(temporaryView.m_oOids.at(temporaryVrf2)); + + ASSERT_NE(match1, nullptr); + ASSERT_NE(match2, nullptr); + EXPECT_EQ(match1->getVid(), currentVrf2); + EXPECT_EQ(match2->getVid(), currentVrf1); +}