Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmake/QsfpServiceTestHwTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ target_link_libraries(hw_transceiver_utils
Folly::folly
fboss_error
platform_mapping
port_test_utils
switch_config_cpp2
transceiver_cpp2
transceiver_manager
Expand Down
1 change: 1 addition & 0 deletions fboss/qsfp_service/test/hw_test/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ cpp_library(
"fbsource//third-party/fmt:fmt",
"fbsource//third-party/googletest:gtest",
"//fboss/agent:fboss-error",
"//fboss/agent/test/utils:port_test_utils",
"//fboss/lib/config:fboss_config_utils",
"//fboss/qsfp_service:transceiver-manager",
"//fboss/qsfp_service/module/properties:transceiver-properties-manager",
Expand Down
22 changes: 12 additions & 10 deletions fboss/qsfp_service/test/hw_test/HwI2cSelectTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

#include "fboss/qsfp_service/test/hw_test/HwPortUtils.h"
#include "fboss/qsfp_service/test/hw_test/HwQsfpEnsemble.h"
#include "fboss/qsfp_service/test/hw_test/HwTransceiverUtils.h"

#include <folly/gen/Base.h>
#include <folly/logging/xlog.h>

namespace facebook::fboss {
Expand Down Expand Up @@ -68,21 +68,23 @@ TEST_F(HwTest, i2cUniqueSerialNumbers) {
if (snIds.find(sn) == snIds.end()) {
snIds[sn] = tcvrId;
} else {
// Found duplicated serial numbers, module must be DAC and connected to
// another DAC on the other end
// Found duplicated serial numbers, module must be a single cable
// assembly (DAC/AEC/AOC) connected back to itself on the other end
auto neighborId = snIds[sn];
CHECK(cabledNames.find(tcvrId) != cabledNames.end());
CHECK(cabledNames.find(neighborId) != cabledNames.end());
EXPECT_EQ(cabledNames[tcvrId].first, cabledNames[neighborId].second);
EXPECT_EQ(cabledNames[tcvrId].second, cabledNames[neighborId].first);

auto transmitterTech =
*(transceiverInfo[tcvrId].tcvrState()->cable()->transmitterTech());
EXPECT_EQ(TransmitterTechnology::COPPER, transmitterTech);

transmitterTech = *(
transceiverInfo[neighborId].tcvrState()->cable()->transmitterTech());
EXPECT_EQ(TransmitterTechnology::COPPER, transmitterTech);
for (auto id : {tcvrId, neighborId}) {
const auto& tcvrState = *transceiverInfo[id].tcvrState();
auto transmitterTech = *(tcvrState.cable()->transmitterTech());
EXPECT_TRUE(
transmitterTech == TransmitterTechnology::COPPER ||
utility::HwTransceiverUtils::isAoc(tcvrState))
<< "Transceiver " << id
<< " shares a serial number but is neither copper nor AOC";
}
}
}
}
Expand Down
46 changes: 46 additions & 0 deletions fboss/qsfp_service/test/hw_test/HwTransceiverUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
#include "fboss/qsfp_service/test/hw_test/HwTransceiverUtils.h"

#include <algorithm>
#include <set>

#include <fmt/format.h>
Expand All @@ -18,8 +19,10 @@
#include "fboss/agent/FbossError.h"
#include "fboss/agent/gen-cpp2/switch_config_types.h"
#include "fboss/agent/platforms/common/PlatformMapping.h"
#include "fboss/agent/test/utils/PortTestUtils.h"
#include "fboss/lib/config/PlatformConfigUtils.h"
#include "fboss/qsfp_service/TransceiverManager.h"
#include "fboss/qsfp_service/module/cmis/CmisHelper.h"
#include "fboss/qsfp_service/module/properties/TransceiverPropertiesManager.h"

namespace facebook::fboss::utility {
Expand Down Expand Up @@ -354,6 +357,14 @@ void HwTransceiverUtils::verifyMediaInterfaceCompliance(
mediaInterfaces.push_back(allMediaInterfaces[mediaLane]);
}

if (isAoc(tcvrState)) {
// An AOC programs like an active cable regardless of the profile's
// copper/optical suffix, so the per-profile verifiers below (which
// read smfCode or expect a copper transmitter) don't apply.
verifyActiveOpticalCableProfile(mgmtInterface, mediaInterfaces, profile);
return;
}

switch (profile) {
case cfg::PortProfileID::PROFILE_10G_1_NRZ_NOFEC_OPTICAL:
verify10gProfile(tcvrState, mgmtInterface, mediaInterfaces);
Expand Down Expand Up @@ -651,6 +662,41 @@ void HwTransceiverUtils::verifyCopper800gProfile(
}
}

bool HwTransceiverUtils::isAoc(const TcvrState& tcvrState) {
return TransceiverManager::activeCable(tcvrState) &&
*tcvrState.cable()->transmitterTech() == TransmitterTechnology::OPTICAL;
}

void HwTransceiverUtils::verifyActiveOpticalCableProfile(
const TransceiverManagementInterface mgmtInterface,
const std::vector<MediaInterfaceId>& mediaInterfaces,
cfg::PortProfileID profile) {
EXPECT_EQ(mgmtInterface, TransceiverManagementInterface::CMIS);

const auto& speedApplications = CmisHelper::getActiveSpeedApplication();
auto expectedCodesIt = speedApplications.find(utility::getSpeed(profile));
if (expectedCodesIt == speedApplications.end()) {
throw FbossError(
"No active cable application for profile ",
apache::thrift::util::enumNameSafe(profile));
}
const auto& expectedCodes = expectedCodesIt->second;
const auto& activeMediaMap = CmisHelper::getActiveMediaInterfaceMapping();

for (const auto& mediaId : mediaInterfaces) {
auto activeCuCode = *mediaId.media()->activeCuCode();
EXPECT_TRUE(
std::find(expectedCodes.begin(), expectedCodes.end(), activeCuCode) !=
expectedCodes.end())
<< "Unexpected activeCuCode "
<< apache::thrift::util::enumNameSafe(activeCuCode) << " for profile "
<< apache::thrift::util::enumNameSafe(profile);
auto mediaCodeIt = activeMediaMap.find(activeCuCode);
ASSERT_TRUE(mediaCodeIt != activeMediaMap.end());
EXPECT_EQ(*mediaId.code(), mediaCodeIt->second);
}
}

void HwTransceiverUtils::verifyDataPathEnabled(
const TcvrState& tcvrState,
const std::string& portName) {
Expand Down
9 changes: 9 additions & 0 deletions fboss/qsfp_service/test/hw_test/HwTransceiverUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,16 @@ class HwTransceiverUtils {
time_t timeReference,
bool expectedReset);

// Active optical cable: reports ACTIVE_CABLES media type encoding like an
// AEC, but an optical transmitter. Its media interface union carries
// activeCuCode, not smfCode.
static bool isAoc(const TcvrState& tcvrState);

private:
static void verifyActiveOpticalCableProfile(
TransceiverManagementInterface mgmtInterface,
const std::vector<MediaInterfaceId>& mediaInterfaces,
cfg::PortProfileID profile);
static void verifyOpticsSettings(
const TcvrState& tcvrState,
const std::string& portName,
Expand Down
Loading