diff --git a/orchagent/dash/dashorch.cpp b/orchagent/dash/dashorch.cpp index 0e9ff1cf9ce..66f03314f6a 100644 --- a/orchagent/dash/dashorch.cpp +++ b/orchagent/dash/dashorch.cpp @@ -24,9 +24,11 @@ #include "pbutils.h" #include "dashrouteorch.h" #include "dashmeterorch.h" +#include using namespace std; using namespace swss; +using namespace google::protobuf::util; extern Directory gDirectory; extern std::unordered_map gVnetNameToId; @@ -34,6 +36,7 @@ extern sai_dash_appliance_api_t* sai_dash_appliance_api; extern sai_dash_vip_api_t* sai_dash_vip_api; extern sai_dash_direction_lookup_api_t* sai_dash_direction_lookup_api; extern sai_dash_eni_api_t* sai_dash_eni_api; +extern sai_dash_trusted_vni_api_t* sai_dash_trusted_vni_api; extern sai_object_id_t gSwitchId; extern size_t gMaxBulkSize; extern CrmOrch *gCrmOrch; @@ -112,9 +115,20 @@ bool DashOrch::addApplianceEntry(const string& appliance_id, const dash::applian { SWSS_LOG_ENTER(); - if (appliance_entries_.find(appliance_id) != appliance_entries_.end()) + auto it = appliance_entries_.find(appliance_id); + + if (it != appliance_entries_.end()) { - SWSS_LOG_WARN("Appliance Entry already exists for %s", appliance_id.c_str()); + if (!MessageDifferencer::Equivalent(it->second.metadata.trusted_vnis(), entry.trusted_vnis())) + { + SWSS_LOG_INFO("Appliance Entry %s already exists with different trusted vnis", appliance_id.c_str()); + removeApplianceTrustedVni(appliance_id, it->second.metadata); + addApplianceTrustedVni(appliance_id, entry); + } + else + { + SWSS_LOG_WARN("Appliance Entry already exists for %s", appliance_id.c_str()); + } return true; } if (!appliance_entries_.empty()) @@ -200,9 +214,42 @@ bool DashOrch::addApplianceEntry(const string& appliance_id, const dash::applian appliance_entries_[appliance_id] = ApplianceEntry { sai_appliance_id, entry }; SWSS_LOG_NOTICE("Created appliance, vip and direction lookup entries for %s", appliance_id.c_str()); + if (entry.has_trusted_vnis()) + { + addApplianceTrustedVni(appliance_id, entry); + } + return true; } +void DashOrch::addApplianceTrustedVni(const std::string& appliance_id, const dash::appliance::Appliance& entry) +{ + SWSS_LOG_ENTER(); + sai_global_trusted_vni_entry_t trusted_vni_entry; + trusted_vni_entry.switch_id = gSwitchId; + sai_u32_range_t vni_range; + if (!to_sai(entry.trusted_vnis(), vni_range)) + { + SWSS_LOG_ERROR("Failed to convert trusted vni range for appliance"); + return; + } + + trusted_vni_entry.vni_range = vni_range; + sai_status_t status = sai_dash_trusted_vni_api->create_global_trusted_vni_entry(&trusted_vni_entry, 0, NULL); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create global trusted vni entry with range %u-%u for appliance", vni_range.min, vni_range.max); + task_process_status handle_status = handleSaiCreateStatus((sai_api_t)SAI_API_DASH_TRUSTED_VNI, status); + if (handle_status != task_success) + { + parseHandleSaiStatusFailure(handle_status); + } + } + appliance_entries_[appliance_id].metadata.mutable_trusted_vnis()->CopyFrom(entry.trusted_vnis()); + SWSS_LOG_NOTICE("Created global trusted vni entry for appliance with range %u-%u", + vni_range.min, vni_range.max); +} + bool DashOrch::removeApplianceEntry(const string& appliance_id) { SWSS_LOG_ENTER(); @@ -261,12 +308,49 @@ bool DashOrch::removeApplianceEntry(const string& appliance_id) } } } + + if (entry.has_trusted_vnis()) + { + removeApplianceTrustedVni(appliance_id, entry); + } + appliance_entries_.erase(appliance_id); SWSS_LOG_NOTICE("Removed appliance, vip and direction lookup entries for %s", appliance_id.c_str()); + return true; } +void DashOrch::removeApplianceTrustedVni(const std::string& appliance_id, const dash::appliance::Appliance& entry) +{ + SWSS_LOG_ENTER(); + sai_global_trusted_vni_entry_t trusted_vni_entry; + trusted_vni_entry.switch_id = gSwitchId; + sai_u32_range_t vni_range; + + if (!to_sai(entry.trusted_vnis(), vni_range)) + { + SWSS_LOG_ERROR("Failed to convert trusted vni range for appliance"); + return; + } + + trusted_vni_entry.vni_range = vni_range; + sai_status_t status = sai_dash_trusted_vni_api->remove_global_trusted_vni_entry(&trusted_vni_entry); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove global trusted vni entry with range %u-%u for appliance", vni_range.min, vni_range.max); + task_process_status handle_status = handleSaiRemoveStatus((sai_api_t)SAI_API_DASH_TRUSTED_VNI, status); + if (handle_status != task_success) + { + parseHandleSaiStatusFailure(handle_status); + } + } + + appliance_entries_[appliance_id].metadata.clear_trusted_vnis(); + SWSS_LOG_NOTICE("Removed global trusted vni entry for appliance with range %u-%u", + vni_range.min, vni_range.max); +} + void DashOrch::doTaskApplianceTable(ConsumerBase& consumer) { SWSS_LOG_ENTER(); @@ -638,19 +722,59 @@ bool DashOrch::addEniAddrMapEntry(const string& eni, const EniEntry& entry) return true; } -bool DashOrch::addEni(const string& eni, EniEntry &entry) +void DashOrch::addEniTrustedVnis(const std::string& eni, const EniEntry& entry) { SWSS_LOG_ENTER(); + sai_eni_trusted_vni_entry_t trusted_vni_entry; + trusted_vni_entry.switch_id = gSwitchId; + trusted_vni_entry.eni_id = entry.eni_id; + sai_u32_range_t vni_range; + if (!to_sai(entry.metadata.trusted_vnis(), vni_range)) + { + SWSS_LOG_ERROR("Failed to convert trusted vni range for ENI %s", entry.metadata.eni_id().c_str()); + return; + } + trusted_vni_entry.vni_range = vni_range; - auto it = eni_entries_.find(eni); - if (it != eni_entries_.end() && it->second.metadata.admin_state() != entry.metadata.admin_state()) + sai_status_t status = sai_dash_trusted_vni_api->create_eni_trusted_vni_entry(&trusted_vni_entry, 0, NULL); + if (status != SAI_STATUS_SUCCESS) { - return setEniAdminState(eni, entry); + SWSS_LOG_ERROR("Failed to create ENI trusted vni entry with range %u-%u for ENI %s", vni_range.min, vni_range.max, entry.metadata.eni_id().c_str()); + task_process_status handle_status = handleSaiCreateStatus((sai_api_t)SAI_API_DASH_TRUSTED_VNI, status); + if (handle_status != task_success) + { + parseHandleSaiStatusFailure(handle_status); + } } + eni_entries_[eni].metadata.mutable_trusted_vnis()->CopyFrom(entry.metadata.trusted_vnis()); + SWSS_LOG_NOTICE("Created ENI trusted vni entry for ENI %s with range %u-%u", + entry.metadata.eni_id().c_str(), vni_range.min, vni_range.max); +} + +bool DashOrch::addEni(const string& eni, EniEntry &entry) +{ + SWSS_LOG_ENTER(); - else if (it != eni_entries_.end()) + auto it = eni_entries_.find(eni); + if (it != eni_entries_.end()) { - SWSS_LOG_WARN("ENI %s already exists", eni.c_str()); + bool changed = false; + if (!MessageDifferencer::Equivalent(it->second.metadata.trusted_vnis(), entry.metadata.trusted_vnis())) + { + SWSS_LOG_INFO("ENI %s trusted vnis have changed", eni.c_str()); + removeEniTrustedVnis(eni, it->second); + addEniTrustedVnis(eni, entry); + changed = true; + } + if (it->second.metadata.admin_state() != entry.metadata.admin_state()) + { + SWSS_LOG_INFO("ENI %s already exists, updating admin state", eni.c_str()); + return setEniAdminState(eni, entry); + } + if (!changed) + { + SWSS_LOG_WARN("ENI %s already exists", eni.c_str()); + } return true; } @@ -660,6 +784,11 @@ bool DashOrch::addEni(const string& eni, EniEntry &entry) } eni_entries_[eni] = entry; + if (entry.metadata.has_trusted_vnis()) + { + addEniTrustedVnis(eni, entry); + } + return true; } @@ -754,6 +883,36 @@ bool DashOrch::removeEniAddrMapEntry(const string& eni) return true; } +void DashOrch::removeEniTrustedVnis(const std::string& eni, const EniEntry& entry) +{ + SWSS_LOG_ENTER(); + sai_eni_trusted_vni_entry_t trusted_vni_entry; + trusted_vni_entry.switch_id = gSwitchId; + trusted_vni_entry.eni_id = entry.eni_id; + sai_u32_range_t vni_range; + + if (!to_sai(entry.metadata.trusted_vnis(), vni_range)) + { + SWSS_LOG_ERROR("Failed to convert trusted vni range for ENI %s", entry.metadata.eni_id().c_str()); + return; + } + + trusted_vni_entry.vni_range = vni_range; + sai_status_t status = sai_dash_trusted_vni_api->remove_eni_trusted_vni_entry(&trusted_vni_entry); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove ENI trusted vni entry with range %u-%u for ENI %s", vni_range.min, vni_range.max, entry.metadata.eni_id().c_str()); + task_process_status handle_status = handleSaiRemoveStatus((sai_api_t)SAI_API_DASH_TRUSTED_VNI, status); + if (handle_status != task_success) + { + parseHandleSaiStatusFailure(handle_status); + } + } + eni_entries_[eni].metadata.clear_trusted_vnis(); + SWSS_LOG_NOTICE("Removed ENI trusted vni entry for ENI %s with range %u-%u", + entry.metadata.eni_id().c_str(), vni_range.min, vni_range.max); +} + bool DashOrch::removeEni(const string& eni) { SWSS_LOG_ENTER(); @@ -763,10 +922,17 @@ bool DashOrch::removeEni(const string& eni) SWSS_LOG_WARN("ENI %s does not exist", eni.c_str()); return true; } + + if (eni_entries_[eni].metadata.has_trusted_vnis()) + { + removeEniTrustedVnis(eni, eni_entries_[eni]); + } + if (!removeEniAddrMapEntry(eni) || !removeEniObject(eni)) { return false; } + eni_entries_.erase(eni); return true; diff --git a/orchagent/dash/dashorch.h b/orchagent/dash/dashorch.h index 20d6e729f68..c55955e8126 100644 --- a/orchagent/dash/dashorch.h +++ b/orchagent/dash/dashorch.h @@ -79,14 +79,18 @@ class DashOrch : public ZmqOrch void doTaskEniRouteTable(ConsumerBase &consumer); void doTaskRouteGroupTable(ConsumerBase &consumer); bool addApplianceEntry(const std::string& appliance_id, const dash::appliance::Appliance &entry); + void addApplianceTrustedVni(const std::string& appliance_id, const dash::appliance::Appliance& entry); bool removeApplianceEntry(const std::string& appliance_id); + void removeApplianceTrustedVni(const std::string& appliance_id, const dash::appliance::Appliance& entry); bool addRoutingTypeEntry(const dash::route_type::RoutingType &routing_type, const dash::route_type::RouteType &entry); bool removeRoutingTypeEntry(const dash::route_type::RoutingType &routing_type); bool addEniObject(const std::string& eni, EniEntry& entry); bool addEniAddrMapEntry(const std::string& eni, const EniEntry& entry); + void addEniTrustedVnis(const std::string& eni, const EniEntry& entry); bool addEni(const std::string& eni, EniEntry &entry); bool removeEniObject(const std::string& eni); bool removeEniAddrMapEntry(const std::string& eni); + void removeEniTrustedVnis(const std::string& eni, const EniEntry& entry); bool removeEni(const std::string& eni); bool setEniAdminState(const std::string& eni, const EniEntry& entry); bool addQosEntry(const std::string& qos_name, const dash::qos::Qos &entry); diff --git a/orchagent/dash/pbutils.cpp b/orchagent/dash/pbutils.cpp index 08e578bb77e..9a643000ca5 100644 --- a/orchagent/dash/pbutils.cpp +++ b/orchagent/dash/pbutils.cpp @@ -91,6 +91,33 @@ bool to_sai(const RepeatedPtrField &pb_prefixes, vector pb_range.range().max()) + { + SWSS_LOG_WARN("The range %s is invalid", pb_range.range().DebugString().c_str()); + return false; + } + sai_range.min = pb_range.range().min(); + sai_range.max = pb_range.range().max(); + } + else + { + SWSS_LOG_WARN("The ValueOrRange %s is invalid", pb_range.DebugString().c_str()); + return false; + } + return true; +} + ip_addr_t to_swss(const dash::types::IpAddress &pb_address) { SWSS_LOG_ENTER(); diff --git a/orchagent/dash/pbutils.h b/orchagent/dash/pbutils.h index f048aae2c5b..08fa8ba4123 100644 --- a/orchagent/dash/pbutils.h +++ b/orchagent/dash/pbutils.h @@ -18,6 +18,8 @@ bool to_sai(const dash::types::IpPrefix &pb_prefix, sai_ip_prefix_t &sai_prefix) bool to_sai(const google::protobuf::RepeatedPtrField &pb_prefixes, std::vector &sai_prefixes); +bool to_sai(const dash::types::ValueOrRange &pb_range, sai_u32_range_t &sai_range); + template bool to_sai(const dash::types::ValueOrRange &pb_range, RangeType &sai_range) { diff --git a/orchagent/saihelper.cpp b/orchagent/saihelper.cpp index c3c4bcb4e30..4500b43e6e5 100644 --- a/orchagent/saihelper.cpp +++ b/orchagent/saihelper.cpp @@ -91,6 +91,7 @@ sai_twamp_api_t* sai_twamp_api; sai_tam_api_t* sai_tam_api; sai_stp_api_t* sai_stp_api; sai_dash_meter_api_t* sai_dash_meter_api; +sai_dash_trusted_vni_api_t* sai_dash_trusted_vni_api; extern sai_object_id_t gSwitchId; extern bool gTraditionalFlexCounter; diff --git a/tests/mock_tests/dashorch_ut.cpp b/tests/mock_tests/dashorch_ut.cpp index e5c66f29484..372c5496eb9 100644 --- a/tests/mock_tests/dashorch_ut.cpp +++ b/tests/mock_tests/dashorch_ut.cpp @@ -13,6 +13,7 @@ #include "dash_api/eni.pb.h" #include "dash_api/qos.pb.h" #include "dash_api/eni_route.pb.h" +#include "dash_api/types.pb.h" EXTERN_MOCK_FNS @@ -20,27 +21,75 @@ EXTERN_MOCK_FNS namespace dashorch_test { DEFINE_SAI_GENERIC_APIS_MOCK(dash_eni, eni) + DEFINE_SAI_ENTRY_APIS_MOCK(dash_trusted_vni, global_trusted_vni, eni_trusted_vni) using namespace mock_orch_test; using ::testing::DoAll; using ::testing::Return; using ::testing::SetArgPointee; using ::testing::SaveArg; + using ::testing::SaveArgPointee; using ::testing::Invoke; using ::testing::InSequence; - class DashOrchTest : public MockDashOrchTest { + using dash::types::ValueOrRange; + + ValueOrRange GenVni(int value) + { + ValueOrRange vni; + vni.set_value(value); + return vni; + } + ValueOrRange GenVni(int min, int max) + { + ValueOrRange vni; + vni.mutable_range()->set_min(min); + vni.mutable_range()->set_max(max); + return vni; + } + + ValueOrRange vni_value1 = GenVni(1000); + ValueOrRange vni_value2 = GenVni(2000); + ValueOrRange vni_range1 = GenVni(3000, 4000); + ValueOrRange vni_range2 = GenVni(5000, 6000); + + std::string GetVniString(const ValueOrRange &vni) + { + if (vni.has_value()) { + return std::to_string(vni.value()); + } else if (vni.has_range()) { + return std::to_string(vni.range().min()) + "_" + std::to_string(vni.range().max()); + } else { + return "Invalid VNI"; + } + } + class DashOrchTest : public MockDashOrchTest, public ::testing::WithParamInterface> { + void ApplySaiMock() { INIT_SAI_API_MOCK(dash_eni); + INIT_SAI_API_MOCK(dash_trusted_vni); MockSaiApis(); } void PreTearDown() override { RestoreSaiApis(); + DEINIT_SAI_API_MOCK(dash_trusted_vni); DEINIT_SAI_API_MOCK(dash_eni); } public: + void VerifyTrustedVniEntry(sai_u32_range_t &actual_entry, const ValueOrRange &expected_vni) + { + if (expected_vni.has_value()) { + EXPECT_EQ(actual_entry.min, expected_vni.value()); + EXPECT_EQ(actual_entry.max, expected_vni.value()); + } else if (expected_vni.has_range()) { + EXPECT_EQ(actual_entry.min, expected_vni.range().min()); + EXPECT_EQ(actual_entry.max, expected_vni.range().max()); + } else { + FAIL() << "Invalid ValueOrRange provided"; + } + } void VerifyEniMode(std::vector &actual_attrs, sai_dash_eni_mode_t expected_mode) { for (auto attr : actual_attrs) { @@ -94,22 +143,14 @@ namespace dashorch_test const sai_attribute_t* attr_start; std::vector actual_attrs; - dash::eni::Eni eni; - std::string mac = "f4:93:9f:ef:c4:7e"; - eni.set_admin_state(dash::eni::State::STATE_ENABLED); - eni.set_eni_id("eni1"); - eni.set_mac_address(mac); - eni.set_vnet(vnet1); - eni.mutable_underlay_ip()->set_ipv4(swss::IpAddress("1.2.3.4").getV4Addr()); - eni.set_eni_mode(dash::eni::MODE_VM); - + dash::eni::Eni eni = BuildEniEntry(); + EXPECT_CALL(*mock_sai_dash_eni_api, create_eni).Times(3) .WillRepeatedly( DoAll( SaveArg<2>(&num_attrs), SaveArg<3>(&attr_start), Invoke(old_sai_dash_eni_api, &sai_dash_eni_api_t::create_eni) // Call the original function - ) ); @@ -132,4 +173,321 @@ namespace dashorch_test VerifyEniMode(actual_attrs, SAI_DASH_ENI_MODE_VM); // Default SetDashTable(APP_DASH_ENI_TABLE_NAME, "eni1", eni, false); } + + TEST_F(DashOrchTest, CreateRemoveApplianceTrustedVnisSingle) + { + int trusted_vni = 100; + dash::appliance::Appliance appliance = BuildApplianceEntry(); + appliance.mutable_trusted_vnis()->set_value(trusted_vni); + + sai_global_trusted_vni_entry_t actual_entry; + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_global_trusted_vni_entry))); + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_global_trusted_vni_entry))); + + SetDashTable(APP_DASH_APPLIANCE_TABLE_NAME, appliance1, appliance); + EXPECT_EQ(actual_entry.vni_range.min, trusted_vni); + EXPECT_EQ(actual_entry.vni_range.max, trusted_vni); + + SetDashTable(APP_DASH_APPLIANCE_TABLE_NAME, appliance1, dash::appliance::Appliance(), false); + EXPECT_EQ(actual_entry.vni_range.min, trusted_vni); + EXPECT_EQ(actual_entry.vni_range.max, trusted_vni); + } + + TEST_F(DashOrchTest, CreateRemoveApplianceTrustedVnisRange) + { + int min_trusted_vni = 500; + int max_trusted_vni = 600; + dash::appliance::Appliance appliance = BuildApplianceEntry(); + appliance.mutable_trusted_vnis()->mutable_range()->set_min(min_trusted_vni); + appliance.mutable_trusted_vnis()->mutable_range()->set_max(max_trusted_vni); + + sai_global_trusted_vni_entry_t actual_entry; + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_global_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_global_trusted_vni_entry))); + + SetDashTable(APP_DASH_APPLIANCE_TABLE_NAME, appliance1, appliance); + EXPECT_EQ(actual_entry.vni_range.min, min_trusted_vni); + EXPECT_EQ(actual_entry.vni_range.max, max_trusted_vni); + + SetDashTable(APP_DASH_APPLIANCE_TABLE_NAME, appliance1, dash::appliance::Appliance(), false); + EXPECT_EQ(actual_entry.vni_range.min, min_trusted_vni); + EXPECT_EQ(actual_entry.vni_range.max, max_trusted_vni); + } + + TEST_F(DashOrchTest, CreateRemoveEniTrustedVnisSingle) + { + CreateApplianceEntry(); + CreateVnet(); + + int trusted_vni = 200; + dash::eni::Eni eni = BuildEniEntry(); + eni.mutable_trusted_vnis()->set_value(trusted_vni); + + sai_eni_trusted_vni_entry_t actual_entry; + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_eni_trusted_vni_entry))); + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_eni_trusted_vni_entry))); + + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, eni); + EXPECT_EQ(actual_entry.vni_range.min, trusted_vni); + EXPECT_EQ(actual_entry.vni_range.max, trusted_vni); + + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, dash::eni::Eni(), false); + EXPECT_EQ(actual_entry.vni_range.min, trusted_vni); + EXPECT_EQ(actual_entry.vni_range.max, trusted_vni); + } + + TEST_F(DashOrchTest, CreateRemoveEniTrustedVnisRange) + { + CreateApplianceEntry(); + CreateVnet(); + + int min_trusted_vni = 700; + int max_trusted_vni = 800; + dash::eni::Eni eni = BuildEniEntry(); + eni.mutable_trusted_vnis()->mutable_range()->set_min(min_trusted_vni); + eni.mutable_trusted_vnis()->mutable_range()->set_max(max_trusted_vni); + + sai_eni_trusted_vni_entry_t actual_entry; + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_eni_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_eni_trusted_vni_entry))); + + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, eni); + EXPECT_EQ(actual_entry.vni_range.min, min_trusted_vni); + EXPECT_EQ(actual_entry.vni_range.max, max_trusted_vni); + + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, dash::eni::Eni(), false); + EXPECT_EQ(actual_entry.vni_range.min, min_trusted_vni); + EXPECT_EQ(actual_entry.vni_range.max, max_trusted_vni); + } + + TEST_F(DashOrchTest, DuplicateSetEniTrustedVniSingle) + { + CreateApplianceEntry(); + CreateVnet(); + + int trusted_vni = 300; + dash::eni::Eni eni = BuildEniEntry(); + eni.mutable_trusted_vnis()->set_value(trusted_vni); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_eni_trusted_vni_entry).Times(1); + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_eni_trusted_vni_entry).Times(0); + + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, eni); + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, eni); + } + + TEST_F(DashOrchTest, DuplicateSetEniTrustedVniRange) + { + CreateApplianceEntry(); + CreateVnet(); + + int min_trusted_vni = 900; + int max_trusted_vni = 1000; + dash::eni::Eni eni = BuildEniEntry(); + eni.mutable_trusted_vnis()->mutable_range()->set_min(min_trusted_vni); + eni.mutable_trusted_vnis()->mutable_range()->set_max(max_trusted_vni); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_eni_trusted_vni_entry).Times(1); + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_eni_trusted_vni_entry).Times(0); + + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, eni); + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, eni); + } + + TEST_P(DashOrchTest, ChangeEniTrustedVni) + { + CreateApplianceEntry(); + CreateVnet(); + + ValueOrRange orig_vni, changed_vni; + std::tie(orig_vni, changed_vni) = GetParam(); + + dash::eni::Eni eni = BuildEniEntry(); + sai_eni_trusted_vni_entry_t actual_entry; + sai_eni_trusted_vni_entry_t removed_entry; + to_sai(changed_vni, removed_entry.vni_range); + + { + InSequence seq; + + // Initial set + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_eni_trusted_vni_entry))); + + // We expect 3 additional changes, orig->changed, changed->orig, and orig->changed + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&removed_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_eni_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_eni_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&removed_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_eni_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_eni_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&removed_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_eni_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_eni_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_eni_trusted_vni_entry))); + } + + for (int i = 0; i < 2; i++) + { + eni.mutable_trusted_vnis()->CopyFrom(orig_vni); + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, eni); + VerifyTrustedVniEntry(removed_entry.vni_range, changed_vni); + VerifyTrustedVniEntry(actual_entry.vni_range, orig_vni); + + eni.mutable_trusted_vnis()->CopyFrom(changed_vni); + SetDashTable(APP_DASH_ENI_TABLE_NAME, eni1, eni); + VerifyTrustedVniEntry(removed_entry.vni_range, orig_vni); + VerifyTrustedVniEntry(actual_entry.vni_range, changed_vni); + } + } + + TEST_P(DashOrchTest, ChangeApplianceTrustedVni) + { + ValueOrRange orig_vni, changed_vni; + std::tie(orig_vni, changed_vni) = GetParam(); + + dash::appliance::Appliance appliance = BuildApplianceEntry(); + sai_global_trusted_vni_entry_t actual_entry; + sai_global_trusted_vni_entry_t removed_entry; + to_sai(changed_vni, removed_entry.vni_range); + + { + InSequence seq; + + // Initial set + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_global_trusted_vni_entry))); + + // We expect 3 additional changes, orig->changed, changed->orig, and orig->changed + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&removed_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_global_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_global_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&removed_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_global_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_global_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, remove_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&removed_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::remove_global_trusted_vni_entry))); + + EXPECT_CALL(*mock_sai_dash_trusted_vni_api, create_global_trusted_vni_entry) + .WillOnce( + DoAll( + SaveArgPointee<0>(&actual_entry), + Invoke(old_sai_dash_trusted_vni_api, &sai_dash_trusted_vni_api_t::create_global_trusted_vni_entry))); + } + + for (int i = 0; i < 2; i++) + { + appliance.mutable_trusted_vnis()->CopyFrom(orig_vni); + SetDashTable(APP_DASH_APPLIANCE_TABLE_NAME, appliance1, appliance); + VerifyTrustedVniEntry(removed_entry.vni_range, changed_vni); + VerifyTrustedVniEntry(actual_entry.vni_range, orig_vni); + + appliance.mutable_trusted_vnis()->CopyFrom(changed_vni); + SetDashTable(APP_DASH_APPLIANCE_TABLE_NAME, appliance1, appliance); + VerifyTrustedVniEntry(removed_entry.vni_range, orig_vni); + VerifyTrustedVniEntry(actual_entry.vni_range, changed_vni); + } + } + + INSTANTIATE_TEST_SUITE_P( + DashOrchChangeTrustedVniTest, + DashOrchTest, + ::testing::Combine( + ::testing::Values(vni_value1, vni_range1), + ::testing::Values(vni_value2, vni_range2)), + [](const testing::TestParamInfo &info) { + const auto &vni1 = std::get<0>(info.param); + const auto &vni2 = std::get<1>(info.param); + return "EniTrustedVni_" + GetVniString(vni1) + "_to_" + GetVniString(vni2); + }); } \ No newline at end of file diff --git a/tests/mock_tests/mock_dash_orch_test.cpp b/tests/mock_tests/mock_dash_orch_test.cpp index 0572775cd52..2f87985b0e5 100644 --- a/tests/mock_tests/mock_dash_orch_test.cpp +++ b/tests/mock_tests/mock_dash_orch_test.cpp @@ -31,14 +31,19 @@ namespace mock_orch_test } } - void MockDashOrchTest::CreateApplianceEntry() + dash::appliance::Appliance MockDashOrchTest::BuildApplianceEntry() { swss::IpAddress sip("1.1.1.1"); dash::appliance::Appliance appliance = dash::appliance::Appliance(); appliance.mutable_sip()->set_ipv4(sip.getV4Addr()); appliance.set_local_region_id(100); appliance.set_vm_vni(9999); - SetDashTable(APP_DASH_APPLIANCE_TABLE_NAME, appliance1, appliance); + return appliance; + } + + void MockDashOrchTest::CreateApplianceEntry() + { + SetDashTable(APP_DASH_APPLIANCE_TABLE_NAME, appliance1, BuildApplianceEntry()); } void MockDashOrchTest::CreateVnet() @@ -99,4 +104,17 @@ namespace mock_orch_test { SetDashTable(APP_DASH_VNET_MAPPING_TABLE_NAME, vnet1 + ":" + vnet_map_ip1, dash::vnet_mapping::VnetMapping(), false); } + + dash::eni::Eni MockDashOrchTest::BuildEniEntry() + { + dash::eni::Eni eni; + std::string mac = "f4:93:9f:ef:c4:7e"; + eni.set_admin_state(dash::eni::State::STATE_ENABLED); + eni.set_eni_id(eni1); + eni.set_mac_address(mac); + eni.set_vnet(vnet1); + eni.mutable_underlay_ip()->set_ipv4(swss::IpAddress("1.2.3.4").getV4Addr()); + eni.set_eni_mode(dash::eni::MODE_VM); + return eni; + } } diff --git a/tests/mock_tests/mock_dash_orch_test.h b/tests/mock_tests/mock_dash_orch_test.h index 95f8bfae014..c554261d0e0 100644 --- a/tests/mock_tests/mock_dash_orch_test.h +++ b/tests/mock_tests/mock_dash_orch_test.h @@ -18,6 +18,7 @@ namespace mock_orch_test {APP_DASH_ENI_TABLE_NAME, (Orch**) &m_DashOrch}, }; void SetDashTable(std::string table_name, std::string key, const google::protobuf::Message &message, bool set = true, bool expect_empty = true); + dash::appliance::Appliance BuildApplianceEntry(); void CreateApplianceEntry(); void AddRoutingType(dash::route_type::EncapType encap_type); void CreateVnet(); @@ -27,11 +28,13 @@ namespace mock_orch_test void AddOutboundRoutingGroup(); void AddOutboundRoutingEntry(bool expect_empty = true); void AddTunnel(); + dash::eni::Eni BuildEniEntry(); std::string vnet1 = "VNET_1"; std::string vnet_map_ip1 = "2.2.2.2"; std::string appliance1 = "APPLIANCE_1"; std::string route_group1 = "ROUTE_GROUP_1"; std::string tunnel1 = "TUNNEL_1"; + std::string eni1 = "ENI_1"; }; } \ No newline at end of file diff --git a/tests/mock_tests/mock_orchagent_main.h b/tests/mock_tests/mock_orchagent_main.h index 517c47f8a2b..d1229930457 100644 --- a/tests/mock_tests/mock_orchagent_main.h +++ b/tests/mock_tests/mock_orchagent_main.h @@ -112,4 +112,5 @@ extern sai_dash_vnet_api_t* sai_dash_vnet_api; extern sai_dash_appliance_api_t* sai_dash_appliance_api; extern sai_dash_outbound_routing_api_t* sai_dash_outbound_routing_api; extern sai_dash_inbound_routing_api_t* sai_dash_inbound_routing_api; -extern sai_dash_tunnel_api_t* sai_dash_tunnel_api; \ No newline at end of file +extern sai_dash_tunnel_api_t* sai_dash_tunnel_api; +extern sai_dash_trusted_vni_api_t* sai_dash_trusted_vni_api; \ No newline at end of file diff --git a/tests/mock_tests/mock_sai_api.h b/tests/mock_tests/mock_sai_api.h index a47bea4065d..5cb76612b10 100644 --- a/tests/mock_tests/mock_sai_api.h +++ b/tests/mock_tests/mock_sai_api.h @@ -205,6 +205,10 @@ This is required since some sai_api do not support this function call yet. * 2. If two arguments are provided, use the second argument as the entry type (e.g. sai_dash_outbound_ca_to_pa_api_t and sai_outbound_ca_to_pa_entry_t) */ #define GET_MOCK_MACRO(_1, _2, NAME, ...) NAME +/* + * DEFINE_SAI_API_MOCK is deprecated. + * Use DEFINE_SAI_ENTRY_APIS_MOCK which supports mocking multiple entry types for a single sai api class. + */ #define DEFINE_SAI_API_MOCK(...) \ GET_MOCK_MACRO(__VA_ARGS__, DEFINE_SAI_API_MOCK_SPECIFY_ENTRY, DEFINE_SAI_API_MOCK_MATCH_ENTRY)(__VA_ARGS__) @@ -277,10 +281,30 @@ This is required since some sai_api do not support this function call yet. ON_CALL(*this, set_##sai_object_type##_attribute).WillByDefault([this](sai_object_id_t oid, const sai_attribute_t *attr) { \ return old_sai_##sai_api_name##_api->set_##sai_object_type##_attribute(oid, attr); \ }); +#define DEFINE_ENTRY_ON_CALL_DEFAULTS(sai_api_name, sai_entry_type) \ + ON_CALL(*this, create_##sai_entry_type##_entry).WillByDefault([this](CREATE_PARAMS(sai_entry_type)) { \ + return old_sai_##sai_api_name##_api->create_##sai_entry_type##_entry(CREATE_ARGS(sai_entry_type)); \ + }); \ + ON_CALL(*this, remove_##sai_entry_type##_entry).WillByDefault([this](REMOVE_PARAMS(sai_entry_type)) { \ + return old_sai_##sai_api_name##_api->remove_##sai_entry_type##_entry(REMOVE_ARGS(sai_entry_type)); \ + }); \ + ON_CALL(*this, create_##sai_entry_type##_entries).WillByDefault([this](CREATE_BULK_PARAMS(sai_entry_type)) { \ + return old_sai_##sai_api_name##_api->create_##sai_entry_type##_entries(CREATE_BULK_ARGS(sai_entry_type)); \ + }); \ + ON_CALL(*this, remove_##sai_entry_type##_entries).WillByDefault([this](REMOVE_BULK_PARAMS(sai_entry_type)) { \ + return old_sai_##sai_api_name##_api->remove_##sai_entry_type##_entries(REMOVE_BULK_ARGS(sai_entry_type)); \ + }); + #define DEFINE_MOCK_METHODS(sai_api_name, sai_object_type) \ MOCK_METHOD4(create_##sai_object_type, sai_status_t(GENERIC_CREATE_PARAMS(sai_object_type))); \ MOCK_METHOD1(remove_##sai_object_type, sai_status_t(GENERIC_REMOVE_PARAMS(sai_object_type))); \ MOCK_METHOD2(set_##sai_object_type##_attribute, sai_status_t(sai_object_id_t, const sai_attribute_t *)); +#define DEFINE_MOCK_ENTRY_METHODS(sai_api_name, sai_entry_type) \ + MOCK_METHOD3(create_##sai_entry_type##_entry, sai_status_t(CREATE_PARAMS(sai_entry_type))); \ + MOCK_METHOD1(remove_##sai_entry_type##_entry, sai_status_t(REMOVE_PARAMS(sai_entry_type))); \ + MOCK_METHOD6(create_##sai_entry_type##_entries, sai_status_t(CREATE_BULK_PARAMS(sai_entry_type))); \ + MOCK_METHOD4(remove_##sai_entry_type##_entries, sai_status_t(REMOVE_BULK_PARAMS(sai_entry_type))); + #define DEFINE_WRAPPER_FUNCTIONS(sai_api_name, sai_object_type) \ inline sai_status_t mock_create_##sai_object_type(GENERIC_CREATE_PARAMS(sai_object_type)) { \ return mock_sai_##sai_api_name##_api->create_##sai_object_type(GENERIC_CREATE_ARGS(sai_object_type)); \ @@ -291,10 +315,29 @@ This is required since some sai_api do not support this function call yet. inline sai_status_t mock_set_##sai_object_type##_attribute(sai_object_id_t oid, const sai_attribute_t *attr) { \ return mock_sai_##sai_api_name##_api->set_##sai_object_type##_attribute(oid, attr); \ } +#define DEFINE_ENTRY_WRAPPER_FUNCTIONS(sai_api_name, sai_entry_type) \ + inline sai_status_t mock_create_##sai_entry_type##_entry(CREATE_PARAMS(sai_entry_type)) { \ + return mock_sai_##sai_api_name##_api->create_##sai_entry_type##_entry(CREATE_ARGS(sai_entry_type)); \ + } \ + inline sai_status_t mock_remove_##sai_entry_type##_entry(REMOVE_PARAMS(sai_entry_type)) { \ + return mock_sai_##sai_api_name##_api->remove_##sai_entry_type##_entry(REMOVE_ARGS(sai_entry_type)); \ + } \ + inline sai_status_t mock_create_##sai_entry_type##_entries(CREATE_BULK_PARAMS(sai_entry_type)) { \ + return mock_sai_##sai_api_name##_api->create_##sai_entry_type##_entries(CREATE_BULK_ARGS(sai_entry_type)); \ + } \ + inline sai_status_t mock_remove_##sai_entry_type##_entries(REMOVE_BULK_PARAMS(sai_entry_type)) { \ + return mock_sai_##sai_api_name##_api->remove_##sai_entry_type##_entries(REMOVE_BULK_ARGS(sai_entry_type)); \ + } + #define APPLY_MOCK_FUNCTIONS(sai_api_name, sai_object_type) \ sai_##sai_api_name##_api->create_##sai_object_type = mock_create_##sai_object_type; \ sai_##sai_api_name##_api->remove_##sai_object_type = mock_remove_##sai_object_type; \ sai_##sai_api_name##_api->set_##sai_object_type##_attribute = mock_set_##sai_object_type##_attribute; +#define APPLY_ENTRY_MOCK_FUNCTIONS(sai_api_name, sai_entry_type) \ + sai_##sai_api_name##_api->create_##sai_entry_type##_entry = mock_create_##sai_entry_type##_entry; \ + sai_##sai_api_name##_api->remove_##sai_entry_type##_entry = mock_remove_##sai_entry_type##_entry; \ + sai_##sai_api_name##_api->create_##sai_entry_type##_entries = mock_create_##sai_entry_type##_entries; \ + sai_##sai_api_name##_api->remove_##sai_entry_type##_entries = mock_remove_##sai_entry_type##_entries; #define DEFINE_SAI_GENERIC_APIS_MOCK(sai_api_name, ...) \ static sai_##sai_api_name##_api_t *old_sai_##sai_api_name##_api; \ @@ -319,6 +362,29 @@ This is required since some sai_api do not support this function call yet. sai_##sai_api_name##_api = old_sai_##sai_api_name##_api; \ delete mock_sai_##sai_api_name##_api; \ } +#define DEFINE_SAI_ENTRY_APIS_MOCK(sai_api_name, ...) \ + static sai_##sai_api_name##_api_t *old_sai_##sai_api_name##_api; \ + static sai_##sai_api_name##_api_t ut_sai_##sai_api_name##_api; \ + class mock_sai_##sai_api_name##_api_t { \ + public: \ + mock_sai_##sai_api_name##_api_t() { \ + FOR_EACH(DEFINE_ENTRY_ON_CALL_DEFAULTS, sai_api_name, __VA_ARGS__) \ + } \ + FOR_EACH(DEFINE_MOCK_ENTRY_METHODS, sai_api_name, __VA_ARGS__) \ + }; \ + static mock_sai_##sai_api_name##_api_t *mock_sai_##sai_api_name##_api; \ + FOR_EACH(DEFINE_ENTRY_WRAPPER_FUNCTIONS, sai_api_name, __VA_ARGS__) \ + inline void apply_sai_##sai_api_name##_api_mock() { \ + mock_sai_##sai_api_name##_api = new NiceMock(); \ + old_sai_##sai_api_name##_api = sai_##sai_api_name##_api; \ + ut_sai_##sai_api_name##_api = *sai_##sai_api_name##_api; \ + sai_##sai_api_name##_api = &ut_sai_##sai_api_name##_api; \ + FOR_EACH(APPLY_ENTRY_MOCK_FUNCTIONS, sai_api_name, __VA_ARGS__) \ + } \ + inline void remove_sai_##sai_api_name##_api_mock() { \ + sai_##sai_api_name##_api = old_sai_##sai_api_name##_api; \ + delete mock_sai_##sai_api_name##_api; \ + } #define DEFINE_SAI_GENERIC_API_OBJECT_BULK_MOCK(sai_api_name, sai_object_type) \ static sai_##sai_api_name##_api_t *old_sai_##sai_api_name##_api; \ diff --git a/tests/mock_tests/ut_saihelper.cpp b/tests/mock_tests/ut_saihelper.cpp index e13882c4074..def88394c4a 100644 --- a/tests/mock_tests/ut_saihelper.cpp +++ b/tests/mock_tests/ut_saihelper.cpp @@ -102,6 +102,7 @@ namespace ut_helper sai_api_query((sai_api_t)SAI_API_DASH_OUTBOUND_ROUTING, (void**)&sai_dash_outbound_routing_api); sai_api_query((sai_api_t)SAI_API_DASH_INBOUND_ROUTING, (void**)&sai_dash_inbound_routing_api); sai_api_query((sai_api_t)SAI_API_DASH_TUNNEL, (void**)&sai_dash_tunnel_api); + sai_api_query((sai_api_t)SAI_API_DASH_TRUSTED_VNI, (void**)&sai_dash_trusted_vni_api); sai_api_query(SAI_API_STP, (void**)&sai_stp_api); return SAI_STATUS_SUCCESS; }