diff --git a/.azure-pipelines/build-docker-sonic-vs-template.yml b/.azure-pipelines/build-docker-sonic-vs-template.yml index 2610fcb837..127145e949 100644 --- a/.azure-pipelines/build-docker-sonic-vs-template.yml +++ b/.azure-pipelines/build-docker-sonic-vs-template.yml @@ -88,9 +88,12 @@ jobs: project: ${{ parameters.sairedis_artifact_project }} pipeline: ${{ parameters.sairedis_artifact_pipeline }} artifact: ${{ parameters.sairedis_artifact_name }} - runVersion: 'latestFromBranch' - runBranch: 'refs/heads/${{ parameters.sairedis_artifact_branch }}' + runVersion: 'specific' + pipelineId: 613643 + # runVersion: 'latestFromBranch' + # runBranch: 'refs/heads/${{ parameters.sairedis_artifact_branch }}' allowPartiallySucceededBuilds: true + allowFailedBuilds: true path: $(Build.ArtifactStagingDirectory)/download/sairedis patterns: | ${{ parameters.sairedis_artifact_pattern }}/libsaivs_*.deb diff --git a/.azure-pipelines/build-template.yml b/.azure-pipelines/build-template.yml index 0a680e35de..94d204f24f 100644 --- a/.azure-pipelines/build-template.yml +++ b/.azure-pipelines/build-template.yml @@ -127,9 +127,12 @@ jobs: project: ${{ parameters.sairedis_artifact_project }} pipeline: ${{ parameters.sairedis_artifact_pipeline }} artifact: ${{ parameters.sairedis_artifact_name }} - runVersion: 'latestFromBranch' - runBranch: 'refs/heads/${{ parameters.sairedis_artifact_branch }}' + runVersion: 'specific' + pipelineId: 613643 + # runVersion: 'latestFromBranch' + # runBranch: 'refs/heads/${{ parameters.sairedis_artifact_branch }}' allowPartiallySucceededBuilds: true + allowFailedBuilds: true path: $(Build.ArtifactStagingDirectory)/download/sairedis patterns: | ${{ parameters.sairedis_artifact_pattern }}/libsaivs_*.deb diff --git a/.azure-pipelines/test-docker-sonic-vs-template.yml b/.azure-pipelines/test-docker-sonic-vs-template.yml index db66b03472..24fc8b8738 100644 --- a/.azure-pipelines/test-docker-sonic-vs-template.yml +++ b/.azure-pipelines/test-docker-sonic-vs-template.yml @@ -136,7 +136,7 @@ jobs: fi all_tests=$(ls test_*.py | xargs) - all_tests="${all_tests} p4rt" + all_tests="${all_tests} p4rt dash" if [ -n '${{ parameters.run_tests_pattern }}' ]; then all_tests=" $(ls ${{ parameters.run_tests_pattern }} | xargs) " diff --git a/orchagent/bulker.h b/orchagent/bulker.h index 86308329b9..ee6f1b7568 100644 --- a/orchagent/bulker.h +++ b/orchagent/bulker.h @@ -134,7 +134,7 @@ static inline bool operator==(const sai_pa_validation_entry_t& a, const sai_pa_v static inline bool operator==(const sai_outbound_routing_entry_t& a, const sai_outbound_routing_entry_t& b) { return a.switch_id == b.switch_id - && a.eni_id == b.eni_id + && a.outbound_routing_group_id == b.outbound_routing_group_id && a.destination == b.destination ; } @@ -257,7 +257,7 @@ namespace std { size_t seed = 0; boost::hash_combine(seed, a.switch_id); - boost::hash_combine(seed, a.eni_id); + boost::hash_combine(seed, a.outbound_routing_group_id); boost::hash_combine(seed, a.destination); return seed; } diff --git a/orchagent/dash/dashorch.cpp b/orchagent/dash/dashorch.cpp index d7c7818e5a..c43092b1cf 100644 --- a/orchagent/dash/dashorch.cpp +++ b/orchagent/dash/dashorch.cpp @@ -17,13 +17,16 @@ #include "tokenize.h" #include "crmorch.h" #include "saihelper.h" +#include "directory.h" #include "taskworker.h" #include "pbutils.h" +#include "dashrouteorch.h" using namespace std; using namespace swss; +extern Directory gDirectory; extern std::unordered_map gVnetNameToId; extern sai_dash_vip_api_t* sai_dash_vip_api; extern sai_dash_direction_lookup_api_t* sai_dash_direction_lookup_api; @@ -37,6 +40,21 @@ DashOrch::DashOrch(DBConnector *db, vector &tableName, ZmqServer *zmqSer SWSS_LOG_ENTER(); } +bool DashOrch::getRouteTypeActions(dash::route_type::RoutingType routing_type, dash::route_type::RouteType& route_type) +{ + SWSS_LOG_ENTER(); + + auto it = routing_type_entries_.find(routing_type); + if (it == routing_type_entries_.end()) + { + SWSS_LOG_WARN("Routing type %s not found", dash::route_type::RoutingType_Name(routing_type).c_str()); + return false; + } + + route_type = it->second; + return true; +} + bool DashOrch::addApplianceEntry(const string& appliance_id, const dash::appliance::Appliance &entry) { SWSS_LOG_ENTER(); @@ -191,34 +209,34 @@ void DashOrch::doTaskApplianceTable(ConsumerBase& consumer) } } -bool DashOrch::addRoutingTypeEntry(const string& routing_type, const dash::route_type::RouteType &entry) +bool DashOrch::addRoutingTypeEntry(const dash::route_type::RoutingType& routing_type, const dash::route_type::RouteType &entry) { SWSS_LOG_ENTER(); if (routing_type_entries_.find(routing_type) != routing_type_entries_.end()) { - SWSS_LOG_WARN("Routing type entry already exists for %s", routing_type.c_str()); + SWSS_LOG_WARN("Routing type entry already exists for %s", dash::route_type::RoutingType_Name(routing_type).c_str()); return true; } routing_type_entries_[routing_type] = entry; - SWSS_LOG_NOTICE("Routing type entry added %s", routing_type.c_str()); + SWSS_LOG_NOTICE("Routing type entry added %s", dash::route_type::RoutingType_Name(routing_type).c_str()); return true; } -bool DashOrch::removeRoutingTypeEntry(const string& routing_type) +bool DashOrch::removeRoutingTypeEntry(const dash::route_type::RoutingType& routing_type) { SWSS_LOG_ENTER(); if (routing_type_entries_.find(routing_type) == routing_type_entries_.end()) { - SWSS_LOG_WARN("Routing type entry does not exist for %s", routing_type.c_str()); + SWSS_LOG_WARN("Routing type entry does not exist for %s", dash::route_type::RoutingType_Name(routing_type).c_str()); return true; } routing_type_entries_.erase(routing_type); - SWSS_LOG_NOTICE("Routing type entry removed for %s", routing_type.c_str()); + SWSS_LOG_NOTICE("Routing type entry removed for %s", dash::route_type::RoutingType_Name(routing_type).c_str()); return true; } @@ -231,8 +249,19 @@ void DashOrch::doTaskRoutingTypeTable(ConsumerBase& consumer) while (it != consumer.m_toSync.end()) { KeyOpFieldsValuesTuple t = it->second; - string routing_type = kfvKey(t); + string routing_type_str = kfvKey(t); string op = kfvOp(t); + dash::route_type::RoutingType routing_type; + + std::transform(routing_type_str.begin(), routing_type_str.end(), routing_type_str.begin(), ::toupper); + routing_type_str = "ROUTING_TYPE_" + routing_type_str; + + if (!dash::route_type::RoutingType_Parse(routing_type_str, &routing_type)) + { + SWSS_LOG_WARN("Invalid routing type %s", routing_type_str.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } if (op == SET_COMMAND) { @@ -240,7 +269,7 @@ void DashOrch::doTaskRoutingTypeTable(ConsumerBase& consumer) if (!parsePbMessage(kfvFieldsValues(t), entry)) { - SWSS_LOG_WARN("Requires protobuff at routing type :%s", routing_type.c_str()); + SWSS_LOG_WARN("Requires protobuff at routing type :%s", routing_type_str.c_str()); it = consumer.m_toSync.erase(it); continue; } @@ -358,6 +387,23 @@ bool DashOrch::addEniObject(const string& eni, EniEntry& entry) eni_attr.value.u32 = app_entry.vm_vni(); eni_attrs.push_back(eni_attr); + if (entry.metadata.has_pl_underlay_sip()) + { + eni_attr.id = SAI_ENI_ATTR_PL_UNDERLAY_SIP; + to_sai(entry.metadata.pl_underlay_sip(), eni_attr.value.ipaddr); + eni_attrs.push_back(eni_attr); + } + + // auto eni_route_it = eni_route_entries_.find(eni); + // if (eni_route_it != eni_route_entries_.end()) + // { + // SWSS_LOG_INFO("ENI %s has route group %s", eni.c_str(), eni_route_it->second.group_id().c_str()); + // DashRouteOrch *dash_route_orch = gDirectory.get(); + // eni_attr.id = SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID; + // eni_attr.value.oid = dash_route_orch->getRouteGroupOid(eni_route_it->second.group_id()); + // eni_attrs.push_back(eni_attr); + // } + sai_status_t status = sai_dash_eni_api->create_eni(&eni_id, gSwitchId, (uint32_t)eni_attrs.size(), eni_attrs.data()); if (status != SAI_STATUS_SUCCESS) @@ -653,6 +699,154 @@ void DashOrch::doTaskQosTable(ConsumerBase& consumer) } } +bool DashOrch::setEniRoute(const std::string& eni, const dash::eni_route::EniRoute& entry) +{ + SWSS_LOG_ENTER(); + + + if (eni_entries_.find(eni) == eni_entries_.end()) + { + SWSS_LOG_INFO("ENI %s not yet created, not programming ENI route entry", eni.c_str()); + return false; + } + + DashRouteOrch *dash_route_orch = gDirectory.get(); + sai_object_id_t route_group_oid = dash_route_orch->getRouteGroupOid(entry.group_id()); + if (route_group_oid == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_INFO("Route group not yet created, skipping route entry for ENI %s", entry.group_id().c_str()); + return false; + } + + std::string old_group_id; + if (eni_route_entries_.find(eni) != eni_route_entries_.end()) + { + if (eni_route_entries_[eni].group_id() != entry.group_id()) + { + old_group_id = eni_route_entries_[eni].group_id(); + SWSS_LOG_INFO("Updating route entry from %s to %s for ENI %s", eni_route_entries_[eni].group_id().c_str(), entry.group_id().c_str(), eni.c_str()); + } + else + { + SWSS_LOG_WARN("Duplicate ENI route entry already exists for %s", eni.c_str()); + return true; + } + } + + sai_attribute_t eni_attr; + eni_attr.id = SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID; + eni_attr.value.oid = route_group_oid; + + sai_status_t status = sai_dash_eni_api->set_eni_attribute(eni_entries_[eni].eni_id, + &eni_attr); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set ENI route group for %s", eni.c_str()); + task_process_status handle_status = handleSaiSetStatus((sai_api_t) SAI_API_DASH_ENI, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + eni_route_entries_[eni] = entry; + dash_route_orch->bindRouteGroup(entry.group_id()); + + if (!old_group_id.empty()) + { + dash_route_orch->unbindRouteGroup(old_group_id); + } + + SWSS_LOG_NOTICE("Updated ENI route group for %s to route group %s", eni.c_str(), entry.group_id().c_str()); + return true; +} + +bool DashOrch::removeEniRoute(const std::string& eni) +{ + SWSS_LOG_ENTER(); + + if (eni_route_entries_.find(eni) == eni_route_entries_.end()) + { + SWSS_LOG_WARN("ENI route entry does not exist for %s", eni.c_str()); + return true; + } + + if (eni_entries_.find(eni) != eni_entries_.end()) + { + sai_attribute_t eni_attr; + eni_attr.id = SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID; + eni_attr.value.oid = SAI_NULL_OBJECT_ID; + + sai_status_t status = sai_dash_eni_api->set_eni_attribute(eni_entries_[eni].eni_id, + &eni_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove ENI route for %s", eni.c_str()); + task_process_status handle_status = handleSaiSetStatus((sai_api_t) SAI_API_DASH_ENI, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + } + + DashRouteOrch *dash_route_orch = gDirectory.get(); + dash_route_orch->unbindRouteGroup(eni_route_entries_[eni].group_id()); + eni_route_entries_.erase(eni); + + SWSS_LOG_NOTICE("Removed ENI route entry for %s", eni.c_str()); + + return true; +} + +void DashOrch::doTaskEniRouteTable(ConsumerBase& consumer) +{ + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + string eni = kfvKey(t); + string op = kfvOp(t); + + if (op == SET_COMMAND) + { + dash::eni_route::EniRoute entry; + + if (!parsePbMessage(kfvFieldsValues(t), entry)) + { + SWSS_LOG_WARN("Requires protobuf at ENI route:%s", eni.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + + if (setEniRoute(eni, entry)) + { + it = consumer.m_toSync.erase(it); + } + else + { + it++; + } + } + else if (op == DEL_COMMAND) + { + if (removeEniRoute(eni)) + { + it = consumer.m_toSync.erase(it); + } + else + { + it++; + } + } + else + { + SWSS_LOG_ERROR("Unknown operation %s", op.c_str()); + it = consumer.m_toSync.erase(it); + } + } +} + void DashOrch::doTask(ConsumerBase& consumer) { SWSS_LOG_ENTER(); @@ -677,6 +871,10 @@ void DashOrch::doTask(ConsumerBase& consumer) { doTaskQosTable(consumer); } + else if (tn == APP_DASH_ENI_ROUTE_TABLE_NAME) + { + doTaskEniRouteTable(consumer); + } else { SWSS_LOG_ERROR("Unknown table: %s", tn.c_str()); diff --git a/orchagent/dash/dashorch.h b/orchagent/dash/dashorch.h index eca365225c..e2b6e3554d 100644 --- a/orchagent/dash/dashorch.h +++ b/orchagent/dash/dashorch.h @@ -22,6 +22,7 @@ #include "dash_api/route_type.pb.h" #include "dash_api/eni.pb.h" #include "dash_api/qos.pb.h" +#include "dash_api/eni_route.pb.h" struct EniEntry { @@ -30,30 +31,35 @@ struct EniEntry }; typedef std::map ApplianceTable; -typedef std::map RoutingTypeTable; +typedef std::map RoutingTypeTable; typedef std::map EniTable; typedef std::map QosTable; +typedef std::map EniRouteTable; class DashOrch : public ZmqOrch { public: DashOrch(swss::DBConnector *db, std::vector &tables, swss::ZmqServer *zmqServer); const EniEntry *getEni(const std::string &eni) const; + bool getRouteTypeActions(dash::route_type::RoutingType routing_type, dash::route_type::RouteType& route_type); private: ApplianceTable appliance_entries_; RoutingTypeTable routing_type_entries_; EniTable eni_entries_; QosTable qos_entries_; + EniRouteTable eni_route_entries_; void doTask(ConsumerBase &consumer); void doTaskApplianceTable(ConsumerBase &consumer); void doTaskRoutingTypeTable(ConsumerBase &consumer); void doTaskEniTable(ConsumerBase &consumer); void doTaskQosTable(ConsumerBase &consumer); + void doTaskEniRouteTable(ConsumerBase &consumer); + void doTaskRouteGroupTable(ConsumerBase &consumer); bool addApplianceEntry(const std::string& appliance_id, const dash::appliance::Appliance &entry); bool removeApplianceEntry(const std::string& appliance_id); - bool addRoutingTypeEntry(const std::string& routing_type, const dash::route_type::RouteType &entry); - bool removeRoutingTypeEntry(const std::string& routing_type); + 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); bool addEni(const std::string& eni, EniEntry &entry); @@ -63,4 +69,6 @@ class DashOrch : public ZmqOrch bool setEniAdminState(const std::string& eni, const EniEntry& entry); bool addQosEntry(const std::string& qos_name, const dash::qos::Qos &entry); bool removeQosEntry(const std::string& qos_name); + bool setEniRoute(const std::string& eni, const dash::eni_route::EniRoute& entry); + bool removeEniRoute(const std::string& eni); }; diff --git a/orchagent/dash/dashrouteorch.cpp b/orchagent/dash/dashrouteorch.cpp index cb3eedbfdc..06de34a05d 100644 --- a/orchagent/dash/dashrouteorch.cpp +++ b/orchagent/dash/dashrouteorch.cpp @@ -61,9 +61,16 @@ bool DashRouteOrch::addOutboundRouting(const string& key, OutboundRoutingBulkCon SWSS_LOG_WARN("Outbound routing entry already exists for %s", key.c_str()); return true; } - if (!dash_orch_->getEni(ctxt.eni)) + + if (isRouteGroupBound(ctxt.route_group)) { - SWSS_LOG_INFO("Retry as ENI entry %s not found", ctxt.eni.c_str()); + SWSS_LOG_WARN("Cannot add new route to route group %s as it is already bound", ctxt.route_group.c_str()); + return true; + } + sai_object_id_t route_group_oid = this->getRouteGroupOid(ctxt.route_group); + if (route_group_oid == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_INFO("Retry as route group %s not found", ctxt.route_group.c_str()); return false; } if (ctxt.metadata.has_vnet() && gVnetNameToId.find(ctxt.metadata.vnet()) == gVnetNameToId.end()) @@ -74,14 +81,22 @@ bool DashRouteOrch::addOutboundRouting(const string& key, OutboundRoutingBulkCon sai_outbound_routing_entry_t outbound_routing_entry; outbound_routing_entry.switch_id = gSwitchId; - outbound_routing_entry.eni_id = dash_orch_->getEni(ctxt.eni)->eni_id; + outbound_routing_entry.outbound_routing_group_id = route_group_oid; swss::copy(outbound_routing_entry.destination, ctxt.destination); sai_attribute_t outbound_routing_attr; vector outbound_routing_attrs; auto& object_statuses = ctxt.object_statuses; + auto it = sOutboundAction.find(ctxt.metadata.routing_type()); + if (it == sOutboundAction.end()) + { + std::string routing_type_str = dash::route_type::RoutingType_Name(ctxt.metadata.routing_type()); + SWSS_LOG_WARN("Routing type %s for outbound routing entry %s not allowed", routing_type_str.c_str(), key.c_str()); + return false; + } + outbound_routing_attr.id = SAI_OUTBOUND_ROUTING_ENTRY_ATTR_ACTION; - outbound_routing_attr.value.u32 = sOutboundAction[ctxt.metadata.routing_type()]; + outbound_routing_attr.value.u32 = it->second; outbound_routing_attrs.push_back(outbound_routing_attr); if (ctxt.metadata.routing_type() == dash::route_type::RoutingType::ROUTING_TYPE_DIRECT) @@ -114,10 +129,21 @@ bool DashRouteOrch::addOutboundRouting(const string& key, OutboundRoutingBulkCon } else { - SWSS_LOG_WARN("Attribute action for outbound routing entry %s", key.c_str()); + SWSS_LOG_WARN("Routing type %s for outbound routing entry %s either invalid or missing required attributes", + dash::route_type::RoutingType_Name(ctxt.metadata.routing_type()).c_str(), key.c_str()); return false; } + if (ctxt.metadata.has_underlay_sip() && ctxt.metadata.underlay_sip().has_ipv4()) + { + outbound_routing_attr.id = SAI_OUTBOUND_ROUTING_ENTRY_ATTR_UNDERLAY_SIP; + if (!to_sai(ctxt.metadata.underlay_sip(), outbound_routing_attr.value.ipaddr)) + { + return false; + } + outbound_routing_attrs.push_back(outbound_routing_attr); + } + object_statuses.emplace_back(); outbound_routing_bulker_.create_entry(&object_statuses.back(), &outbound_routing_entry, (uint32_t)outbound_routing_attrs.size(), outbound_routing_attrs.data()); @@ -153,7 +179,7 @@ bool DashRouteOrch::addOutboundRoutingPost(const string& key, const OutboundRout } } - OutboundRoutingEntry entry = { dash_orch_->getEni(ctxt.eni)->eni_id, ctxt.destination, ctxt.metadata }; + OutboundRoutingEntry entry = { this->getRouteGroupOid(ctxt.route_group), ctxt.destination, ctxt.metadata }; routing_entries_[key] = entry; gCrmOrch->incCrmResUsedCounter(ctxt.destination.isV4() ? CrmResourceType::CRM_DASH_IPV4_OUTBOUND_ROUTING : CrmResourceType::CRM_DASH_IPV6_OUTBOUND_ROUTING); @@ -174,11 +200,17 @@ bool DashRouteOrch::removeOutboundRouting(const string& key, OutboundRoutingBulk return true; } + if (isRouteGroupBound(ctxt.route_group)) + { + SWSS_LOG_WARN("Cannot remove route from route group %s as it is already bound", ctxt.route_group.c_str()); + return true; + } + auto& object_statuses = ctxt.object_statuses; OutboundRoutingEntry entry = routing_entries_[key]; sai_outbound_routing_entry_t outbound_routing_entry; outbound_routing_entry.switch_id = gSwitchId; - outbound_routing_entry.eni_id = entry.eni; + outbound_routing_entry.outbound_routing_group_id = entry.route_group; swss::copy(outbound_routing_entry.destination, entry.destination); object_statuses.emplace_back(); outbound_routing_bulker_.remove_entry(&object_statuses.back(), &outbound_routing_entry); @@ -248,13 +280,13 @@ void DashRouteOrch::doTaskRouteTable(ConsumerBase& consumer) ctxt.clear(); } - string& eni = ctxt.eni; + string& route_group = ctxt.route_group; IpPrefix& destination = ctxt.destination; vector keys = tokenize(key, ':'); - eni = keys[0]; + route_group = keys[0]; string ip_str; - size_t pos = key.find(":", eni.length()); + size_t pos = key.find(":", route_group.length()); ip_str = key.substr(pos + 1); destination = IpPrefix(ip_str); @@ -630,6 +662,170 @@ void DashRouteOrch::doTaskRouteRuleTable(ConsumerBase& consumer) } } +bool DashRouteOrch::addRouteGroup(const string& route_group, const dash::route_group::RouteGroup& entry) +{ + SWSS_LOG_ENTER(); + + sai_object_id_t route_group_oid = this->getRouteGroupOid(route_group); + if (route_group_oid != SAI_NULL_OBJECT_ID) + { + SWSS_LOG_WARN("Route group %s already exists", route_group.c_str()); + return true; + } + + sai_status_t status = sai_dash_outbound_routing_api->create_outbound_routing_group(&route_group_oid, gSwitchId, 0, NULL); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create route group %s", route_group.c_str()); + task_process_status handle_status = handleSaiCreateStatus((sai_api_t) SAI_API_DASH_OUTBOUND_ROUTING, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + + route_group_oid_map_[route_group] = route_group_oid; + SWSS_LOG_INFO("Route group %s added", route_group.c_str()); + + return true; +} + +bool DashRouteOrch::removeRouteGroup(const string& route_group) +{ + SWSS_LOG_ENTER(); + + if (isRouteGroupBound(route_group)) + { + SWSS_LOG_WARN("Cannot remove bound route group %s", route_group.c_str()); + return false; + } + + sai_object_id_t route_group_oid = this->getRouteGroupOid(route_group); + if (route_group_oid == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_INFO("Failed to find route group %s to remove", route_group.c_str()); + return true; + } + + sai_status_t status = sai_dash_outbound_routing_api->remove_outbound_routing_group(route_group_oid); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove route group %s", route_group.c_str()); + task_process_status handle_status = handleSaiRemoveStatus((sai_api_t) SAI_API_DASH_OUTBOUND_ROUTING, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + + route_group_oid_map_.erase(route_group); + SWSS_LOG_INFO("Route group %s removed", route_group.c_str()); + + return true; +} + +sai_object_id_t DashRouteOrch::getRouteGroupOid(const string& route_group) const +{ + SWSS_LOG_ENTER(); + + auto it = route_group_oid_map_.find(route_group); + if (it == route_group_oid_map_.end()) + { + return SAI_NULL_OBJECT_ID; + } + + return it->second; +} + +void DashRouteOrch::bindRouteGroup(const std::string& route_group) +{ + auto it = route_group_bind_count_.find(route_group); + + if (it == route_group_bind_count_.end()) + { + route_group_bind_count_[route_group] = 1; + return; + } + it->second++; +} + +void DashRouteOrch::unbindRouteGroup(const std::string& route_group) +{ + auto it = route_group_bind_count_.find(route_group); + + if (it == route_group_bind_count_.end()) + { + SWSS_LOG_WARN("Cannot unbind route group %s since it is not bound to any ENIs", route_group.c_str()); + return; + } + it->second--; + + if (it->second == 0) + { + SWSS_LOG_INFO("Route group %s completely unbound", route_group.c_str()); + route_group_bind_count_.erase(it); + } +} + +bool DashRouteOrch::isRouteGroupBound(const std::string& route_group) const +{ + auto it = route_group_bind_count_.find(route_group); + if (it == route_group_bind_count_.end()) + { + return false; + } + return it->second > 0; +} + +void DashRouteOrch::doTaskRouteGroupTable(ConsumerBase& consumer) +{ + SWSS_LOG_ENTER(); + + auto it = consumer.m_toSync.begin(); + + while (it != consumer.m_toSync.end()) + { + auto t = it->second; + string route_group = kfvKey(t); + string op = kfvOp(t); + if (op == SET_COMMAND) + { + dash::route_group::RouteGroup entry; + if (!parsePbMessage(kfvFieldsValues(t), entry)) + { + SWSS_LOG_WARN("Requires protobuf at RouteGroup :%s", route_group.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + + if (addRouteGroup(route_group, entry)) + { + it = consumer.m_toSync.erase(it); + } + else + { + it++; + } + } + else if (op == DEL_COMMAND) + { + if (removeRouteGroup(route_group)) + { + it = consumer.m_toSync.erase(it); + } + else + { + it++; + } + } + else + { + SWSS_LOG_ERROR("Unknown operation %s", op.c_str()); + it = consumer.m_toSync.erase(it); + } + } +} + void DashRouteOrch::doTask(ConsumerBase& consumer) { SWSS_LOG_ENTER(); @@ -646,6 +842,10 @@ void DashRouteOrch::doTask(ConsumerBase& consumer) { doTaskRouteRuleTable(consumer); } + else if (tn == APP_DASH_ROUTE_GROUP_TABLE_NAME) + { + doTaskRouteGroupTable(consumer); + } else { SWSS_LOG_ERROR("Unknown table: %s", tn.c_str()); diff --git a/orchagent/dash/dashrouteorch.h b/orchagent/dash/dashrouteorch.h index d61fcaa936..0813de7e21 100644 --- a/orchagent/dash/dashrouteorch.h +++ b/orchagent/dash/dashrouteorch.h @@ -18,11 +18,12 @@ #include "dash_api/route.pb.h" #include "dash_api/route_rule.pb.h" +#include "dash_api/route_group.pb.h" struct OutboundRoutingEntry { - sai_object_id_t eni; + sai_object_id_t route_group; swss::IpPrefix destination; dash::route::Route metadata; }; @@ -41,7 +42,7 @@ typedef std::map RoutingRuleTable; struct OutboundRoutingBulkContext { - std::string eni; + std::string route_group; swss::IpPrefix destination; dash::route::Route metadata; std::deque object_statuses; @@ -77,6 +78,10 @@ class DashRouteOrch : public ZmqOrch { public: DashRouteOrch(swss::DBConnector *db, std::vector &tables, DashOrch *dash_orch, swss::ZmqServer *zmqServer); + sai_object_id_t getRouteGroupOid(const std::string& route_group) const; + void bindRouteGroup(const std::string& route_group); + void unbindRouteGroup(const std::string& route_group); + bool isRouteGroupBound(const std::string& route_group) const; private: RoutingTable routing_entries_; @@ -84,10 +89,13 @@ class DashRouteOrch : public ZmqOrch EntityBulker outbound_routing_bulker_; EntityBulker inbound_routing_bulker_; DashOrch *dash_orch_; + std::unordered_map route_group_oid_map_; + std::unordered_map route_group_bind_count_; void doTask(ConsumerBase &consumer); void doTaskRouteTable(ConsumerBase &consumer); void doTaskRouteRuleTable(ConsumerBase &consumer); + void doTaskRouteGroupTable(ConsumerBase &consumer); bool addOutboundRouting(const std::string& key, OutboundRoutingBulkContext& ctxt); bool addOutboundRoutingPost(const std::string& key, const OutboundRoutingBulkContext& ctxt); bool removeOutboundRouting(const std::string& key, OutboundRoutingBulkContext& ctxt); @@ -96,4 +104,7 @@ class DashRouteOrch : public ZmqOrch bool addInboundRoutingPost(const std::string& key, const InboundRoutingBulkContext& ctxt); bool removeInboundRouting(const std::string& key, InboundRoutingBulkContext& ctxt); bool removeInboundRoutingPost(const std::string& key, const InboundRoutingBulkContext& ctxt); + bool addRouteGroup(const std::string& key, const dash::route_group::RouteGroup& entry); + bool removeRouteGroup(const std::string& key); + }; diff --git a/orchagent/dash/dashvnetorch.cpp b/orchagent/dash/dashvnetorch.cpp index e06f1b1e38..b2f257ecc4 100644 --- a/orchagent/dash/dashvnetorch.cpp +++ b/orchagent/dash/dashvnetorch.cpp @@ -20,6 +20,7 @@ #include "dashorch.h" #include "crmorch.h" #include "saihelper.h" +#include "directory.h" #include "taskworker.h" #include "pbutils.h" @@ -34,6 +35,7 @@ extern sai_dash_pa_validation_api_t* sai_dash_pa_validation_api; extern sai_object_id_t gSwitchId; extern size_t gMaxBulkSize; extern CrmOrch *gCrmOrch; +extern Directory gDirectory; DashVnetOrch::DashVnetOrch(DBConnector *db, vector &tables, ZmqServer *zmqServer) : vnet_bulker_(sai_dash_vnet_api, gSwitchId, gMaxBulkSize), @@ -283,10 +285,67 @@ void DashVnetOrch::addOutboundCaToPa(const string& key, VnetMapBulkContext& ctxt auto& object_statuses = ctxt.outbound_ca_to_pa_object_statuses; sai_attribute_t outbound_ca_to_pa_attr; vector outbound_ca_to_pa_attrs; + + DashOrch* dash_orch = gDirectory.get(); + dash::route_type::RouteType route_type_actions; + if (!dash_orch->getRouteTypeActions(ctxt.metadata.routing_type(), route_type_actions)) + { + SWSS_LOG_INFO("Failed to get route type actions for %s", key.c_str()); + } - outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_UNDERLAY_DIP; - to_sai(ctxt.metadata.underlay_ip(), outbound_ca_to_pa_attr.value.ipaddr); - outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + for (auto action: route_type_actions.items()) + { + if (action.action_type() == dash::route_type::ACTION_TYPE_STATICENCAP) + { + outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_DASH_ENCAPSULATION; + if (action.encap_type() == dash::route_type::ENCAP_TYPE_VXLAN) + { + outbound_ca_to_pa_attr.value.u32 = SAI_DASH_ENCAPSULATION_VXLAN; + } + else if (action.encap_type() == dash::route_type::ENCAP_TYPE_NVGRE) + { + outbound_ca_to_pa_attr.value.u32 = SAI_DASH_ENCAPSULATION_NVGRE; + } + else + { + SWSS_LOG_ERROR("Invalid encap type %d for %s", action.encap_type(), key.c_str()); + return; + } + outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + + outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_TUNNEL_KEY; + outbound_ca_to_pa_attr.value.u32 = action.vni(); + outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + } + } + + if (ctxt.metadata.routing_type() == dash::route_type::ROUTING_TYPE_PRIVATELINK) + { + outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_ACTION; + outbound_ca_to_pa_attr.value.u32 = SAI_OUTBOUND_CA_TO_PA_ENTRY_ACTION_SET_PRIVATE_LINK_MAPPING; + outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + + outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_UNDERLAY_DIP; + to_sai(ctxt.metadata.underlay_ip(), outbound_ca_to_pa_attr.value.ipaddr); + outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + + outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP; + to_sai(ctxt.metadata.overlay_dip_prefix().ip(), outbound_ca_to_pa_attr.value.ipaddr); + outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + + outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP_MASK; + to_sai(ctxt.metadata.overlay_dip_prefix().mask(), outbound_ca_to_pa_attr.value.ipaddr); + outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + + + outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_SIP; + to_sai(ctxt.metadata.overlay_sip_prefix().ip(), outbound_ca_to_pa_attr.value.ipaddr); + outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + + outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_SIP_MASK; + to_sai(ctxt.metadata.overlay_sip_prefix().mask(), outbound_ca_to_pa_attr.value.ipaddr); + outbound_ca_to_pa_attrs.push_back(outbound_ca_to_pa_attr); + } outbound_ca_to_pa_attr.id = SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DMAC; memcpy(outbound_ca_to_pa_attr.value.mac, ctxt.metadata.mac_address().c_str(), sizeof(sai_mac_t)); @@ -664,6 +723,16 @@ void DashVnetOrch::doTaskVnetMapTable(ConsumerBase& consumer) it = consumer.m_toSync.erase(it); continue; } + if (ctxt.metadata.routing_type() == dash::route_type::RoutingType::ROUTING_TYPE_UNSPECIFIED) + { + // VnetMapping::action_type is deprecated in favor of VnetMapping::routing_type. For messages still using the old action_type field, + // copy it to the new routing_type field. All subsequent operations will use the new field. + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + SWSS_LOG_WARN("VnetMapping::action_type is deprecated. Use VnetMapping::routing_type instead"); + ctxt.metadata.set_routing_type(ctxt.metadata.action_type()); + #pragma GCC diagnostic pop + } if (addVnetMap(key, ctxt)) { it = consumer.m_toSync.erase(it); diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 047263c93a..0d2ab1c200 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -261,6 +261,7 @@ bool OrchDaemon::init() APP_DASH_APPLIANCE_TABLE_NAME, APP_DASH_ROUTING_TYPE_TABLE_NAME, APP_DASH_ENI_TABLE_NAME, + APP_DASH_ENI_ROUTE_TABLE_NAME, APP_DASH_QOS_TABLE_NAME }; @@ -269,7 +270,8 @@ bool OrchDaemon::init() vector dash_route_tables = { APP_DASH_ROUTE_TABLE_NAME, - APP_DASH_ROUTE_RULE_TABLE_NAME + APP_DASH_ROUTE_RULE_TABLE_NAME, + APP_DASH_ROUTE_GROUP_TABLE_NAME }; DashRouteOrch *dash_route_orch = new DashRouteOrch(m_applDb, dash_route_tables, dash_orch, m_zmqServer); diff --git a/tests/conftest.py b/tests/conftest.py index 93f54c824e..c94224539b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1877,7 +1877,7 @@ def dvs(request, manage_dvs) -> DockerVirtualSwitch: return manage_dvs(log_path, dvs_env) -@pytest.yield_fixture(scope="module") +@pytest.fixture(scope="module") def vst(request): vctns = request.config.getoption("--vctns") topo = request.config.getoption("--topo") diff --git a/tests/dash/dash_configs.py b/tests/dash/dash_configs.py new file mode 100644 index 0000000000..2f1590ebaa --- /dev/null +++ b/tests/dash/dash_configs.py @@ -0,0 +1,171 @@ +import base64 +import socket +import uuid +from ipaddress import ip_address as IP + +from dash_api.appliance_pb2 import * +from dash_api.vnet_pb2 import * +from dash_api.eni_pb2 import * +from dash_api.route_pb2 import * +from dash_api.route_rule_pb2 import * +from dash_api.vnet_mapping_pb2 import * +from dash_api.route_type_pb2 import * +from dash_api.types_pb2 import * + +VNET_ENCAP = "vnet_encap" +VNET_DIRECT = "vnet_direct" +PRIVATELINK = "privatelink" +DECAP = "decap" + +SIP = "10.0.0.1" +UNDERLAY_IP = "25.1.1.1" +VNET_MAP_IP1 = "10.1.1.1" +VNET_MAP_IP2 = "10.1.1.2" +UNDERLAY_IP = "101.1.2.3" +OUTBOUND_ROUTE_PREFIX1 = "10.1.0.8/32" +OUTBOUND_ROUTE_PREFIX2 = "10.1.0.9/32" +OVERLAY_IP = "10.0.0.6" +PL_ENCODING_IP = "::56b2:0:20:0:0" +PL_ENCODING_MASK = "::ffff:ffff:ffff:0:0" +PL_UNDERLAY_SIP1 = "55.1.2.3" +PL_UNDERLAY_SIP2 = "55.2.3.4" +PL_OVERLAY_SIP = "fd40:108:0:d204:0:200::0" +PL_OVERLAY_SIP_MASK = "ffff:ffff:ffff:ffff:ffff:ffff::" +PL_OVERLAY_DIP = "2603:10e1:100:2::3401:203" +PL_OVERLAY_DIP_MASK = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + +APPLIANCE_ID = "100" +VM_VNI = "4321" +ENCAP_VNI = 100 +VNET1 = "Vnet1" +VNET1_VNI = "45654" +VNET1_GUID = "559c6ce8-26ab-4193-b946-ccc6e8f930b2" +MAC_STRING = "F4939FEFC47E" +MAC_ADDRESS = "F4:93:9F:EF:C4:7E" +ENI_ID = "497f23d7-f0ac-4c99-a98f-59b470e8c7bd" +ROUTE_GROUP1 = "RouteGroup1" +ROUTE_GROUP2 = "RouteGroup2" +ROUTE_GROUP1_GUID = "48af6ce8-26cc-4293-bfa6-0126e8fcdeb2" +ROUTE_GROUP2_GUID = "58cf62e0-22cc-4693-baa6-012358fcdec9" + +APPLIANCE_CONFIG = { + "sip": { + "ipv4": socket.htonl(int(IP(SIP))) + }, + "vm_vni": int(VM_VNI) +} + +VNET_CONFIG = { + "vni": VNET1_VNI, + "guid": { + "value": base64.b64encode(bytes.fromhex(uuid.UUID(VNET1_GUID).hex)) + } +} + +ENI_CONFIG = { + "vnet": VNET1, + "underlay_ip": { + "ipv4": socket.htonl(int(IP(UNDERLAY_IP))) + }, + "mac_address": bytes.fromhex(MAC_STRING), + "eni_id": ENI_ID, + "admin_state": State.STATE_ENABLED, + "pl_underlay_sip": { + "ipv4": socket.htonl(int(IP(PL_UNDERLAY_SIP1))) + }, + "pl_sip_encoding": { + "ip": { + "ipv6": base64.b64encode(IP(PL_ENCODING_IP).packed) + }, + "mask": { + "ipv6": base64.b64encode(IP(PL_ENCODING_MASK).packed) + } + } +} + +VNET_MAPPING_CONFIG_VNET_ENCAP = { + "mac_address": bytes.fromhex(MAC_STRING), + "action_type": RoutingType.ROUTING_TYPE_VNET_ENCAP, + "underlay_ip": { + "ipv4": socket.htonl(int(IP(UNDERLAY_IP))) + }, +} + +VNET_MAPPING_CONFIG_PRIVATELINK = { + "mac_address": bytes.fromhex(MAC_STRING), + "action_type": RoutingType.ROUTING_TYPE_PRIVATELINK, + "underlay_ip": { + "ipv4": socket.htonl(int(IP(UNDERLAY_IP))) + }, + "overlay_sip_prefix": { + "ip": { + "ipv6": base64.b64encode(IP(PL_OVERLAY_SIP).packed) + }, + "mask": { + "ipv6": base64.b64encode(IP(PL_OVERLAY_SIP_MASK).packed) + } + }, + "overlay_dip_prefix": { + "ip": { + "ipv6": base64.b64encode(IP(PL_OVERLAY_DIP).packed) + }, + "mask": { + "ipv6": base64.b64encode(IP(PL_OVERLAY_DIP_MASK).packed) + } + }, +} + +ROUTE_VNET_CONFIG = { + "routing_type": RoutingType.ROUTING_TYPE_VNET, + "vnet": VNET1, +} + +ROUTE_VNET_CONFIG_UNDERLAY_SIP = { + "routing_type": RoutingType.ROUTING_TYPE_VNET, + "vnet": VNET1, + "underlay_sip": { + "ipv4": socket.htonl(int(IP(PL_UNDERLAY_SIP2))) + } +} + +ROUTING_TYPE_VNET_ENCAP_CONFIG = { + "items": [ + { + "action_name": "action1", + "action_type": ActionType.ACTION_TYPE_MAPROUTING + }, + ] +} + +ROUTING_TYPE_PL_CONFIG = { + "items": [ + { + "action_name": "action1", + "action_type": ActionType.ACTION_TYPE_4_to_6 + }, + { + "action_name": "action2", + "action_type": ActionType.ACTION_TYPE_STATICENCAP, + "encap_type": EncapType.ENCAP_TYPE_NVGRE, + "vni": ENCAP_VNI + } + ] +} + +ROUTE_GROUP1_CONFIG = { + "guid": ROUTE_GROUP1_GUID, + "version": "rg_version" +} + +ROUTE_GROUP2_CONFIG = { + "guid": ROUTE_GROUP2_GUID, + "version": "rg_version" +} + +ENI_ROUTE_GROUP1_CONFIG = { + "group_id": ROUTE_GROUP1, +} + +ENI_ROUTE_GROUP2_CONFIG = { + "group_id": ROUTE_GROUP2, +} \ No newline at end of file diff --git a/tests/dash/dash_db.py b/tests/dash/dash_db.py new file mode 100644 index 0000000000..7dbb19b1fe --- /dev/null +++ b/tests/dash/dash_db.py @@ -0,0 +1,237 @@ +from swsscommon import swsscommon +from dvslib.dvs_common import wait_for_result +import typing +import pytest + +from dash_api.appliance_pb2 import * +from dash_api.vnet_pb2 import * +from dash_api.eni_pb2 import * +from dash_api.eni_route_pb2 import * +from dash_api.route_pb2 import * +from dash_api.route_group_pb2 import * +from dash_api.route_rule_pb2 import * +from dash_api.vnet_mapping_pb2 import * +from dash_api.route_type_pb2 import * +from dash_api.types_pb2 import * +from google.protobuf.json_format import ParseDict +from google.protobuf.message import Message + +APP_DB_TO_PROTOBUF_MAP = { + swsscommon.APP_DASH_APPLIANCE_TABLE_NAME: Appliance, + swsscommon.APP_DASH_VNET_TABLE_NAME: Vnet, + swsscommon.APP_DASH_ENI_TABLE_NAME: Eni, + swsscommon.APP_DASH_VNET_MAPPING_TABLE_NAME: VnetMapping, + swsscommon.APP_DASH_ROUTE_TABLE_NAME: Route, + swsscommon.APP_DASH_ROUTE_RULE_TABLE_NAME: RouteRule, + swsscommon.APP_DASH_ENI_ROUTE_TABLE_NAME: EniRoute, + swsscommon.APP_DASH_ROUTING_TYPE_TABLE_NAME: RouteType, + swsscommon.APP_DASH_ROUTE_GROUP_TABLE_NAME: RouteGroup +} + +@pytest.fixture(scope='module') +def dash_db(dvs): + return DashDB(dvs) + +def to_string(value): + if isinstance(value, bool): + return "true" if value else "false" + elif isinstance(value, bytes): + return value + return str(value) + +class ProducerStateTable(swsscommon.ProducerStateTable): + def __setitem__(self, key: str, pairs: typing.Union[dict, list, tuple]): + pairs_str = [] + if isinstance(pairs, dict): + pairs = pairs.items() + for k, v in pairs: + pairs_str.append((to_string(k), to_string(v))) + self.set(key, pairs_str) + + def __delitem__(self, key: str): + self.delete(str(key)) + + +class Table(swsscommon.Table): + def __getitem__(self, key: str): + exists, result = self.get(str(key)) + if not exists: + return None + else: + return dict(result) + + def get_keys(self): + return self.getKeys() + + def get_newly_created_oid(self, old_oids): + new_oids = self.asic_db.wait_for_n_keys(self, len(old_oids) + 1) + oid = [ids for ids in new_oids if ids not in old_oids] + return oid[0] + + +class DashDB(object): + + def parse_key_value(self, arglist): + if len(arglist) < 2: + raise ValueError("Invalid number of arguments") + # elif len(arglist) == 1: + # handle case where no value is passed (e.g. in remove_app_db_entry) + # key = arglist[0] + # value = None + else: + # concat all parts of the key, assume last arg to be the value + key = ":".join(arglist[:-1]) + value = arglist[-1] + return key, value + + def set_app_db_entry(self, table_name, *args): + key, value = self.parse_key_value(args) + if isinstance(value, dict): + pb = ParseDict(value, APP_DB_TO_PROTOBUF_MAP[table_name]()) + pb_string = pb.SerializeToString() + elif isinstance(value, Message): + pb_string = value.SerializeToString() + else: + pb_string = value + + table = ProducerStateTable(self.dvs.get_app_db().db_connection, table_name) + table[key] = {'pb': pb_string} + + def remove_app_db_entry(self, table_name, *key_parts): + # key, _ = self.parse_key_value(args) + key = ":".join(key_parts) + table = ProducerStateTable(self.dvs.get_app_db().db_connection, table_name) + del table[key] + + def get_asic_db_entry(self, table_name, key): + table = Table(self.dvs.get_asic_db().db_connection, table_name) + return table[key] + + def wait_for_asic_db_keys(self, table_name, min_keys=1): + + def polling_function(): + table = Table(self.dvs.get_asic_db().db_connection, table_name) + keys = table.get_keys() + return len(keys) >= min_keys, keys + + _, keys = wait_for_result(polling_function, failure_message=f"Found fewer than {min_keys} keys in ASIC_DB table {table_name}") + return keys + + def wait_for_asic_db_field(self, table_name, key, field, expected_value=None): + + def polling_function(): + table = Table(self.dvs.get_asic_db().db_connection, table_name) + attrs = table[key] + if attrs is None or field not in attrs: + return False, None + + if expected_value is not None: + return attrs[field] == expected_value, attrs[field] + else: + return True, attrs[field] + + if expected_value is not None: + failure_message = f"Field {field} in ASIC_DB table {table_name} not equal to {expected_value}" + else: + failure_message = f"Field {field} not found in ASIC_DB table {table_name}" + success, value = wait_for_result(polling_function, failure_message=failure_message) + if success: + return value + else: + return None + + def __init__(self, dvs): + self.dvs = dvs + self.app_dash_routing_type_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_ROUTING_TYPE_TABLE") + self.app_dash_appliance_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_APPLIANCE_TABLE") + self.app_dash_vnet_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_VNET_TABLE") + self.app_dash_eni_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_ENI_TABLE") + self.app_dash_vnet_map_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_VNET_MAPPING_TABLE") + self.app_dash_route_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_ROUTE_TABLE") + self.app_dash_route_rule_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_ROUTE_RULE_TABLE") + self.app_dash_eni_route_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_ENI_ROUTE_TABLE") + self.app_dash_route_group_table = ProducerStateTable( + self.dvs.get_app_db().db_connection, "DASH_ROUTE_GROUP_TABLE") + + self.asic_direction_lookup_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_DIRECTION_LOOKUP_ENTRY") + self.asic_vip_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_VIP_ENTRY") + self.asic_dash_vnet_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_VNET") + self.asic_eni_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_ENI") + self.asic_eni_ether_addr_map_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_ENI_ETHER_ADDRESS_MAP_ENTRY") + self.asic_dash_outbound_ca_to_pa_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_CA_TO_PA_ENTRY") + self.asic_pa_validation_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_PA_VALIDATION_ENTRY") + self.asic_outbound_routing_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY") + self.asic_inbound_routing_rule_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_INBOUND_ROUTING_ENTRY") + self.asic_outbound_routing_group_table = Table( + self.dvs.get_asic_db().db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_GROUP") + + def create_appliance(self, appliance_id, attr_maps: dict): + self.app_dash_appliance_table[str(appliance_id)] = attr_maps + + def remove_appliance(self, appliance_id): + del self.app_dash_appliance_table[str(appliance_id)] + + def create_vnet(self, vnet, attr_maps: dict): + self.app_dash_vnet_table[str(vnet)] = attr_maps + + def remove_vnet(self, vnet): + del self.app_dash_vnet_table[str(vnet)] + + def create_eni(self, eni, attr_maps: dict): + self.app_dash_eni_table[str(eni)] = attr_maps + + def remove_eni(self, eni): + del self.app_dash_eni_table[str(eni)] + + def create_eni_route(self, eni, attr_maps: dict): + self.app_dash_eni_route_table[str(eni)] = attr_maps + + def remove_eni_route(self, eni): + del self.app_dash_eni_route_table[str(eni)] + + def create_vnet_mapping(self, vnet, ip, attr_maps: dict): + self.app_dash_vnet_map_table[str(vnet) + ":" + str(ip)] = attr_maps + + def remove_vnet_mapping(self, vnet, ip): + del self.app_dash_vnet_map_table[str(vnet) + ":" + str(ip)] + + def create_route(self, route_group, ip, attr_maps: dict): + self.app_dash_route_table[str(route_group) + ":" + str(ip)] = attr_maps + + def remove_route(self, route_group, ip): + del self.app_dash_route_table[str(route_group) + ":" + str(ip)] + + def create_route_group(self, route_group, attr_maps: dict): + self.app_dash_route_group_table[str(route_group)] = attr_maps + + def remove_route_group(self, route_group): + del self.app_dash_route_group_table[str(route_group)] + + def create_inbound_routing(self, mac_string, vni, ip, attr_maps: dict): + self.app_dash_route_rule_table[str(mac_string) + ":" + str(vni) + ":" + str(ip)] = attr_maps + + def remove_inbound_routing(self, mac_string, vni, ip): + del self.app_dash_route_rule_table[str(mac_string) + ":" + str(vni) + ":" + str(ip)] + + def create_routing_type(self, routing_type, attr_maps: dict): + self.app_dash_routing_type_table[str(routing_type)] = attr_maps + + def remove_routing_type(self, routing_type): + del self.app_dash_routing_type_table[str(routing_type)] diff --git a/tests/test_dash_acl.py b/tests/dash/test_dash_acl.py similarity index 100% rename from tests/test_dash_acl.py rename to tests/dash/test_dash_acl.py diff --git a/tests/dash/test_dash_pl.py b/tests/dash/test_dash_pl.py new file mode 100644 index 0000000000..93ee8d19b3 --- /dev/null +++ b/tests/dash/test_dash_pl.py @@ -0,0 +1,79 @@ +import pytest + +from dvslib.sai_utils import assert_sai_attribute_exists + +from dash_api.appliance_pb2 import * +from dash_api.vnet_pb2 import * +from dash_api.eni_pb2 import * +from dash_api.route_pb2 import * +from dash_api.route_rule_pb2 import * +from dash_api.vnet_mapping_pb2 import * +from dash_api.route_type_pb2 import * +from dash_api.types_pb2 import * + +from dash_db import dash_db, DashDB +from dash_configs import * +from sai_attrs import * +from swsscommon.swsscommon import ( + APP_DASH_APPLIANCE_TABLE_NAME, + APP_DASH_ENI_TABLE_NAME, + APP_DASH_VNET_TABLE_NAME, + APP_DASH_VNET_MAPPING_TABLE_NAME, + APP_DASH_ROUTE_TABLE_NAME, + APP_DASH_ENI_ROUTE_TABLE_NAME, + APP_DASH_ROUTING_TYPE_TABLE_NAME, + APP_DASH_ROUTE_GROUP_TABLE_NAME, +) + +DVS_ENV = ["HWSKU=DPU-2P"] +NUM_PORTS = 2 + +@pytest.fixture(autouse=True) +def common_setup_teardown(dash_db: DashDB): + dash_db.set_app_db_entry(APP_DASH_ROUTING_TYPE_TABLE_NAME, PRIVATELINK, ROUTING_TYPE_PL_CONFIG) + dash_db.set_app_db_entry(APP_DASH_APPLIANCE_TABLE_NAME, APPLIANCE_ID, APPLIANCE_CONFIG) + dash_db.set_app_db_entry(APP_DASH_VNET_TABLE_NAME, VNET1, VNET_CONFIG) + dash_db.set_app_db_entry(APP_DASH_ENI_TABLE_NAME, ENI_ID, ENI_CONFIG) + dash_db.set_app_db_entry(APP_DASH_VNET_MAPPING_TABLE_NAME, VNET1, VNET_MAP_IP1, VNET_MAPPING_CONFIG_PRIVATELINK) + dash_db.set_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP1, ROUTE_GROUP1_CONFIG) + # Don't set DASH_ROUTE_TABLE and DASH_ENI_ROUTE_TABLE entries here for flexibility, test cases will set them as needed + + yield + + dash_db.remove_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID) + dash_db.remove_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX1) + dash_db.remove_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP1) + dash_db.remove_app_db_entry(APP_DASH_VNET_MAPPING_TABLE_NAME, VNET1, VNET_MAP_IP1) + dash_db.remove_app_db_entry(APP_DASH_ENI_TABLE_NAME, ENI_ID) + dash_db.remove_app_db_entry(APP_DASH_VNET_TABLE_NAME, VNET1) + dash_db.remove_app_db_entry(APP_DASH_APPLIANCE_TABLE_NAME, APPLIANCE_ID) + dash_db.remove_app_db_entry(APP_DASH_ROUTING_TYPE_TABLE_NAME, PRIVATELINK) + + +def test_pl_eni_attrs(dash_db: DashDB): + dash_db.set_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX1, ROUTE_VNET_CONFIG) + dash_db.set_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID, ENI_ROUTE_GROUP1_CONFIG) + + enis = dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_ENI") + eni_attrs = dash_db.get_asic_db_entry("ASIC_STATE:SAI_OBJECT_TYPE_ENI", enis[0]) + assert_sai_attribute_exists(SAI_ENI_ATTR_PL_UNDERLAY_SIP, eni_attrs, PL_UNDERLAY_SIP1) + +def test_pl_eni_override_underlay_sip(dash_db: DashDB): + dash_db.set_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX1, ROUTE_VNET_CONFIG_UNDERLAY_SIP) + dash_db.set_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID, ENI_ROUTE_GROUP1_CONFIG) + + outbound_routing_keys = dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY") + outbound_routing_attrs = dash_db.get_asic_db_entry("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY", outbound_routing_keys[0]) + assert_sai_attribute_exists(SAI_OUTBOUND_ROUTING_ENTRY_ATTR_UNDERLAY_SIP, outbound_routing_attrs, PL_UNDERLAY_SIP2) + +def test_pl_outbound_ca_to_pa_attrs(dash_db: DashDB): + outbound_ca_to_pa_keys = dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_CA_TO_PA_ENTRY") + outbound_attrs = dash_db.get_asic_db_entry("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_CA_TO_PA_ENTRY", outbound_ca_to_pa_keys[0]) + + assert_sai_attribute_exists(SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_ACTION, outbound_attrs, SAI_OUTBOUND_CA_TO_PA_ENTRY_ACTION_SET_PRIVATE_LINK_MAPPING) + assert_sai_attribute_exists(SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_SIP, outbound_attrs, PL_OVERLAY_SIP) + assert_sai_attribute_exists(SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_SIP_MASK, outbound_attrs, PL_OVERLAY_SIP_MASK) + assert_sai_attribute_exists(SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP, outbound_attrs, PL_OVERLAY_DIP) + assert_sai_attribute_exists(SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP_MASK, outbound_attrs, PL_OVERLAY_DIP_MASK) + assert_sai_attribute_exists(SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_TUNNEL_KEY, outbound_attrs, ENCAP_VNI) + assert_sai_attribute_exists(SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_DASH_ENCAPSULATION, outbound_attrs, SAI_DASH_ENCAPSULATION_NVGRE) diff --git a/tests/dash/test_dash_route_group.py b/tests/dash/test_dash_route_group.py new file mode 100644 index 0000000000..10860465f2 --- /dev/null +++ b/tests/dash/test_dash_route_group.py @@ -0,0 +1,87 @@ +import pytest +import time +from dash_db import DashDB, dash_db +from dash_configs import * +from dvslib.sai_utils import assert_sai_attribute_exists +from sai_attrs import * +from swsscommon.swsscommon import ( + APP_DASH_APPLIANCE_TABLE_NAME, + APP_DASH_ENI_TABLE_NAME, + APP_DASH_VNET_TABLE_NAME, + APP_DASH_VNET_MAPPING_TABLE_NAME, + APP_DASH_ROUTE_TABLE_NAME, + APP_DASH_ENI_ROUTE_TABLE_NAME, + APP_DASH_ROUTING_TYPE_TABLE_NAME, + APP_DASH_ROUTE_GROUP_TABLE_NAME, +) + +@pytest.fixture(scope='module', autouse=True) +def common_setup_teardown(dash_db: DashDB): + dash_db.set_app_db_entry(APP_DASH_APPLIANCE_TABLE_NAME, APPLIANCE_ID, APPLIANCE_CONFIG) + dash_db.set_app_db_entry(APP_DASH_ROUTING_TYPE_TABLE_NAME, PRIVATELINK, ROUTING_TYPE_PL_CONFIG) + dash_db.set_app_db_entry(APP_DASH_VNET_TABLE_NAME, VNET1, VNET_CONFIG) + dash_db.set_app_db_entry(APP_DASH_ENI_TABLE_NAME, ENI_ID, ENI_CONFIG) + dash_db.set_app_db_entry(APP_DASH_VNET_MAPPING_TABLE_NAME, VNET1, VNET_MAP_IP1, VNET_MAPPING_CONFIG_PRIVATELINK) + # Don't set DASH_ROUTE_TABLE and DASH_ENI_ROUTE_TABLE entries here for flexibility, test cases will set them as needed + + yield + + dash_db.remove_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID) + dash_db.remove_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX1) + dash_db.remove_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP2, OUTBOUND_ROUTE_PREFIX1) + dash_db.remove_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP1) + dash_db.remove_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP2) + dash_db.remove_app_db_entry(APP_DASH_VNET_MAPPING_TABLE_NAME, VNET1, VNET_MAP_IP1) + dash_db.remove_app_db_entry(APP_DASH_ENI_TABLE_NAME, ENI_ID) + dash_db.remove_app_db_entry(APP_DASH_VNET_TABLE_NAME, VNET1) + dash_db.remove_app_db_entry(APP_DASH_ROUTING_TYPE_TABLE_NAME, PRIVATELINK) + dash_db.remove_app_db_entry(APP_DASH_APPLIANCE_TABLE_NAME, APPLIANCE_ID) + +def test_rebind_eni_route_group(dash_db: DashDB): + dash_db.set_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP1, ROUTE_GROUP1_CONFIG) + dash_db.set_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX1, ROUTE_VNET_CONFIG) + rg1_oid = dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_GROUP")[0] + + dash_db.set_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP2, ROUTE_GROUP2_CONFIG) + dash_db.set_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP2, OUTBOUND_ROUTE_PREFIX1, ROUTE_VNET_CONFIG_UNDERLAY_SIP) + rg2_oid = dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_GROUP", min_keys=2)[1] + + dash_db.set_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID, ENI_ROUTE_GROUP1_CONFIG) + + eni_key = dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_ENI")[0] + dash_db.wait_for_asic_db_field("ASIC_STATE:SAI_OBJECT_TYPE_ENI", eni_key, SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID, rg1_oid) + + dash_db.set_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID, ENI_ROUTE_GROUP2_CONFIG) + dash_db.wait_for_asic_db_field("ASIC_STATE:SAI_OBJECT_TYPE_ENI", eni_key, SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID, rg2_oid) + +def test_duplicate_eni_route_group(dash_db: DashDB): + dash_db.set_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP1, ROUTE_GROUP1_CONFIG) + dash_db.set_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX1, ROUTE_VNET_CONFIG) + rg1_oid = dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_GROUP")[0] + + dash_db.set_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID, ENI_ROUTE_GROUP1_CONFIG) + + eni_key = dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_ENI")[0] + dash_db.wait_for_asic_db_field("ASIC_STATE:SAI_OBJECT_TYPE_ENI", eni_key, SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID, rg1_oid) + + dash_db.set_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID, ENI_ROUTE_GROUP1_CONFIG) + dash_db.wait_for_asic_db_field("ASIC_STATE:SAI_OBJECT_TYPE_ENI", eni_key, SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID, rg1_oid) + +def test_bound_route_group_immutable(dash_db: DashDB): + dash_db.set_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP1, ROUTE_GROUP1_CONFIG) + num_route_groups = len(dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_GROUP")) + dash_db.set_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX1, ROUTE_VNET_CONFIG) + num_routes = len(dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY")) + + dash_db.set_app_db_entry(APP_DASH_ENI_ROUTE_TABLE_NAME, ENI_ID, ENI_ROUTE_GROUP1_CONFIG) + dash_db.set_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX2, ROUTE_VNET_CONFIG_UNDERLAY_SIP) + time.sleep(3) + assert len(dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY")) == num_routes + + dash_db.remove_app_db_entry(APP_DASH_ROUTE_TABLE_NAME, ROUTE_GROUP1, OUTBOUND_ROUTE_PREFIX1) + time.sleep(3) + assert len(dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY")) == num_routes + + dash_db.remove_app_db_entry(APP_DASH_ROUTE_GROUP_TABLE_NAME, ROUTE_GROUP1) + time.sleep(3) + assert len(dash_db.wait_for_asic_db_keys("ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_GROUP")) == num_route_groups diff --git a/tests/dash/test_dash_vnet.py b/tests/dash/test_dash_vnet.py new file mode 100644 index 0000000000..ab46d1b1ac --- /dev/null +++ b/tests/dash/test_dash_vnet.py @@ -0,0 +1,241 @@ +from dash_api.appliance_pb2 import * +from dash_api.vnet_pb2 import * +from dash_api.eni_pb2 import * +from dash_api.eni_route_pb2 import * +from dash_api.route_pb2 import * +from dash_api.route_group_pb2 import * +from dash_api.route_rule_pb2 import * +from dash_api.vnet_mapping_pb2 import * +from dash_api.route_type_pb2 import * +from dash_api.types_pb2 import * + +from dash_db import dash_db +from dash_configs import * + +import time +import uuid +import ipaddress +import socket + +DVS_ENV = ["HWSKU=DPU-2P"] +NUM_PORTS = 2 + +class TestDash(object): + def test_appliance(self, dash_db): + self.appliance_id = "100" + self.sip = "10.0.0.1" + self.vm_vni = "4321" + pb = Appliance() + pb.sip.ipv4 = socket.htonl(int(ipaddress.ip_address(self.sip))) + pb.vm_vni = int(self.vm_vni) + dash_db.create_appliance(self.appliance_id, {"pb": pb.SerializeToString()}) + time.sleep(3) + + direction_entries = dash_db.asic_direction_lookup_table.get_keys() + assert direction_entries + fvs = dash_db.asic_direction_lookup_table[direction_entries[0]] + for fv in fvs.items(): + if fv[0] == "SAI_DIRECTION_LOOKUP_ENTRY_ATTR_ACTION": + assert fv[1] == "SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION" + vip_entries = dash_db.asic_vip_table.get_keys() + assert vip_entries + fvs = dash_db.asic_vip_table[vip_entries[0]] + for fv in fvs.items(): + if fv[0] == "SAI_VIP_ENTRY_ATTR_ACTION": + assert fv[1] == "SAI_VIP_ENTRY_ACTION_ACCEPT" + + def test_vnet(self, dash_db): + self.vnet = "Vnet1" + self.vni = "45654" + self.guid = "559c6ce8-26ab-4193-b946-ccc6e8f930b2" + pb = Vnet() + pb.vni = int(self.vni) + pb.guid.value = bytes.fromhex(uuid.UUID(self.guid).hex) + dash_db.create_vnet(self.vnet, {"pb": pb.SerializeToString()}) + time.sleep(3) + vnets = dash_db.asic_dash_vnet_table.get_keys() + assert vnets + self.vnet_oid = vnets[0] + vnet_attr = dash_db.asic_dash_vnet_table[self.vnet_oid] + assert vnet_attr["SAI_VNET_ATTR_VNI"] == "45654" + + def test_eni(self, dash_db): + self.vnet = "Vnet1" + self.mac_string = "F4939FEFC47E" + self.mac_address = "F4:93:9F:EF:C4:7E" + self.eni_id = "497f23d7-f0ac-4c99-a98f-59b470e8c7bd" + self.underlay_ip = "25.1.1.1" + self.admin_state = "enabled" + pb = Eni() + pb.eni_id = self.eni_id + pb.mac_address = bytes.fromhex(self.mac_address.replace(":", "")) + pb.underlay_ip.ipv4 = socket.htonl(int(ipaddress.ip_address(self.underlay_ip))) + pb.admin_state = State.STATE_ENABLED + pb.vnet = self.vnet + dash_db.create_eni(self.mac_string, {"pb": pb.SerializeToString()}) + time.sleep(3) + vnets = dash_db.asic_dash_vnet_table.get_keys() + assert vnets + self.vnet_oid = vnets[0] + enis = dash_db.asic_eni_table.get_keys() + assert enis + self.eni_oid = enis[0] + fvs = dash_db.asic_eni_table[enis[0]] + for fv in fvs.items(): + if fv[0] == "SAI_ENI_ATTR_VNET_ID": + assert fv[1] == str(self.vnet_oid) + if fv[0] == "SAI_ENI_ATTR_PPS": + assert fv[1] == 0 + if fv[0] == "SAI_ENI_ATTR_CPS": + assert fv[1] == 0 + if fv[0] == "SAI_ENI_ATTR_FLOWS": + assert fv[1] == 0 + if fv[0] == "SAI_ENI_ATTR_ADMIN_STATE": + assert fv[1] == "true" + + time.sleep(3) + eni_addr_maps = dash_db.asic_eni_ether_addr_map_table.get_keys() + assert eni_addr_maps + fvs = dash_db.asic_eni_ether_addr_map_table[eni_addr_maps[0]] + for fv in fvs.items(): + if fv[0] == "SAI_ENI_ETHER_ADDRESS_MAP_ENTRY_ATTR_ENI_ID": + assert fv[1] == str(self.eni_oid) + + # test admin state update + pb.admin_state = State.STATE_DISABLED + dash_db.create_eni(self.mac_string, {"pb": pb.SerializeToString()}) + time.sleep(3) + enis = dash_db.asic_eni_table.get_keys() + assert len(enis) == 1 + assert enis[0] == self.eni_oid + eni_attrs = dash_db.asic_eni_table[self.eni_oid] + assert eni_attrs["SAI_ENI_ATTR_ADMIN_STATE"] == "false" + + def test_vnet_map(self, dash_db): + self.vnet = "Vnet1" + self.ip1 = "10.1.1.1" + self.ip2 = "10.1.1.2" + self.mac_address = "F4:93:9F:EF:C4:7E" + self.routing_type = "vnet_encap" + self.underlay_ip = "101.1.2.3" + route_type_msg = RouteType() + route_action = RouteTypeItem() + route_action.action_name = "action1" + route_action.action_type = ACTION_TYPE_MAPROUTING + route_type_msg.items.append(route_action) + dash_db.create_routing_type(self.routing_type, {"pb": route_type_msg.SerializeToString()}) + pb = VnetMapping() + pb.mac_address = bytes.fromhex(self.mac_address.replace(":", "")) + pb.action_type = RoutingType.ROUTING_TYPE_VNET_ENCAP + pb.underlay_ip.ipv4 = socket.htonl(int(ipaddress.ip_address(self.underlay_ip))) + + dash_db.create_vnet_mapping(self.vnet, self.ip1, {"pb": pb.SerializeToString()}) + dash_db.create_vnet_mapping(self.vnet, self.ip2, {"pb": pb.SerializeToString()}) + time.sleep(3) + + vnet_ca_to_pa_maps = dash_db.asic_dash_outbound_ca_to_pa_table.get_keys() + assert len(vnet_ca_to_pa_maps) >= 2 + fvs = dash_db.asic_dash_outbound_ca_to_pa_table[vnet_ca_to_pa_maps[0]] + for fv in fvs.items(): + if fv[0] == "SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_UNDERLAY_DIP": + assert fv[1] == "101.1.2.3" + if fv[0] == "SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DMAC": + assert fv[1] == "F4:93:9F:EF:C4:7E" + + vnet_pa_validation_maps = dash_db.asic_pa_validation_table.get_keys() + assert vnet_pa_validation_maps + fvs = dash_db.asic_pa_validation_table[vnet_pa_validation_maps[0]] + for fv in fvs.items(): + if fv[0] == "SAI_PA_VALIDATION_ENTRY_ATTR_ACTION": + assert fv[1] == "SAI_PA_VALIDATION_ENTRY_ACTION_PERMIT" + + def test_outbound_routing(self, dash_db): + pb = RouteGroup() + self.group_id = ROUTE_GROUP1 + dash_db.create_route_group(self.group_id, {"pb": pb.SerializeToString()}) + time.sleep(3) + outbound_routing_group_entries = dash_db.asic_outbound_routing_group_table.get_keys() + assert outbound_routing_group_entries + + self.vnet = "Vnet1" + self.ip = "10.1.0.0/24" + self.action_type = "vnet_direct" + self.overlay_ip = "10.0.0.6" + pb = Route() + pb.action_type = RoutingType.ROUTING_TYPE_VNET_DIRECT + pb.vnet_direct.vnet = self.vnet + pb.vnet_direct.overlay_ip.ipv4 = socket.htonl(int(ipaddress.ip_address(self.overlay_ip))) + dash_db.create_route(self.group_id, self.ip, {"pb": pb.SerializeToString()}) + time.sleep(3) + outbound_routing_entries = dash_db.asic_outbound_routing_table.get_keys() + assert outbound_routing_entries + fvs = dash_db.asic_outbound_routing_table[outbound_routing_entries[0]] + for fv in fvs.items(): + if fv[0] == "SAI_OUTBOUND_ROUTING_ENTRY_ATTR_ACTION": + assert fv[1] == "SAI_OUTBOUND_ROUTING_ENTRY_ACTION_ROUTE_VNET_DIRECT" + if fv[0] == "SAI_OUTBOUND_ROUTING_ENTRY_ATTR_OVERLAY_IP": + assert fv[1] == "10.0.0.6" + assert "SAI_OUTBOUND_ROUTING_ENTRY_ATTR_DST_VNET_ID" in fvs + + pb = EniRoute() + pb.group_id = self.group_id + self.mac_string = "F4939FEFC47E" + dash_db.create_eni_route(self.mac_string, {"pb": pb.SerializeToString()}) + time.sleep(3) + eni_entries = dash_db.asic_eni_table.get_keys() + fvs = dash_db.asic_eni_table[eni_entries[0]] + for fv in fvs.items(): + if fv[0] == "SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID": + assert fv[1] == outbound_routing_group_entries[0] + + def test_inbound_routing(self, dash_db): + self.mac_string = "F4939FEFC47E" + self.vnet = "Vnet1" + self.vni = "3251" + self.ip = "10.1.1.1" + self.action_type = "decap" + self.pa_validation = "true" + self.priority = "1" + self.protocol = "0" + pb = RouteRule() + pb.pa_validation = True + pb.priority = int(self.priority) + pb.protocol = int(self.protocol) + pb.vnet = self.vnet + + dash_db.create_inbound_routing(self.mac_string, self.vni, self.ip, {"pb": pb.SerializeToString()}) + time.sleep(3) + + inbound_routing_entries = dash_db.asic_inbound_routing_rule_table.get_keys() + assert inbound_routing_entries + fvs = dash_db.asic_inbound_routing_rule_table[inbound_routing_entries[0]] + for fv in fvs.items(): + if fv[0] == "SAI_INBOUND_ROUTING_ENTRY_ATTR_ACTION": + assert fv[1] == "SAI_INBOUND_ROUTING_ENTRY_ACTION_TUNNEL_DECAP_PA_VALIDATE" + + def test_cleanup(self, dash_db): + self.vnet = "Vnet1" + self.mac_string = "F4939FEFC47E" + self.group_id = ROUTE_GROUP1 + self.vni = "3251" + self.sip = "10.1.1.1" + self.dip = "10.1.0.0/24" + self.ip2 = "10.1.1.2" + self.appliance_id = "100" + self.routing_type = "vnet_encap" + dash_db.remove_inbound_routing(self.mac_string, self.vni, self.sip) + dash_db.remove_eni_route(self.mac_string) + dash_db.remove_route(self.group_id, self.dip) + dash_db.remove_route_group(self.group_id) + dash_db.remove_vnet_mapping(self.vnet, self.sip) + dash_db.remove_vnet_mapping(self.vnet, self.ip2) + dash_db.remove_routing_type(self.routing_type) + dash_db.remove_eni(self.mac_string) + dash_db.remove_vnet(self.vnet) + dash_db.remove_appliance(self.appliance_id) + +# 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 diff --git a/tests/dvslib/sai_utils.py b/tests/dvslib/sai_utils.py new file mode 100644 index 0000000000..f5e245f3cd --- /dev/null +++ b/tests/dvslib/sai_utils.py @@ -0,0 +1,16 @@ +from ipaddress import ip_address as IP + +def assert_sai_attribute_exists(attr_name, attrs, expected_val=None): + assert attr_name in attrs, f"Attribute {attr_name} not found in {attrs}" + if expected_val is not None: + expected = expected_val + actual = attrs[attr_name] + # Attempt to convert to specific types to avoid string comparison when possible + for type in [int, IP]: + try: + expected = type(expected) + actual = type(actual) + break + except ValueError: + continue + assert actual == expected, f"Attribute {attr_name} value mismatch. Expected: {expected}, Actual: {actual}" diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index c3a305b1eb..0f5afa4486 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -1,6 +1,7 @@ FLEX_CTR_DIR = $(top_srcdir)/orchagent/flex_counter DEBUG_CTR_DIR = $(top_srcdir)/orchagent/debug_counter P4_ORCH_DIR = $(top_srcdir)/orchagent/p4orch +DASH_ORCH_DIR = $(top_srcdir)/orchagent/dash DASH_PROTO_DIR = $(top_srcdir)/orchagent/dash/proto CFLAGS_SAI = -I /usr/include/sai @@ -22,7 +23,7 @@ LDADD_GTEST = -L/usr/src/gtest ## Orchagent Unit Tests -tests_INCLUDES = -I $(FLEX_CTR_DIR) -I $(DEBUG_CTR_DIR) -I $(top_srcdir)/lib -I$(top_srcdir)/cfgmgr -I$(top_srcdir)/orchagent -I$(P4_ORCH_DIR)/tests -I$(top_srcdir)/warmrestart +tests_INCLUDES = -I $(FLEX_CTR_DIR) -I $(DEBUG_CTR_DIR) -I $(top_srcdir)/lib -I$(top_srcdir)/cfgmgr -I$(top_srcdir)/orchagent -I$(P4_ORCH_DIR)/tests -I$(DASH_ORCH_DIR) -I$(top_srcdir)/warmrestart tests_SOURCES = aclorch_ut.cpp \ portsorch_ut.cpp \ @@ -60,8 +61,10 @@ tests_SOURCES = aclorch_ut.cpp \ switchorch_ut.cpp \ warmrestarthelper_ut.cpp \ neighorch_ut.cpp \ + dashorch_ut.cpp \ twamporch_ut.cpp \ flexcounter_ut.cpp \ + mock_orch_test.cpp \ $(top_srcdir)/warmrestart/warmRestartHelper.cpp \ $(top_srcdir)/lib/gearboxutils.cpp \ $(top_srcdir)/lib/subintf.cpp \ diff --git a/tests/mock_tests/dashorch_ut.cpp b/tests/mock_tests/dashorch_ut.cpp new file mode 100644 index 0000000000..7786596fd7 --- /dev/null +++ b/tests/mock_tests/dashorch_ut.cpp @@ -0,0 +1,55 @@ +#define private public +#include "directory.h" +#undef private +#define protected public +#include "orch.h" +#undef protected +#include "ut_helper.h" +#include "mock_orchagent_main.h" +#include "mock_sai_api.h" +#include "mock_orch_test.h" +#include "dash_api/appliance.pb.h" +#include "dash_api/route_type.pb.h" +#include "dash_api/eni.pb.h" +#include "dash_api/qos.pb.h" +#include "dash_api/eni_route.pb.h" + + +EXTERN_MOCK_FNS + +namespace dashorch_test +{ + using namespace mock_orch_test; + class DashOrchTest : public MockOrchTest {}; + + TEST_F(DashOrchTest, GetNonExistRoutingType) + { + dash::route_type::RouteType route_type; + bool success = m_DashOrch->getRouteTypeActions(dash::route_type::RoutingType::ROUTING_TYPE_DIRECT, route_type); + EXPECT_FALSE(success); + } + + TEST_F(DashOrchTest, DuplicateRoutingTypeEntry) + { + dash::route_type::RouteType route_type1; + dash::route_type::RouteTypeItem *item1 = route_type1.add_items(); + item1->set_action_type(dash::route_type::ActionType::ACTION_TYPE_STATICENCAP); + bool success = m_DashOrch->addRoutingTypeEntry(dash::route_type::RoutingType::ROUTING_TYPE_VNET, route_type1); + EXPECT_TRUE(success); + EXPECT_EQ(m_DashOrch->routing_type_entries_.size(), 1); + EXPECT_EQ(m_DashOrch->routing_type_entries_[dash::route_type::RoutingType::ROUTING_TYPE_VNET].items()[0].action_type(), item1->action_type()); + + dash::route_type::RouteType route_type2; + dash::route_type::RouteTypeItem *item2 = route_type2.add_items(); + item2->set_action_type(dash::route_type::ActionType::ACTION_TYPE_DECAP); + success = m_DashOrch->addRoutingTypeEntry(dash::route_type::RoutingType::ROUTING_TYPE_VNET, route_type2); + EXPECT_TRUE(success); + EXPECT_EQ(m_DashOrch->routing_type_entries_[dash::route_type::RoutingType::ROUTING_TYPE_VNET].items()[0].action_type(), item1->action_type()); + } + + TEST_F(DashOrchTest, RemoveNonExistRoutingType) + { + bool success = m_DashOrch->removeRoutingTypeEntry(dash::route_type::RoutingType::ROUTING_TYPE_DROP); + EXPECT_TRUE(success); + } +} \ No newline at end of file diff --git a/tests/mock_tests/mock_orch_test.cpp b/tests/mock_tests/mock_orch_test.cpp new file mode 100644 index 0000000000..c6898188b4 --- /dev/null +++ b/tests/mock_tests/mock_orch_test.cpp @@ -0,0 +1,279 @@ +#include "mock_orch_test.h" + +using namespace std; + +namespace mock_orch_test +{ + +void MockOrchTest::ApplyInitialConfigs() {} +void MockOrchTest::PostSetUp() {} +void MockOrchTest::PreTearDown() {} + +void MockOrchTest::PrepareSai() +{ + sai_attribute_t attr; + + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + sai_status_t status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + // Get switch source MAC address + attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gMacAddress = attr.value.mac; + + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gVirtualRouterId = attr.value.oid; + + /* Create a loopback underlay router interface */ + vector underlay_intf_attrs; + + sai_attribute_t underlay_intf_attr; + underlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; + underlay_intf_attr.value.oid = gVirtualRouterId; + underlay_intf_attrs.push_back(underlay_intf_attr); + + underlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + underlay_intf_attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_LOOPBACK; + underlay_intf_attrs.push_back(underlay_intf_attr); + + underlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_MTU; + underlay_intf_attr.value.u32 = 9100; + underlay_intf_attrs.push_back(underlay_intf_attr); + + status = sai_router_intfs_api->create_router_interface(&gUnderlayIfId, gSwitchId, (uint32_t)underlay_intf_attrs.size(), underlay_intf_attrs.data()); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); +} + +void MockOrchTest::SetUp() +{ + map profile = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + + ut_helper::initSaiApi(profile); + m_app_db = make_shared("APPL_DB", 0); + m_config_db = make_shared("CONFIG_DB", 0); + m_state_db = make_shared("STATE_DB", 0); + m_chassis_app_db = make_shared("CHASSIS_APP_DB", 0); + + PrepareSai(); + + const int portsorch_base_pri = 40; + vector ports_tables = { + { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, + { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, + { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, + { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } + }; + + TableConnector stateDbSwitchTable(m_state_db.get(), STATE_SWITCH_CAPABILITY_TABLE_NAME); + TableConnector app_switch_table(m_app_db.get(), APP_SWITCH_TABLE_NAME); + TableConnector conf_asic_sensors(m_config_db.get(), CFG_ASIC_SENSORS_TABLE_NAME); + + vector switch_tables = { + conf_asic_sensors, + app_switch_table + }; + + gSwitchOrch = new SwitchOrch(m_app_db.get(), switch_tables, stateDbSwitchTable); + gDirectory.set(gSwitchOrch); + ut_orch_list.push_back((Orch **)&gSwitchOrch); + + vector flex_counter_tables = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + + m_FlexCounterOrch = new FlexCounterOrch(m_config_db.get(), flex_counter_tables); + gDirectory.set(m_FlexCounterOrch); + ut_orch_list.push_back((Orch **)&m_FlexCounterOrch); + + static const vector route_pattern_tables = { + CFG_FLOW_COUNTER_ROUTE_PATTERN_TABLE_NAME, + }; + gFlowCounterRouteOrch = new FlowCounterRouteOrch(m_config_db.get(), route_pattern_tables); + gDirectory.set(gFlowCounterRouteOrch); + ut_orch_list.push_back((Orch **)&gFlowCounterRouteOrch); + + gVrfOrch = new VRFOrch(m_app_db.get(), APP_VRF_TABLE_NAME, m_state_db.get(), STATE_VRF_OBJECT_TABLE_NAME); + gDirectory.set(gVrfOrch); + ut_orch_list.push_back((Orch **)&gVrfOrch); + + gIntfsOrch = new IntfsOrch(m_app_db.get(), APP_INTF_TABLE_NAME, gVrfOrch, m_chassis_app_db.get()); + gDirectory.set(gIntfsOrch); + ut_orch_list.push_back((Orch **)&gIntfsOrch); + + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); + gDirectory.set(gPortsOrch); + ut_orch_list.push_back((Orch **)&gPortsOrch); + + const int fgnhgorch_pri = 15; + + vector fgnhg_tables = { + { CFG_FG_NHG, fgnhgorch_pri }, + { CFG_FG_NHG_PREFIX, fgnhgorch_pri }, + { CFG_FG_NHG_MEMBER, fgnhgorch_pri } + }; + + gFgNhgOrch = new FgNhgOrch(m_config_db.get(), m_app_db.get(), m_state_db.get(), fgnhg_tables, gNeighOrch, gIntfsOrch, gVrfOrch); + gDirectory.set(gFgNhgOrch); + ut_orch_list.push_back((Orch **)&gFgNhgOrch); + + const int fdborch_pri = 20; + + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri }, + { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri }, + { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri } + }; + + TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); + TableConnector stateMclagDbFdb(m_state_db.get(), STATE_MCLAG_REMOTE_FDB_TABLE_NAME); + gFdbOrch = new FdbOrch(m_app_db.get(), app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch); + gDirectory.set(gFdbOrch); + ut_orch_list.push_back((Orch **)&gFdbOrch); + + gNeighOrch = new NeighOrch(m_app_db.get(), APP_NEIGH_TABLE_NAME, gIntfsOrch, gFdbOrch, gPortsOrch, m_chassis_app_db.get()); + gDirectory.set(gNeighOrch); + ut_orch_list.push_back((Orch **)&gNeighOrch); + + vector tunnel_tables = { + APP_TUNNEL_DECAP_TABLE_NAME, + APP_TUNNEL_DECAP_TERM_TABLE_NAME + }; + m_TunnelDecapOrch = new TunnelDecapOrch(m_app_db.get(), m_state_db.get(), m_config_db.get(), tunnel_tables); + gDirectory.set(m_TunnelDecapOrch); + ut_orch_list.push_back((Orch **)&m_TunnelDecapOrch); + vector mux_tables = { + CFG_MUX_CABLE_TABLE_NAME, + CFG_PEER_SWITCH_TABLE_NAME + }; + + vector buffer_tables = { + APP_BUFFER_POOL_TABLE_NAME, + APP_BUFFER_PROFILE_TABLE_NAME, + APP_BUFFER_QUEUE_TABLE_NAME, + APP_BUFFER_PG_TABLE_NAME, + APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, + APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME + }; + gBufferOrch = new BufferOrch(m_app_db.get(), m_config_db.get(), m_state_db.get(), buffer_tables); + ut_orch_list.push_back((Orch **)&gBufferOrch); + + vector policer_tables = { + TableConnector(m_config_db.get(), CFG_POLICER_TABLE_NAME), + TableConnector(m_config_db.get(), CFG_PORT_STORM_CONTROL_TABLE_NAME) + }; + + TableConnector stateDbStorm(m_state_db.get(), STATE_BUM_STORM_CAPABILITY_TABLE_NAME); + gPolicerOrch = new PolicerOrch(policer_tables, gPortsOrch); + gDirectory.set(gPolicerOrch); + ut_orch_list.push_back((Orch **)&gPolicerOrch); + + gNhgOrch = new NhgOrch(m_app_db.get(), APP_NEXTHOP_GROUP_TABLE_NAME); + gDirectory.set(gNhgOrch); + ut_orch_list.push_back((Orch **)&gNhgOrch); + + vector srv6_tables = { + APP_SRV6_SID_LIST_TABLE_NAME, + APP_SRV6_MY_SID_TABLE_NAME + }; + gSrv6Orch = new Srv6Orch(m_app_db.get(), srv6_tables, gSwitchOrch, gVrfOrch, gNeighOrch); + gDirectory.set(gSrv6Orch); + ut_orch_list.push_back((Orch **)&gSrv6Orch); + gCrmOrch = new CrmOrch(m_config_db.get(), CFG_CRM_TABLE_NAME); + gDirectory.set(gCrmOrch); + ut_orch_list.push_back((Orch **)&gCrmOrch); + + const int routeorch_pri = 5; + vector route_tables = { + { APP_ROUTE_TABLE_NAME, routeorch_pri }, + { APP_LABEL_ROUTE_TABLE_NAME, routeorch_pri } + }; + gRouteOrch = new RouteOrch(m_app_db.get(), route_tables, gSwitchOrch, gNeighOrch, gIntfsOrch, gVrfOrch, gFgNhgOrch, gSrv6Orch); + gDirectory.set(gRouteOrch); + ut_orch_list.push_back((Orch **)&gRouteOrch); + TableConnector stateDbMirrorSession(m_state_db.get(), STATE_MIRROR_SESSION_TABLE_NAME); + TableConnector confDbMirrorSession(m_config_db.get(), CFG_MIRROR_SESSION_TABLE_NAME); + gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, gPolicerOrch); + gDirectory.set(gMirrorOrch); + ut_orch_list.push_back((Orch **)&gMirrorOrch); + + vector dash_tables = { + APP_DASH_APPLIANCE_TABLE_NAME, + APP_DASH_ROUTING_TYPE_TABLE_NAME, + APP_DASH_ENI_TABLE_NAME, + APP_DASH_ENI_ROUTE_TABLE_NAME, + APP_DASH_QOS_TABLE_NAME + }; + + m_DashOrch = new DashOrch(m_app_db.get(), dash_tables, nullptr); + gDirectory.set(m_DashOrch); + ut_orch_list.push_back((Orch **)&m_DashOrch); + + TableConnector confDbAclTable(m_config_db.get(), CFG_ACL_TABLE_TABLE_NAME); + TableConnector confDbAclTableType(m_config_db.get(), CFG_ACL_TABLE_TYPE_TABLE_NAME); + TableConnector confDbAclRuleTable(m_config_db.get(), CFG_ACL_RULE_TABLE_NAME); + TableConnector appDbAclTable(m_app_db.get(), APP_ACL_TABLE_TABLE_NAME); + TableConnector appDbAclTableType(m_app_db.get(), APP_ACL_TABLE_TYPE_TABLE_NAME); + TableConnector appDbAclRuleTable(m_app_db.get(), APP_ACL_RULE_TABLE_NAME); + + vector acl_table_connectors = { + confDbAclTableType, + confDbAclTable, + confDbAclRuleTable, + appDbAclTable, + appDbAclRuleTable, + appDbAclTableType, + }; + gAclOrch = new AclOrch(acl_table_connectors, m_state_db.get(), + gSwitchOrch, gPortsOrch, gMirrorOrch, gNeighOrch, gRouteOrch, NULL); + gDirectory.set(gAclOrch); + ut_orch_list.push_back((Orch **)&gAclOrch); + + m_MuxOrch = new MuxOrch(m_config_db.get(), mux_tables, m_TunnelDecapOrch, gNeighOrch, gFdbOrch); + gDirectory.set(m_MuxOrch); + ut_orch_list.push_back((Orch **)&m_MuxOrch); + + m_MuxCableOrch = new MuxCableOrch(m_app_db.get(), m_state_db.get(), APP_MUX_CABLE_TABLE_NAME); + gDirectory.set(m_MuxCableOrch); + ut_orch_list.push_back((Orch **)&m_MuxCableOrch); + + m_MuxStateOrch = new MuxStateOrch(m_state_db.get(), STATE_HW_MUX_CABLE_TABLE_NAME); + gDirectory.set(m_MuxStateOrch); + ut_orch_list.push_back((Orch **)&m_MuxStateOrch); + + m_VxlanTunnelOrch = new VxlanTunnelOrch(m_state_db.get(), m_app_db.get(), APP_VXLAN_TUNNEL_TABLE_NAME); + gDirectory.set(m_VxlanTunnelOrch); + ut_orch_list.push_back((Orch **)&m_VxlanTunnelOrch); + + ApplyInitialConfigs(); + PostSetUp(); +} + +void MockOrchTest::TearDown() +{ + PreTearDown(); + for (std::vector::reverse_iterator rit = ut_orch_list.rbegin(); rit != ut_orch_list.rend(); ++rit) + { + Orch **orch = *rit; + delete *orch; + *orch = nullptr; + } + + gDirectory.m_values.clear(); + + ut_helper::uninitSaiApi(); +} +} \ No newline at end of file diff --git a/tests/mock_tests/mock_orch_test.h b/tests/mock_tests/mock_orch_test.h index fe6d3a0e07..86c5a36655 100644 --- a/tests/mock_tests/mock_orch_test.h +++ b/tests/mock_tests/mock_orch_test.h @@ -9,9 +9,6 @@ #include "gtest/gtest.h" #include -using namespace std; -using ::testing::Return; -using ::testing::Throw; namespace mock_orch_test { @@ -53,267 +50,13 @@ namespace mock_orch_test MuxStateOrch *m_MuxStateOrch; FlexCounterOrch *m_FlexCounterOrch; VxlanTunnelOrch *m_VxlanTunnelOrch; - - virtual void ApplyInitialConfigs() {} - - void PrepareSai() - { - sai_attribute_t attr; - - attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; - attr.value.booldata = true; - - sai_status_t status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); - ASSERT_EQ(status, SAI_STATUS_SUCCESS); - - // Get switch source MAC address - attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; - status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); - - ASSERT_EQ(status, SAI_STATUS_SUCCESS); - - gMacAddress = attr.value.mac; - - attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; - status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); - - ASSERT_EQ(status, SAI_STATUS_SUCCESS); - - gVirtualRouterId = attr.value.oid; - - /* Create a loopback underlay router interface */ - vector underlay_intf_attrs; - - sai_attribute_t underlay_intf_attr; - underlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; - underlay_intf_attr.value.oid = gVirtualRouterId; - underlay_intf_attrs.push_back(underlay_intf_attr); - - underlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; - underlay_intf_attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_LOOPBACK; - underlay_intf_attrs.push_back(underlay_intf_attr); - - underlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_MTU; - underlay_intf_attr.value.u32 = 9100; - underlay_intf_attrs.push_back(underlay_intf_attr); - - status = sai_router_intfs_api->create_router_interface(&gUnderlayIfId, gSwitchId, (uint32_t)underlay_intf_attrs.size(), underlay_intf_attrs.data()); - ASSERT_EQ(status, SAI_STATUS_SUCCESS); - } - - virtual void PostSetUp() {}; - - void SetUp() override - { - map profile = { - { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, - { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } - }; - - ut_helper::initSaiApi(profile); - m_app_db = make_shared("APPL_DB", 0); - m_config_db = make_shared("CONFIG_DB", 0); - m_state_db = make_shared("STATE_DB", 0); - m_chassis_app_db = make_shared("CHASSIS_APP_DB", 0); - - PrepareSai(); - - const int portsorch_base_pri = 40; - vector ports_tables = { - { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, - { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, - { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, - { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, - { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } - }; - - TableConnector stateDbSwitchTable(m_state_db.get(), STATE_SWITCH_CAPABILITY_TABLE_NAME); - TableConnector app_switch_table(m_app_db.get(), APP_SWITCH_TABLE_NAME); - TableConnector conf_asic_sensors(m_config_db.get(), CFG_ASIC_SENSORS_TABLE_NAME); - - vector switch_tables = { - conf_asic_sensors, - app_switch_table - }; - - gSwitchOrch = new SwitchOrch(m_app_db.get(), switch_tables, stateDbSwitchTable); - gDirectory.set(gSwitchOrch); - ut_orch_list.push_back((Orch **)&gSwitchOrch); - - vector flex_counter_tables = { - CFG_FLEX_COUNTER_TABLE_NAME - }; - - m_FlexCounterOrch = new FlexCounterOrch(m_config_db.get(), flex_counter_tables); - gDirectory.set(m_FlexCounterOrch); - ut_orch_list.push_back((Orch **)&m_FlexCounterOrch); - - static const vector route_pattern_tables = { - CFG_FLOW_COUNTER_ROUTE_PATTERN_TABLE_NAME, - }; - gFlowCounterRouteOrch = new FlowCounterRouteOrch(m_config_db.get(), route_pattern_tables); - gDirectory.set(gFlowCounterRouteOrch); - ut_orch_list.push_back((Orch **)&gFlowCounterRouteOrch); - - gVrfOrch = new VRFOrch(m_app_db.get(), APP_VRF_TABLE_NAME, m_state_db.get(), STATE_VRF_OBJECT_TABLE_NAME); - gDirectory.set(gVrfOrch); - ut_orch_list.push_back((Orch **)&gVrfOrch); - - gIntfsOrch = new IntfsOrch(m_app_db.get(), APP_INTF_TABLE_NAME, gVrfOrch, m_chassis_app_db.get()); - gDirectory.set(gIntfsOrch); - ut_orch_list.push_back((Orch **)&gIntfsOrch); - - gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); - gDirectory.set(gPortsOrch); - ut_orch_list.push_back((Orch **)&gPortsOrch); - - const int fgnhgorch_pri = 15; - - vector fgnhg_tables = { - { CFG_FG_NHG, fgnhgorch_pri }, - { CFG_FG_NHG_PREFIX, fgnhgorch_pri }, - { CFG_FG_NHG_MEMBER, fgnhgorch_pri } - }; - - gFgNhgOrch = new FgNhgOrch(m_config_db.get(), m_app_db.get(), m_state_db.get(), fgnhg_tables, gNeighOrch, gIntfsOrch, gVrfOrch); - gDirectory.set(gFgNhgOrch); - ut_orch_list.push_back((Orch **)&gFgNhgOrch); - - const int fdborch_pri = 20; - - vector app_fdb_tables = { - { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri }, - { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri }, - { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri } - }; - - TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); - TableConnector stateMclagDbFdb(m_state_db.get(), STATE_MCLAG_REMOTE_FDB_TABLE_NAME); - gFdbOrch = new FdbOrch(m_app_db.get(), app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch); - gDirectory.set(gFdbOrch); - ut_orch_list.push_back((Orch **)&gFdbOrch); - - gNeighOrch = new NeighOrch(m_app_db.get(), APP_NEIGH_TABLE_NAME, gIntfsOrch, gFdbOrch, gPortsOrch, m_chassis_app_db.get()); - gDirectory.set(gNeighOrch); - ut_orch_list.push_back((Orch **)&gNeighOrch); - - vector tunnel_tables = { - APP_TUNNEL_DECAP_TABLE_NAME, - APP_TUNNEL_DECAP_TERM_TABLE_NAME - }; - m_TunnelDecapOrch = new TunnelDecapOrch(m_app_db.get(), m_state_db.get(), m_config_db.get(), tunnel_tables); - gDirectory.set(m_TunnelDecapOrch); - ut_orch_list.push_back((Orch **)&m_TunnelDecapOrch); - vector mux_tables = { - CFG_MUX_CABLE_TABLE_NAME, - CFG_PEER_SWITCH_TABLE_NAME - }; - - vector buffer_tables = { - APP_BUFFER_POOL_TABLE_NAME, - APP_BUFFER_PROFILE_TABLE_NAME, - APP_BUFFER_QUEUE_TABLE_NAME, - APP_BUFFER_PG_TABLE_NAME, - APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, - APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME - }; - gBufferOrch = new BufferOrch(m_app_db.get(), m_config_db.get(), m_state_db.get(), buffer_tables); - ut_orch_list.push_back((Orch **)&gBufferOrch); - - vector policer_tables = { - TableConnector(m_config_db.get(), CFG_POLICER_TABLE_NAME), - TableConnector(m_config_db.get(), CFG_PORT_STORM_CONTROL_TABLE_NAME) - }; - - TableConnector stateDbStorm(m_state_db.get(), STATE_BUM_STORM_CAPABILITY_TABLE_NAME); - gPolicerOrch = new PolicerOrch(policer_tables, gPortsOrch); - gDirectory.set(gPolicerOrch); - ut_orch_list.push_back((Orch **)&gPolicerOrch); - - gNhgOrch = new NhgOrch(m_app_db.get(), APP_NEXTHOP_GROUP_TABLE_NAME); - gDirectory.set(gNhgOrch); - ut_orch_list.push_back((Orch **)&gNhgOrch); - - vector srv6_tables = { - APP_SRV6_SID_LIST_TABLE_NAME, - APP_SRV6_MY_SID_TABLE_NAME - }; - gSrv6Orch = new Srv6Orch(m_app_db.get(), srv6_tables, gSwitchOrch, gVrfOrch, gNeighOrch); - gDirectory.set(gSrv6Orch); - ut_orch_list.push_back((Orch **)&gSrv6Orch); - gCrmOrch = new CrmOrch(m_config_db.get(), CFG_CRM_TABLE_NAME); - gDirectory.set(gCrmOrch); - ut_orch_list.push_back((Orch **)&gCrmOrch); - - const int routeorch_pri = 5; - vector route_tables = { - { APP_ROUTE_TABLE_NAME, routeorch_pri }, - { APP_LABEL_ROUTE_TABLE_NAME, routeorch_pri } - }; - gRouteOrch = new RouteOrch(m_app_db.get(), route_tables, gSwitchOrch, gNeighOrch, gIntfsOrch, gVrfOrch, gFgNhgOrch, gSrv6Orch); - gDirectory.set(gRouteOrch); - ut_orch_list.push_back((Orch **)&gRouteOrch); - TableConnector stateDbMirrorSession(m_state_db.get(), STATE_MIRROR_SESSION_TABLE_NAME); - TableConnector confDbMirrorSession(m_config_db.get(), CFG_MIRROR_SESSION_TABLE_NAME); - gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, gPolicerOrch); - gDirectory.set(gMirrorOrch); - ut_orch_list.push_back((Orch **)&gMirrorOrch); - - TableConnector confDbAclTable(m_config_db.get(), CFG_ACL_TABLE_TABLE_NAME); - TableConnector confDbAclTableType(m_config_db.get(), CFG_ACL_TABLE_TYPE_TABLE_NAME); - TableConnector confDbAclRuleTable(m_config_db.get(), CFG_ACL_RULE_TABLE_NAME); - TableConnector appDbAclTable(m_app_db.get(), APP_ACL_TABLE_TABLE_NAME); - TableConnector appDbAclTableType(m_app_db.get(), APP_ACL_TABLE_TYPE_TABLE_NAME); - TableConnector appDbAclRuleTable(m_app_db.get(), APP_ACL_RULE_TABLE_NAME); - - vector acl_table_connectors = { - confDbAclTableType, - confDbAclTable, - confDbAclRuleTable, - appDbAclTable, - appDbAclRuleTable, - appDbAclTableType, - }; - gAclOrch = new AclOrch(acl_table_connectors, m_state_db.get(), - gSwitchOrch, gPortsOrch, gMirrorOrch, gNeighOrch, gRouteOrch, NULL); - gDirectory.set(gAclOrch); - ut_orch_list.push_back((Orch **)&gAclOrch); - - m_MuxOrch = new MuxOrch(m_config_db.get(), mux_tables, m_TunnelDecapOrch, gNeighOrch, gFdbOrch); - gDirectory.set(m_MuxOrch); - ut_orch_list.push_back((Orch **)&m_MuxOrch); - - m_MuxCableOrch = new MuxCableOrch(m_app_db.get(), m_state_db.get(), APP_MUX_CABLE_TABLE_NAME); - gDirectory.set(m_MuxCableOrch); - ut_orch_list.push_back((Orch **)&m_MuxCableOrch); - - m_MuxStateOrch = new MuxStateOrch(m_state_db.get(), STATE_HW_MUX_CABLE_TABLE_NAME); - gDirectory.set(m_MuxStateOrch); - ut_orch_list.push_back((Orch **)&m_MuxStateOrch); - - m_VxlanTunnelOrch = new VxlanTunnelOrch(m_state_db.get(), m_app_db.get(), APP_VXLAN_TUNNEL_TABLE_NAME); - gDirectory.set(m_VxlanTunnelOrch); - ut_orch_list.push_back((Orch **)&m_VxlanTunnelOrch); - - ApplyInitialConfigs(); - PostSetUp(); - } - - virtual void PreTearDown() {}; - - void TearDown() override - { - PreTearDown(); - for (std::vector::reverse_iterator rit = ut_orch_list.rbegin(); rit != ut_orch_list.rend(); ++rit) - { - Orch **orch = *rit; - delete *orch; - *orch = nullptr; - } - - gDirectory.m_values.clear(); - - ut_helper::uninitSaiApi(); - } + DashOrch *m_DashOrch; + + void PrepareSai(); + void SetUp(); + void TearDown(); + virtual void ApplyInitialConfigs(); + virtual void PostSetUp(); + virtual void PreTearDown(); }; } diff --git a/tests/mock_tests/mock_orchagent_main.h b/tests/mock_tests/mock_orchagent_main.h index 3437d7e22f..f2469a09ef 100644 --- a/tests/mock_tests/mock_orchagent_main.h +++ b/tests/mock_tests/mock_orchagent_main.h @@ -11,6 +11,7 @@ #include "fdborch.h" #include "mirrororch.h" #define private public +#include "dashorch.h" #include "bufferorch.h" #include "qosorch.h" #define protected public @@ -90,3 +91,6 @@ extern sai_samplepacket_api_t *sai_samplepacket_api; extern sai_fdb_api_t* sai_fdb_api; extern sai_twamp_api_t* sai_twamp_api; extern sai_tam_api_t* sai_tam_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; diff --git a/tests/mock_tests/ut_saihelper.cpp b/tests/mock_tests/ut_saihelper.cpp index f2b7c54ad5..269f54f06b 100644 --- a/tests/mock_tests/ut_saihelper.cpp +++ b/tests/mock_tests/ut_saihelper.cpp @@ -91,6 +91,9 @@ namespace ut_helper sai_api_query(SAI_API_FDB, (void**)&sai_fdb_api); sai_api_query(SAI_API_TWAMP, (void**)&sai_twamp_api); sai_api_query(SAI_API_TAM, (void**)&sai_tam_api); + sai_api_query((sai_api_t)SAI_API_DASH_VIP, (void**)&sai_dash_vip_api); + sai_api_query((sai_api_t)SAI_API_DASH_DIRECTION_LOOKUP, (void**)&sai_dash_direction_lookup_api); + sai_api_query((sai_api_t)SAI_API_DASH_ENI, (void**)&sai_dash_eni_api); return SAI_STATUS_SUCCESS; } @@ -122,6 +125,9 @@ namespace ut_helper sai_counter_api = nullptr; sai_twamp_api = nullptr; sai_tam_api = nullptr; + sai_dash_vip_api = nullptr; + sai_dash_direction_lookup_api = nullptr; + sai_dash_eni_api = nullptr; return SAI_STATUS_SUCCESS; } diff --git a/tests/sai_attrs.py b/tests/sai_attrs.py new file mode 100644 index 0000000000..207eb545ed --- /dev/null +++ b/tests/sai_attrs.py @@ -0,0 +1,17 @@ +SAI_ENI_ATTR_PL_SIP = 'SAI_ENI_ATTR_PL_SIP' +SAI_ENI_ATTR_PL_SIP_MASK = 'SAI_ENI_ATTR_PL_SIP_MASK' +SAI_ENI_ATTR_PL_UNDERLAY_SIP = 'SAI_ENI_ATTR_PL_UNDERLAY_SIP' +SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID = 'SAI_ENI_ATTR_OUTBOUND_ROUTING_GROUP_ID' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ACTION_SET_TUNNEL_MAPPING = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ACTION_SET_TUNNEL_MAPPING' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ACTION_SET_PRIVATE_LINK_MAPPING = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ACTION_SET_PRIVATE_LINK_MAPPING' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP_MASK = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP_MASK' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_ACTION = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_ACTION' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_SIP = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_SIP' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_SIP_MASK = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_SIP_MASK' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP_MASK = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DIP_MASK' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_DASH_ENCAPSULATION = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_DASH_ENCAPSULATION' +SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_TUNNEL_KEY = 'SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_TUNNEL_KEY' +SAI_DASH_ENCAPSULATION_NVGRE = 'SAI_DASH_ENCAPSULATION_NVGRE' +SAI_OUTBOUND_ROUTING_ENTRY_ATTR_UNDERLAY_SIP = 'SAI_OUTBOUND_ROUTING_ENTRY_ATTR_UNDERLAY_SIP' \ No newline at end of file diff --git a/tests/test_dash_vnet.py b/tests/test_dash_vnet.py deleted file mode 100644 index 5a38fb2d15..0000000000 --- a/tests/test_dash_vnet.py +++ /dev/null @@ -1,344 +0,0 @@ -from swsscommon import swsscommon - -from dash_api.appliance_pb2 import * -from dash_api.vnet_pb2 import * -from dash_api.eni_pb2 import * -from dash_api.route_pb2 import * -from dash_api.route_rule_pb2 import * -from dash_api.vnet_mapping_pb2 import * -from dash_api.route_type_pb2 import * -from dash_api.types_pb2 import * - -import typing -import time -import binascii -import uuid -import ipaddress -import sys -import socket - - -DVS_ENV = ["HWSKU=DPU-2P"] -NUM_PORTS = 2 - -def to_string(value): - if isinstance(value, bool): - return "true" if value else "false" - elif isinstance(value, bytes): - return value - return str(value) - - -class ProduceStateTable(object): - def __init__(self, database, table_name: str): - self.table = swsscommon.ProducerStateTable( - database.db_connection, - table_name) - - def __setitem__(self, key: str, pairs: typing.Union[dict, list, tuple]): - pairs_str = [] - if isinstance(pairs, dict): - pairs = pairs.items() - for k, v in pairs: - pairs_str.append((to_string(k), to_string(v))) - self.table.set(key, pairs_str) - - def __delitem__(self, key: str): - self.table.delete(str(key)) - - -class Table(object): - def __init__(self, database, table_name: str): - self.table_name = table_name - self.table = swsscommon.Table(database.db_connection, self.table_name) - - def __getitem__(self, key: str): - exists, result = self.table.get(str(key)) - if not exists: - return None - else: - return dict(result) - - def get_keys(self): - return self.table.getKeys() - - def get_newly_created_oid(self, old_oids): - new_oids = self.asic_db.wait_for_n_keys(table, len(old_oids) + 1) - oid = [ids for ids in new_oids if ids not in old_oids] - return oid[0] - - -class Dash(object): - def __init__(self, dvs): - self.dvs = dvs - self.app_dash_appliance_table = ProduceStateTable( - self.dvs.get_app_db(), "DASH_APPLIANCE_TABLE") - self.asic_direction_lookup_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_DIRECTION_LOOKUP_ENTRY") - self.asic_vip_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_VIP_ENTRY") - self.app_dash_vnet_table = ProduceStateTable( - self.dvs.get_app_db(), "DASH_VNET_TABLE") - self.asic_dash_vnet_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_VNET") - self.app_dash_eni_table = ProduceStateTable( - self.dvs.get_app_db(), "DASH_ENI_TABLE") - self.asic_eni_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_ENI") - self.asic_eni_ether_addr_map_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_ENI_ETHER_ADDRESS_MAP_ENTRY") - self.app_dash_vnet_map_table = ProduceStateTable( - self.dvs.get_app_db(), "DASH_VNET_MAPPING_TABLE") - self.asic_dash_outbound_ca_to_pa_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_CA_TO_PA_ENTRY") - self.asic_pa_validation_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_PA_VALIDATION_ENTRY") - self.app_dash_route_table = ProduceStateTable( - self.dvs.get_app_db(), "DASH_ROUTE_TABLE") - self.app_dash_route_rule_table = ProduceStateTable( - self.dvs.get_app_db(), "DASH_ROUTE_RULE_TABLE") - self.asic_outbound_routing_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY") - self.asic_inbound_routing_rule_table = Table( - self.dvs.get_asic_db(), "ASIC_STATE:SAI_OBJECT_TYPE_INBOUND_ROUTING_ENTRY") - - def create_appliance(self, appliance_id, attr_maps: dict): - self.app_dash_appliance_table[str(appliance_id)] = attr_maps - - def remove_appliance(self, appliance_id): - del self.app_dash_appliance_table[str(appliance_id)] - - def create_vnet(self, vnet, attr_maps: dict): - self.app_dash_vnet_table[str(vnet)] = attr_maps - - def remove_vnet(self, vnet): - del self.app_dash_vnet_table[str(vnet)] - - def create_eni(self, eni, attr_maps: dict): - self.app_dash_eni_table[str(eni)] = attr_maps - - def remove_eni(self, eni): - del self.app_dash_eni_table[str(eni)] - - def create_vnet_map(self, vnet, ip, attr_maps: dict): - self.app_dash_vnet_map_table[str(vnet) + ":" + str(ip)] = attr_maps - - def remove_vnet_map(self, vnet, ip): - del self.app_dash_vnet_map_table[str(vnet) + ":" + str(ip)] - - def create_outbound_routing(self, mac_string, ip, attr_maps: dict): - self.app_dash_route_table[str(mac_string) + ":" + str(ip)] = attr_maps - - def remove_outbound_routing(self, mac_string, ip): - del self.app_dash_route_table[str(mac_string) + ":" + str(ip)] - - def create_inbound_routing(self, mac_string, vni, ip, attr_maps: dict): - self.app_dash_route_rule_table[str(mac_string) + ":" + str(vni) + ":" + str(ip)] = attr_maps - - def remove_inbound_routing(self, mac_string, vni, ip): - del self.app_dash_route_rule_table[str(mac_string) + ":" + str(vni) + ":" + str(ip)] - -class TestDash(object): - def test_appliance(self, dvs): - dashobj = Dash(dvs) - self.appliance_id = "100" - self.sip = "10.0.0.1" - self.vm_vni = "4321" - pb = Appliance() - pb.sip.ipv4 = socket.htonl(int(ipaddress.ip_address(self.sip))) - pb.vm_vni = int(self.vm_vni) - dashobj.create_appliance(self.appliance_id, {"pb": pb.SerializeToString()}) - time.sleep(3) - - direction_entries = dashobj.asic_direction_lookup_table.get_keys() - assert direction_entries - fvs = dashobj.asic_direction_lookup_table[direction_entries[0]] - for fv in fvs.items(): - if fv[0] == "SAI_DIRECTION_LOOKUP_ENTRY_ATTR_ACTION": - assert fv[1] == "SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION" - vip_entries = dashobj.asic_vip_table.get_keys() - assert vip_entries - fvs = dashobj.asic_vip_table[vip_entries[0]] - for fv in fvs.items(): - if fv[0] == "SAI_VIP_ENTRY_ATTR_ACTION": - assert fv[1] == "SAI_VIP_ENTRY_ACTION_ACCEPT" - return dashobj - - def test_vnet(self, dvs): - dashobj = Dash(dvs) - self.vnet = "Vnet1" - self.vni = "45654" - self.guid = "559c6ce8-26ab-4193-b946-ccc6e8f930b2" - pb = Vnet() - pb.vni = int(self.vni) - pb.guid.value = bytes.fromhex(uuid.UUID(self.guid).hex) - dashobj.create_vnet(self.vnet, {"pb": pb.SerializeToString()}) - time.sleep(3) - vnets = dashobj.asic_dash_vnet_table.get_keys() - assert vnets - self.vnet_oid = vnets[0] - vnet_attr = dashobj.asic_dash_vnet_table[self.vnet_oid] - assert vnet_attr["SAI_VNET_ATTR_VNI"] == "45654" - return dashobj - - def test_eni(self, dvs): - dashobj = Dash(dvs) - self.vnet = "Vnet1" - self.mac_string = "F4939FEFC47E" - self.mac_address = "F4:93:9F:EF:C4:7E" - self.eni_id = "497f23d7-f0ac-4c99-a98f-59b470e8c7bd" - self.underlay_ip = "25.1.1.1" - self.admin_state = "enabled" - pb = Eni() - pb.eni_id = self.eni_id - pb.mac_address = bytes.fromhex(self.mac_address.replace(":", "")) - pb.underlay_ip.ipv4 = socket.htonl(int(ipaddress.ip_address(self.underlay_ip))) - pb.admin_state = State.STATE_ENABLED - pb.vnet = self.vnet - dashobj.create_eni(self.mac_string, {"pb": pb.SerializeToString()}) - time.sleep(3) - vnets = dashobj.asic_dash_vnet_table.get_keys() - assert vnets - self.vnet_oid = vnets[0] - enis = dashobj.asic_eni_table.get_keys() - assert enis - self.eni_oid = enis[0]; - fvs = dashobj.asic_eni_table[enis[0]] - for fv in fvs.items(): - if fv[0] == "SAI_ENI_ATTR_VNET_ID": - assert fv[1] == str(self.vnet_oid) - if fv[0] == "SAI_ENI_ATTR_PPS": - assert fv[1] == 0 - if fv[0] == "SAI_ENI_ATTR_CPS": - assert fv[1] == 0 - if fv[0] == "SAI_ENI_ATTR_FLOWS": - assert fv[1] == 0 - if fv[0] == "SAI_ENI_ATTR_ADMIN_STATE": - assert fv[1] == "true" - - time.sleep(3) - eni_addr_maps = dashobj.asic_eni_ether_addr_map_table.get_keys() - assert eni_addr_maps - fvs = dashobj.asic_eni_ether_addr_map_table[eni_addr_maps[0]] - for fv in fvs.items(): - if fv[0] == "SAI_ENI_ETHER_ADDRESS_MAP_ENTRY_ATTR_ENI_ID": - assert fv[1] == str(self.eni_oid) - - # test admin state update - pb.admin_state = State.STATE_DISABLED - dashobj.create_eni(self.mac_string, {"pb": pb.SerializeToString()}) - time.sleep(3) - enis = dashobj.asic_eni_table.get_keys() - assert len(enis) == 1 - assert enis[0] == self.eni_oid - eni_attrs = dashobj.asic_eni_table[self.eni_oid] - assert eni_attrs["SAI_ENI_ATTR_ADMIN_STATE"] == "false" - - return dashobj - - def test_vnet_map(self, dvs): - dashobj = Dash(dvs) - self.vnet = "Vnet1" - self.ip1 = "10.1.1.1" - self.ip2 = "10.1.1.2" - self.mac_address = "F4:93:9F:EF:C4:7E" - self.routing_type = "vnet_encap" - self.underlay_ip = "101.1.2.3" - pb = VnetMapping() - pb.mac_address = bytes.fromhex(self.mac_address.replace(":", "")) - pb.action_type = RoutingType.ROUTING_TYPE_VNET_ENCAP - pb.underlay_ip.ipv4 = socket.htonl(int(ipaddress.ip_address(self.underlay_ip))) - - dashobj.create_vnet_map(self.vnet, self.ip1, {"pb": pb.SerializeToString()}) - dashobj.create_vnet_map(self.vnet, self.ip2, {"pb": pb.SerializeToString()}) - time.sleep(3) - - vnet_ca_to_pa_maps = dashobj.asic_dash_outbound_ca_to_pa_table.get_keys() - assert len(vnet_ca_to_pa_maps) >= 2 - fvs = dashobj.asic_dash_outbound_ca_to_pa_table[vnet_ca_to_pa_maps[0]] - for fv in fvs.items(): - if fv[0] == "SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_UNDERLAY_DIP": - assert fv[1] == "101.1.2.3" - if fv[0] == "SAI_OUTBOUND_CA_TO_PA_ENTRY_ATTR_OVERLAY_DMAC": - assert fv[1] == "F4:93:9F:EF:C4:7E" - - vnet_pa_validation_maps = dashobj.asic_pa_validation_table.get_keys() - assert vnet_pa_validation_maps - fvs = dashobj.asic_pa_validation_table[vnet_pa_validation_maps[0]] - for fv in fvs.items(): - if fv[0] == "SAI_PA_VALIDATION_ENTRY_ATTR_ACTION": - assert fv[1] == "SAI_PA_VALIDATION_ENTRY_ACTION_PERMIT" - return dashobj - - def test_outbound_routing(self, dvs): - dashobj = Dash(dvs) - self.vnet = "Vnet1" - self.mac_string = "F4939FEFC47E" - self.ip = "10.1.0.0/24" - self.action_type = "vnet_direct" - self.overlay_ip= "10.0.0.6" - pb = Route() - pb.action_type = RoutingType.ROUTING_TYPE_VNET_DIRECT - pb.vnet_direct.vnet = self.vnet - pb.vnet_direct.overlay_ip.ipv4 = socket.htonl(int(ipaddress.ip_address(self.overlay_ip))) - dashobj.create_outbound_routing(self.mac_string, self.ip, {"pb": pb.SerializeToString()}) - time.sleep(3) - - outbound_routing_entries = dashobj.asic_outbound_routing_table.get_keys() - assert outbound_routing_entries - fvs = dashobj.asic_outbound_routing_table[outbound_routing_entries[0]] - for fv in fvs.items(): - if fv[0] == "SAI_OUTBOUND_ROUTING_ENTRY_ATTR_ACTION": - assert fv[1] == "SAI_OUTBOUND_ROUTING_ENTRY_ACTION_ROUTE_VNET_DIRECT" - if fv[0] == "SAI_OUTBOUND_ROUTING_ENTRY_ATTR_OVERLAY_IP": - assert fv[1] == "10.0.0.6" - assert "SAI_OUTBOUND_ROUTING_ENTRY_ATTR_DST_VNET_ID" in fvs - return dashobj - - def test_inbound_routing(self, dvs): - dashobj = Dash(dvs) - self.mac_string = "F4939FEFC47E" - self.vnet = "Vnet1" - self.vni = "3251" - self.ip = "10.1.1.1" - self.action_type = "decap" - self.pa_validation = "true" - self.priority = "1" - self.protocol = "0" - pb = RouteRule() - pb.pa_validation = True - pb.priority = int(self.priority) - pb.protocol = int(self.protocol) - pb.vnet = self.vnet - - dashobj.create_inbound_routing(self.mac_string, self.vni, self.ip, {"pb": pb.SerializeToString()}) - time.sleep(3) - - inbound_routing_entries = dashobj.asic_inbound_routing_rule_table.get_keys() - assert inbound_routing_entries - fvs = dashobj.asic_inbound_routing_rule_table[inbound_routing_entries[0]] - for fv in fvs.items(): - if fv[0] == "SAI_INBOUND_ROUTING_ENTRY_ATTR_ACTION": - assert fv[1] == "SAI_INBOUND_ROUTING_ENTRY_ACTION_TUNNEL_DECAP_PA_VALIDATE" - return dashobj - - def test_cleanup(self, dvs): - dashobj = Dash(dvs) - self.vnet = "Vnet1" - self.mac_string = "F4939FEFC47E" - self.vni = "3251" - self.sip = "10.1.1.1" - self.dip = "10.1.0.0/24" - self.appliance_id = "100" - dashobj.remove_inbound_routing(self.mac_string, self.vni, self.sip) - dashobj.remove_outbound_routing(self.mac_string, self.dip) - dashobj.remove_eni(self.mac_string) - dashobj.remove_vnet_map(self.vnet, self.sip) - dashobj.remove_vnet(self.vnet) - dashobj.remove_appliance(self.appliance_id) - -# 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