diff --git a/orchagent/switch/switch_capabilities.cpp b/orchagent/switch/switch_capabilities.cpp index 049d9894e9..a8444c078c 100644 --- a/orchagent/switch/switch_capabilities.cpp +++ b/orchagent/switch/switch_capabilities.cpp @@ -399,29 +399,57 @@ void SwitchCapabilities::querySwitchEcmpHashAttrCapabilities() { SWSS_LOG_ENTER(); - sai_attr_capability_t attrCap; + sai_attr_capability_t ecmpCap; + auto ecmpStatus = queryAttrCapabilitiesSai( + ecmpCap, SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH + ); + if (ecmpStatus != SAI_STATUS_SUCCESS) + { + SWSS_LOG_WARN( + "Failed to get attribute(%s) capabilities", + toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH).c_str() + ); + } + else if (ecmpCap.get_implemented) + { + switchCapabilities.ecmpHash.isAttrSupported = true; + return; + } - auto status = queryAttrCapabilitiesSai( - attrCap, SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH + sai_attr_capability_t ecmpV4Cap; + auto ecmpV4Status = queryAttrCapabilitiesSai( + ecmpV4Cap, SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH_IPV4 ); - if (status != SAI_STATUS_SUCCESS) + if (ecmpV4Status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR( "Failed to get attribute(%s) capabilities", - toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH).c_str() + toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH_IPV4).c_str() ); return; } - if (!attrCap.get_implemented) + sai_attr_capability_t ecmpV6Cap; + auto ecmpV6Status = queryAttrCapabilitiesSai( + ecmpV6Cap, SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH_IPV6 + ); + if (ecmpV6Status != SAI_STATUS_SUCCESS) { - SWSS_LOG_WARN( - "Attribute(%s) GET is not implemented in SAI", - toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH).c_str() + SWSS_LOG_ERROR( + "Failed to get attribute(%s) capabilities", + toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_HASH_IPV6).c_str() ); return; } + if (!ecmpV4Cap.get_implemented || !ecmpV6Cap.get_implemented) + { + SWSS_LOG_ERROR( + "One or more of required ECMP capabilities not supported %d, %d", + ecmpV4Cap.get_implemented, ecmpV6Cap.get_implemented + ); + return; + } switchCapabilities.ecmpHash.isAttrSupported = true; } @@ -440,14 +468,44 @@ void SwitchCapabilities::querySwitchLagHashAttrCapabilities() "Failed to get attribute(%s) capabilities", toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_LAG_HASH).c_str() ); + } + else if (attrCap.get_implemented) + { + switchCapabilities.lagHash.isAttrSupported = true; return; } - if (!attrCap.get_implemented) + sai_attr_capability_t lagV4Cap; + auto lagV4Status = queryAttrCapabilitiesSai( + lagV4Cap, SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_LAG_HASH_IPV4 + ); + if (lagV4Status != SAI_STATUS_SUCCESS) { - SWSS_LOG_WARN( - "Attribute(%s) GET is not implemented in SAI", - toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_LAG_HASH).c_str() + SWSS_LOG_ERROR( + "Failed to get attribute(%s) capabilities", + toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_LAG_HASH_IPV4).c_str() + ); + return; + } + + sai_attr_capability_t lagV6Cap; + auto lagV6Status = queryAttrCapabilitiesSai( + lagV6Cap, SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_LAG_HASH_IPV6 + ); + if (lagV6Status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR( + "Failed to get attribute(%s) capabilities", + toStr(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_LAG_HASH_IPV6).c_str() + ); + return; + } + + if (!lagV4Cap.get_implemented || !lagV6Cap.get_implemented) + { + SWSS_LOG_ERROR( + "One or more of required LAG capabilities not supported %d, %d", + lagV4Cap.get_implemented, lagV6Cap.get_implemented ); return; } diff --git a/orchagent/switchorch.cpp b/orchagent/switchorch.cpp index aa09f3df80..6b940a78a7 100644 --- a/orchagent/switchorch.cpp +++ b/orchagent/switchorch.cpp @@ -710,11 +710,17 @@ void SwitchOrch::doAppSwitchTableTask(Consumer &consumer) } } -bool SwitchOrch::setSwitchHashFieldListSai(const SwitchHash &hash, bool isEcmpHash) const +sai_status_t SwitchOrch::setSwitchHashAttributeSai(sai_attr_id_t attrType, sai_object_id_t oid) const { - const auto &oid = isEcmpHash ? m_switchHashDefaults.ecmpHash.oid : m_switchHashDefaults.lagHash.oid; - const auto &hfSet = isEcmpHash ? hash.ecmp_hash.value : hash.lag_hash.value; + sai_attribute_t attr; + attr.id = attrType; + attr.value.oid = oid; + auto status = sai_switch_api->set_switch_attribute(gSwitchId, &attr); + return status; +} +sai_status_t SwitchOrch::setSwitchHashFieldListSai(const sai_object_id_t oid, const std::set &hfSet) const +{ std::vector hfList; std::transform( hfSet.cbegin(), hfSet.cend(), std::back_inserter(hfList), @@ -728,6 +734,104 @@ bool SwitchOrch::setSwitchHashFieldListSai(const SwitchHash &hash, bool isEcmpHa attr.value.s32list.count = static_cast(hfList.size()); auto status = sai_hash_api->set_hash_attribute(oid, &attr); + return status; +} + +sai_status_t SwitchOrch::createHashObjectSai(sai_object_id_t &oid, const std::set &hfSet) const +{ + std::vector hfList; + std::transform( + hfSet.cbegin(), hfSet.cend(), std::back_inserter(hfList), + [](sai_native_hash_field_t value) { return static_cast(value); } + ); + + sai_attribute_t attr; + + attr.id = SAI_HASH_ATTR_NATIVE_HASH_FIELD_LIST; + attr.value.s32list.list = hfList.data(); + attr.value.s32list.count = static_cast(hfList.size()); + + auto status = sai_hash_api->create_hash(&oid, gSwitchId, 1, &attr); + return status; +} + +bool SwitchOrch::setSwitchHashFieldList(const SwitchHash &hash, bool isEcmpHash) +{ + SWSS_LOG_ENTER(); + + const auto &hfSet = isEcmpHash ? hash.ecmp_hash.value : hash.lag_hash.value; + const auto &oid = isEcmpHash ? m_switchHashDefaults.ecmpHash.oid : m_switchHashDefaults.lagHash.oid; + const auto &platformSupportsOnlyV4V6 = isEcmpHash ? m_switchHashDefaults.ecmpHash.platformSupportsOnlyV4V6 : m_switchHashDefaults.lagHash.platformSupportsOnlyV4V6; + auto &v4Oid = isEcmpHash ? m_switchHashDefaults.ecmpHash.v4Oid : m_switchHashDefaults.lagHash.v4Oid; + auto &v6Oid = isEcmpHash ? m_switchHashDefaults.ecmpHash.v6Oid : m_switchHashDefaults.lagHash.v6Oid; + + sai_attr_id_t v4HashType = isEcmpHash ? SAI_SWITCH_ATTR_ECMP_HASH_IPV4 : SAI_SWITCH_ATTR_LAG_HASH_IPV4; + sai_attr_id_t v6HashType = isEcmpHash ? SAI_SWITCH_ATTR_ECMP_HASH_IPV6 : SAI_SWITCH_ATTR_LAG_HASH_IPV6; + + sai_status_t status; + + if (!platformSupportsOnlyV4V6) + { + // oid == SAI_NULL_OBJECT_ID is acceptable for non-platformSupportsOnlyV4V6 platforms + status = setSwitchHashFieldListSai(oid, hfSet); + return status == SAI_STATUS_SUCCESS; + } + + // platform (broadcom) supports only V4/V6 attribute type, v4Oid/v6Oid can not be NULL for modifying hash-fields + if (v4Oid == SAI_NULL_OBJECT_ID || v6Oid == SAI_NULL_OBJECT_ID) + { + sai_object_id_t v4OidAllotted, v6OidAllotted; + + // clear out the existing default fields which are associated with SAI_NULL_OBJECT_ID + // this step is necessary for broadcom chips + SWSS_LOG_DEBUG("Creating new oids for IPv4 and IPv6 Hash-fields"); + status = setSwitchHashAttributeSai(v4HashType, SAI_NULL_OBJECT_ID); + if( status == SAI_STATUS_SUCCESS) + { + status = setSwitchHashAttributeSai(v6HashType, SAI_NULL_OBJECT_ID); + } + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to reset hash parameters during initialization"); + return status == SAI_STATUS_SUCCESS; + } + + // create a new Hash object with given set of hash-fields + status = createHashObjectSai(v4OidAllotted, hfSet); + if (status == SAI_STATUS_SUCCESS) + { + status = createHashObjectSai(v6OidAllotted, hfSet); + } + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create hash object, status=%d", status); + return false; + } + + // set the hash attribute to new object oid + status = setSwitchHashAttributeSai(v4HashType, v4OidAllotted); + if (status == SAI_STATUS_SUCCESS) + { + status = setSwitchHashAttributeSai(v6HashType, v6OidAllotted); + } + if (status == SAI_STATUS_SUCCESS) + { + v4Oid = v4OidAllotted; + v6Oid = v6OidAllotted; + } + + return status == SAI_STATUS_SUCCESS; + } + + SWSS_LOG_DEBUG("Re-using IPv4 and IPv6 Hash-field oids"); + + // oids are allotted previously, use them now + status = setSwitchHashFieldListSai(v4Oid, hfSet); + if (status == SAI_STATUS_SUCCESS) + { + status = setSwitchHashFieldListSai(v6Oid, hfSet); + } + return status == SAI_STATUS_SUCCESS; } @@ -761,7 +865,7 @@ bool SwitchOrch::setSwitchHash(const SwitchHash &hash) return false; } - if (!setSwitchHashFieldListSai(hash, true)) + if (!setSwitchHashFieldList(hash, true)) { SWSS_LOG_ERROR("Failed to set switch ECMP hash in SAI"); return false; @@ -796,7 +900,7 @@ bool SwitchOrch::setSwitchHash(const SwitchHash &hash) return false; } - if (!setSwitchHashFieldListSai(hash, false)) + if (!setSwitchHashFieldList(hash, false)) { SWSS_LOG_ERROR("Failed to set switch LAG hash in SAI"); return false; @@ -1912,15 +2016,16 @@ void SwitchOrch::querySwitchTpidCapability() } } -bool SwitchOrch::getSwitchHashOidSai(sai_object_id_t &oid, bool isEcmpHash) const +bool SwitchOrch::getSwitchHashOidSai(sai_object_id_t &oid, sai_attr_id_t attr_id) const { sai_attribute_t attr; - attr.id = isEcmpHash ? SAI_SWITCH_ATTR_ECMP_HASH : SAI_SWITCH_ATTR_LAG_HASH; + attr.id = attr_id; attr.value.oid = SAI_NULL_OBJECT_ID; auto status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); if (status != SAI_STATUS_SUCCESS) { + SWSS_LOG_WARN("Failed to get switch hash OID"); return false; } @@ -1932,15 +2037,40 @@ bool SwitchOrch::getSwitchHashOidSai(sai_object_id_t &oid, bool isEcmpHash) cons void SwitchOrch::querySwitchHashDefaults() { SWSS_LOG_ENTER(); - - if (!getSwitchHashOidSai(m_switchHashDefaults.ecmpHash.oid, true)) + if (!getSwitchHashOidSai(m_switchHashDefaults.ecmpHash.oid, SAI_SWITCH_ATTR_ECMP_HASH) ) { - SWSS_LOG_WARN("Failed to get switch ECMP hash OID"); + auto rv4 = getSwitchHashOidSai( + m_switchHashDefaults.ecmpHash.v4Oid, SAI_SWITCH_ATTR_ECMP_HASH_IPV4); + + auto rv6 = getSwitchHashOidSai( + m_switchHashDefaults.ecmpHash.v6Oid, SAI_SWITCH_ATTR_ECMP_HASH_IPV6); + + if (!rv4 && !rv6) + { + SWSS_LOG_WARN("Failed to get switch ECMP hash OID"); + } + else + { + m_switchHashDefaults.ecmpHash.platformSupportsOnlyV4V6 = true; + } } - if (!getSwitchHashOidSai(m_switchHashDefaults.lagHash.oid, false)) + if (!getSwitchHashOidSai(m_switchHashDefaults.lagHash.oid, SAI_SWITCH_ATTR_LAG_HASH)) { - SWSS_LOG_WARN("Failed to get switch LAG hash OID"); + auto rv4 = getSwitchHashOidSai( + m_switchHashDefaults.lagHash.v4Oid, SAI_SWITCH_ATTR_LAG_HASH_IPV4); + + auto rv6 = getSwitchHashOidSai( + m_switchHashDefaults.lagHash.v6Oid, SAI_SWITCH_ATTR_LAG_HASH_IPV6); + + if (!rv4 && !rv6) + { + SWSS_LOG_WARN("Failed to get switch LAG hash OID"); + } + else + { + m_switchHashDefaults.lagHash.platformSupportsOnlyV4V6 = true; + } } } diff --git a/orchagent/switchorch.h b/orchagent/switchorch.h index 67a93625c0..3d4cbc0a99 100644 --- a/orchagent/switchorch.h +++ b/orchagent/switchorch.h @@ -94,11 +94,14 @@ class SwitchOrch : public Orch void generateSwitchCounterNameMap() const; // Switch hash - bool setSwitchHashFieldListSai(const SwitchHash &hash, bool isEcmpHash) const; + sai_status_t setSwitchHashFieldListSai(const sai_object_id_t oid, const std::set &hfSet) const; + sai_status_t createHashObjectSai(sai_object_id_t &oid, const std::set &hfSet) const; + sai_status_t setSwitchHashAttributeSai(sai_attr_id_t attrType, sai_object_id_t oid) const; + bool setSwitchHashFieldList(const SwitchHash &hash, bool isEcmpHash); bool setSwitchHashAlgorithmSai(const SwitchHash &hash, bool isEcmpHash) const; bool setSwitchHash(const SwitchHash &hash); - bool getSwitchHashOidSai(sai_object_id_t &oid, bool isEcmpHash) const; + bool getSwitchHashOidSai(sai_object_id_t &oid, sai_attr_id_t attr_id) const; void querySwitchHashDefaults(); void setSwitchIcmpOffloadCapability(); @@ -163,10 +166,17 @@ class SwitchOrch : public Orch struct { struct { sai_object_id_t oid = SAI_NULL_OBJECT_ID; + sai_object_id_t v4Oid = SAI_NULL_OBJECT_ID; + sai_object_id_t v6Oid = SAI_NULL_OBJECT_ID; + bool platformSupportsOnlyV4V6 = false; // platform supports only V4/V6 attr type } ecmpHash; struct { sai_object_id_t oid = SAI_NULL_OBJECT_ID; + sai_object_id_t v4Oid = SAI_NULL_OBJECT_ID; + sai_object_id_t v6Oid = SAI_NULL_OBJECT_ID; + bool platformSupportsOnlyV4V6 = false; // platform supports only V4/V6 attr type } lagHash; + } m_switchHashDefaults; // Statistics