diff --git a/fboss/agent/hw/sai/switch/SaiManagerTable.cpp b/fboss/agent/hw/sai/switch/SaiManagerTable.cpp index ef0a4bc521d02..77ee092b034b8 100644 --- a/fboss/agent/hw/sai/switch/SaiManagerTable.cpp +++ b/fboss/agent/hw/sai/switch/SaiManagerTable.cpp @@ -231,6 +231,17 @@ void SaiManagerTable::reset(bool skipSwitchManager) { portManager_->resetTamObject(portId); } } +#endif +#if defined(TAJO_SAI_SDK) + // Tajo keeps a default switch-event TAM handle even without MoD reports. + // Always clear switch TAM binding first so TAM/TAM_EVENT/TAM_EVENT_THRESHOLD + // objects can be removed cleanly before switch teardown. + switchManager_->setTamObject({}); + // If MoD reports were configured, clear per-port TAM bindings too. + auto modPortIds = tamManager_->getAllMirrorOnDropPortIds(); + for (auto portId : modPortIds) { + portManager_->setTamObject(portId, {}); + } #endif tamManager_.reset(); diff --git a/fboss/agent/hw/sai/switch/npu/tajo/SaiTamManager.cpp b/fboss/agent/hw/sai/switch/npu/tajo/SaiTamManager.cpp index 579e58b0f1bed..ecde4be20019b 100644 --- a/fboss/agent/hw/sai/switch/npu/tajo/SaiTamManager.cpp +++ b/fboss/agent/hw/sai/switch/npu/tajo/SaiTamManager.cpp @@ -7,6 +7,7 @@ extern "C" { } #include +#include #include "fboss/agent/hw/sai/api/SwitchApi.h" #include "fboss/agent/hw/sai/store/SaiStore.h" @@ -104,28 +105,41 @@ void rebuildAndRebindTam( << " port(s)"; } -// Build a TAM_EVENT_THRESHOLD object whose UNIT is packets and RATE is the -// configured packet-per-second cap. Returns nullptr if no rate is configured -// or the configured value is non-positive — SAI_TAM_EVENT_ATTR_THRESHOLD -// will then be left unset on the TAM_EVENT, which is the most permissive -// default (no rate limiting). +// Build a TAM_EVENT_THRESHOLD object for PACKET_DROP events. +// On this SDK path, SAI_TAM_EVENT_ATTR_THRESHOLD is mandatory for +// SAI_TAM_EVENT_TYPE_PACKET_DROP, so we always create and attach a threshold +// object. When dropPacketRateThreshold is configured with a positive value, +// program UNIT=PACKETS and RATE=; otherwise leave threshold fields +// unset to keep the most permissive behavior (no explicit rate limiting). std::shared_ptr createTamEventThreshold( SaiStore* saiStore, std::optional rateThreshold) { - if (!rateThreshold.has_value() || *rateThreshold <= 0) { - if (rateThreshold.has_value()) { - XLOG(WARN) << "MirrorOnDropReport dropPacketRateThreshold=" - << *rateThreshold - << " is non-positive; ignoring (no rate limiting will apply)"; - } - return nullptr; - } SaiTamEventThresholdTraits::CreateAttributes thresholdTraits; - std::get>( - thresholdTraits) = - static_cast(SAI_TAM_EVENT_THRESHOLD_UNIT_PACKETS); - std::get>( - thresholdTraits) = static_cast(*rateThreshold); + if (rateThreshold.has_value() && *rateThreshold > 0) { + std::get>( + thresholdTraits) = + static_cast(SAI_TAM_EVENT_THRESHOLD_UNIT_PACKETS); + std::get>( + thresholdTraits) = static_cast(*rateThreshold); + } else if (rateThreshold.has_value()) { + XLOG(WARN) << "MirrorOnDropReport dropPacketRateThreshold=" + << *rateThreshold + << " is non-positive; using threshold object without explicit " + << "rate limit"; + std::get>( + thresholdTraits) = + static_cast(SAI_TAM_EVENT_THRESHOLD_UNIT_PACKETS); + std::get>( + thresholdTraits) = std::numeric_limits::max(); + } else { + // MoD default behavior when no threshold is configured: keep reporting + // enabled by using a permissive packet-rate cap. + std::get>( + thresholdTraits) = + static_cast(SAI_TAM_EVENT_THRESHOLD_UNIT_PACKETS); + std::get>( + thresholdTraits) = std::numeric_limits::max(); + } auto& store = saiStore->get(); return store.setObject(thresholdTraits, thresholdTraits); } @@ -220,13 +234,39 @@ std::shared_ptr SaiTamManager::createTamTransport( sai_int32_t transportType, std::optional dstMac) { auto& transportStore = saiStore_->get(); + std::optional srcMacAttr = + std::nullopt; + if (SaiTamTransportTraits::Attributes::SrcMacAddress:: + optionalExtensionAttributeId() + .has_value()) { + srcMacAttr = SaiTamTransportTraits::Attributes::SrcMacAddress( + folly::MacAddress(report->getSwitchMac())); + } else { + XLOG(INFO) << "Skipping TAM transport srcMac extension attribute " + << "(unsupported on this SAI implementation)"; + } + + std::optional dstMacAttr = + std::nullopt; + if (dstMac.has_value()) { + if (SaiTamTransportTraits::Attributes::DstMacAddress:: + optionalExtensionAttributeId() + .has_value()) { + dstMacAttr = + SaiTamTransportTraits::Attributes::DstMacAddress(dstMac.value()); + } else { + XLOG(INFO) << "Skipping TAM transport dstMac extension attribute " + << "(unsupported on this SAI implementation)"; + } + } + auto transportTraits = SaiTamTransportTraits::AdapterHostKey{ transportType, report->getLocalSrcPort(), report->getCollectorPort(), report->getMtu(), - folly::MacAddress(report->getSwitchMac()), - dstMac, + srcMacAttr, + dstMacAttr, }; return transportStore.setObject(transportTraits, transportTraits); }