From 714282b5312ba39725eb2ce7524856e73e40051a Mon Sep 17 00:00:00 2001 From: Vybhav Acharya Date: Fri, 15 May 2026 06:06:49 +0000 Subject: [PATCH] Add fboss2-dev config ptp transparent-clock CLI command Implements `fboss2-dev config ptp transparent-clock ` to toggle the ptpTcEnable field in SwitchSettings. The change is HITLESS (no agent restart required). --- cmake/CliFboss2.cmake | 4 + cmake/CliFboss2TestConfig.cmake | 1 + cmake/CliFboss2TestIntegrationTest.cmake | 1 + fboss/cli/fboss2/BUCK | 4 + fboss/cli/fboss2/CmdListConfig.cpp | 16 +++ .../commands/config/ptp/CmdConfigPtp.cpp | 20 ++++ .../fboss2/commands/config/ptp/CmdConfigPtp.h | 35 ++++++ .../CmdConfigPtpTransparentClock.cpp | 86 ++++++++++++++ .../CmdConfigPtpTransparentClock.h | 53 +++++++++ fboss/cli/fboss2/test/config/BUCK | 1 + .../CmdConfigPtpTransparentClockTest.cpp | 108 ++++++++++++++++++ fboss/cli/fboss2/test/integration_test/BUCK | 1 + .../test/integration_test/ConfigPtpTest.cpp | 63 ++++++++++ 13 files changed, 393 insertions(+) create mode 100644 fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.cpp create mode 100644 fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h create mode 100644 fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.cpp create mode 100644 fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h create mode 100644 fboss/cli/fboss2/test/config/CmdConfigPtpTransparentClockTest.cpp create mode 100644 fboss/cli/fboss2/test/integration_test/ConfigPtpTest.cpp diff --git a/cmake/CliFboss2.cmake b/cmake/CliFboss2.cmake index bf99733e85fa4..73adec39670b5 100644 --- a/cmake/CliFboss2.cmake +++ b/cmake/CliFboss2.cmake @@ -717,6 +717,10 @@ add_library(fboss2_config_lib fboss/cli/fboss2/commands/config/l2/CmdConfigL2.h fboss/cli/fboss2/commands/config/l2/learning_mode/CmdConfigL2LearningMode.cpp fboss/cli/fboss2/commands/config/l2/learning_mode/CmdConfigL2LearningMode.h + fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.cpp + fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h + fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.cpp + fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h fboss/cli/fboss2/commands/config/protocol/CmdConfigProtocol.cpp fboss/cli/fboss2/commands/config/protocol/CmdConfigProtocol.h fboss/cli/fboss2/commands/config/protocol/bgp/BgpConfigSession.cpp diff --git a/cmake/CliFboss2TestConfig.cmake b/cmake/CliFboss2TestConfig.cmake index 670736e44deae..6686171cad8df 100644 --- a/cmake/CliFboss2TestConfig.cmake +++ b/cmake/CliFboss2TestConfig.cmake @@ -9,6 +9,7 @@ add_executable(fboss2_cmd_config_test fboss/cli/fboss2/test/config/CmdConfigInterfaceSwitchportAccessVlanTest.cpp fboss/cli/fboss2/test/config/CmdConfigInterfaceTest.cpp fboss/cli/fboss2/test/config/CmdConfigL2LearningModeTest.cpp + fboss/cli/fboss2/test/config/CmdConfigPtpTransparentClockTest.cpp fboss/cli/fboss2/test/config/CmdConfigQosBufferPoolTest.cpp fboss/cli/fboss2/test/config/CmdConfigReloadTest.cpp fboss/cli/fboss2/test/config/CmdConfigSessionCommitTest.cpp diff --git a/cmake/CliFboss2TestIntegrationTest.cmake b/cmake/CliFboss2TestIntegrationTest.cmake index 83db4e88430c1..e4248952e3140 100644 --- a/cmake/CliFboss2TestIntegrationTest.cmake +++ b/cmake/CliFboss2TestIntegrationTest.cmake @@ -14,6 +14,7 @@ add_executable(fboss2_integration_test fboss/cli/fboss2/test/integration_test/ConfigInterfaceProfileTest.cpp fboss/cli/fboss2/test/integration_test/ConfigL2LearningModeTest.cpp fboss/cli/fboss2/test/integration_test/ConfigPfcTest.cpp + fboss/cli/fboss2/test/integration_test/ConfigPtpTest.cpp fboss/cli/fboss2/test/integration_test/ConfigPortQueueConfigTest.cpp fboss/cli/fboss2/test/integration_test/ConfigQosPolicyMapTest.cpp fboss/cli/fboss2/test/integration_test/ConfigSessionClearTest.cpp diff --git a/fboss/cli/fboss2/BUCK b/fboss/cli/fboss2/BUCK index 3173c042ff267..63e2712a95668 100644 --- a/fboss/cli/fboss2/BUCK +++ b/fboss/cli/fboss2/BUCK @@ -1030,6 +1030,8 @@ cpp_library( "commands/config/interface/switchport/access/vlan/CmdConfigInterfaceSwitchportAccessVlan.cpp", "commands/config/l2/CmdConfigL2.cpp", "commands/config/l2/learning_mode/CmdConfigL2LearningMode.cpp", + "commands/config/ptp/CmdConfigPtp.cpp", + "commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.cpp", "commands/config/protocol/CmdConfigProtocol.cpp", "commands/config/protocol/bgp/BgpConfigSession.cpp", "commands/config/protocol/bgp/CmdConfigProtocolBgp.cpp", @@ -1128,6 +1130,8 @@ cpp_library( "commands/config/interface/switchport/access/vlan/CmdConfigInterfaceSwitchportAccessVlan.h", "commands/config/l2/CmdConfigL2.h", "commands/config/l2/learning_mode/CmdConfigL2LearningMode.h", + "commands/config/ptp/CmdConfigPtp.h", + "commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h", "commands/config/protocol/CmdConfigProtocol.h", "commands/config/protocol/bgp/BgpConfigSession.h", "commands/config/protocol/bgp/CmdConfigProtocolBgp.h", diff --git a/fboss/cli/fboss2/CmdListConfig.cpp b/fboss/cli/fboss2/CmdListConfig.cpp index 80ef97e9567a2..a2085510fb6fd 100644 --- a/fboss/cli/fboss2/CmdListConfig.cpp +++ b/fboss/cli/fboss2/CmdListConfig.cpp @@ -80,6 +80,8 @@ #include "fboss/cli/fboss2/commands/config/protocol/bgp/peer/CmdConfigProtocolBgpPeerV4OverV6Nh.h" #include "fboss/cli/fboss2/commands/config/protocol/bgp/peer/CmdConfigProtocolBgpPeerWarningLimit.h" #include "fboss/cli/fboss2/commands/config/protocol/bgp/peer/CmdConfigProtocolBgpPeerWarningOnly.h" +#include "fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h" +#include "fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h" #include "fboss/cli/fboss2/commands/config/qos/CmdConfigQos.h" #include "fboss/cli/fboss2/commands/config/qos/buffer_pool/CmdConfigQosBufferPool.h" #include "fboss/cli/fboss2/commands/config/qos/policy/CmdConfigQosPolicy.h" @@ -170,6 +172,20 @@ const CommandTree& kConfigCommandTree() { }}, }, + { + "config", + "ptp", + "Configure PTP settings", + commandHandler, + argRegistrar, + {{ + "transparent-clock", + "Enable or disable PTP transparent clock mode", + commandHandler, + argRegistrar, + }}, + }, + { "config", "protocol", diff --git a/fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.cpp b/fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.cpp new file mode 100644 index 0000000000000..09d99de28c5ba --- /dev/null +++ b/fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2004-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#include "fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h" + +#include "fboss/cli/fboss2/CmdHandler.cpp" + +namespace facebook::fboss { + +// Explicit template instantiation +template void CmdHandler::run(); + +} // namespace facebook::fboss diff --git a/fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h b/fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h new file mode 100644 index 0000000000000..deb37a5f1a07a --- /dev/null +++ b/fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2004-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#pragma once + +#include "fboss/cli/fboss2/CmdHandler.h" + +namespace facebook::fboss { + +struct CmdConfigPtpTraits : public WriteCommandTraits { + using ObjectArgType = utils::NoneArgType; + using RetType = std::string; +}; + +class CmdConfigPtp : public CmdHandler { + public: + using ObjectArgType = CmdConfigPtpTraits::ObjectArgType; + using RetType = CmdConfigPtpTraits::RetType; + + RetType queryClient(const HostInfo& /* hostInfo */) { + throw std::runtime_error( + "Incomplete command, please use 'transparent-clock' subcommand"); + } + + void printOutput(const RetType& /* model */) {} +}; + +} // namespace facebook::fboss diff --git a/fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.cpp b/fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.cpp new file mode 100644 index 0000000000000..eb4639e1527fe --- /dev/null +++ b/fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2004-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#include "fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h" + +#include "fboss/cli/fboss2/CmdHandler.cpp" + +#include +#include +#include +#include "fboss/cli/fboss2/session/ConfigSession.h" + +namespace facebook::fboss { + +namespace { +constexpr std::string_view kEnable = "enable"; +constexpr std::string_view kDisable = "disable"; +} // namespace + +PtpTransparentClockArg::PtpTransparentClockArg(std::vector v) { + if (v.empty()) { + throw std::invalid_argument( + "PTP transparent clock state is required (enable or disable)"); + } + if (v.size() != 1) { + throw std::invalid_argument( + "Expected exactly one argument (enable or disable)"); + } + + std::string state = v[0]; + folly::toLowerAscii(state); + if (state == kEnable) { + enable_ = true; + } else if (state == kDisable) { + enable_ = false; + } else { + throw std::invalid_argument( + "Invalid PTP transparent clock state '" + v[0] + + "'. Expected 'enable' or 'disable'"); + } + data_.push_back(v[0]); +} + +CmdConfigPtpTransparentClockTraits::RetType +CmdConfigPtpTransparentClock::queryClient( + const HostInfo& /* hostInfo */, + const ObjectArgType& state) { + auto& session = ConfigSession::getInstance(); + auto& config = session.getAgentConfig(); + auto& swConfig = *config.sw(); + + bool newValue = state.getEnable(); + bool currentValue = *swConfig.switchSettings()->ptpTcEnable(); + + if (currentValue == newValue) { + return fmt::format( + "PTP transparent clock is already {}", + newValue ? "enabled" : "disabled"); + } + + swConfig.switchSettings()->ptpTcEnable() = newValue; + + session.saveConfig(cli::ServiceType::AGENT, cli::ConfigActionLevel::HITLESS); + + return fmt::format( + "Successfully {} PTP transparent clock", + newValue ? "enabled" : "disabled"); +} + +void CmdConfigPtpTransparentClock::printOutput(const RetType& output) { + std::cout << output << std::endl; +} + +// Explicit template instantiation +template void CmdHandler< + CmdConfigPtpTransparentClock, + CmdConfigPtpTransparentClockTraits>::run(); + +} // namespace facebook::fboss diff --git a/fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h b/fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h new file mode 100644 index 0000000000000..30e7f206aeb0d --- /dev/null +++ b/fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2004-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#pragma once + +#include "fboss/cli/fboss2/CmdHandler.h" +#include "fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h" + +namespace facebook::fboss { + +class PtpTransparentClockArg : public utils::BaseObjectArgType { + public: + /* implicit */ PtpTransparentClockArg( // NOLINT(google-explicit-constructor) + std::vector v); + + bool getEnable() const { + return enable_; + } + + private: + bool enable_{false}; +}; + +struct CmdConfigPtpTransparentClockTraits : public WriteCommandTraits { + using ParentCmd = CmdConfigPtp; + static void addCliArg(CLI::App& cmd, std::vector& args) { + cmd.add_option( + "state", args, "PTP transparent clock state (enable|disable)"); + } + using ObjectArgType = PtpTransparentClockArg; + using RetType = std::string; +}; + +class CmdConfigPtpTransparentClock : public CmdHandler< + CmdConfigPtpTransparentClock, + CmdConfigPtpTransparentClockTraits> { + public: + using ObjectArgType = CmdConfigPtpTransparentClockTraits::ObjectArgType; + using RetType = CmdConfigPtpTransparentClockTraits::RetType; + + RetType queryClient(const HostInfo& hostInfo, const ObjectArgType& state); + + void printOutput(const RetType& output); +}; + +} // namespace facebook::fboss diff --git a/fboss/cli/fboss2/test/config/BUCK b/fboss/cli/fboss2/test/config/BUCK index b14d20bcf0eca..ba04499029264 100644 --- a/fboss/cli/fboss2/test/config/BUCK +++ b/fboss/cli/fboss2/test/config/BUCK @@ -11,6 +11,7 @@ cpp_unittest( "CmdConfigInterfaceSwitchportAccessVlanTest.cpp", "CmdConfigInterfaceTest.cpp", "CmdConfigL2LearningModeTest.cpp", + "CmdConfigPtpTransparentClockTest.cpp", "CmdConfigQosBufferPoolTest.cpp", "CmdConfigReloadTest.cpp", "CmdConfigSessionCommitTest.cpp", diff --git a/fboss/cli/fboss2/test/config/CmdConfigPtpTransparentClockTest.cpp b/fboss/cli/fboss2/test/config/CmdConfigPtpTransparentClockTest.cpp new file mode 100644 index 0000000000000..a3ec585e09820 --- /dev/null +++ b/fboss/cli/fboss2/test/config/CmdConfigPtpTransparentClockTest.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2004-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#include "fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.h" +#include +#include +#include "fboss/cli/fboss2/session/ConfigSession.h" +#include "fboss/cli/fboss2/test/config/CmdConfigTestBase.h" +#include "fboss/cli/fboss2/utils/PortMap.h" // NOLINT(misc-include-cleaner) + +using namespace ::testing; + +namespace facebook::fboss { + +// Seed mirrors a production switch config where ptpTcEnable is true +class CmdConfigPtpTransparentClockTestFixture : public CmdConfigTestBase { + public: + CmdConfigPtpTransparentClockTestFixture() + : CmdConfigTestBase( + "fboss_ptp_tc_test_%%%%-%%%%-%%%%-%%%%", + R"({ + "sw": { + "switchSettings": { + "ptpTcEnable": true + } + } +})") {} + + protected: + const std::string cmdPrefix_ = "config ptp transparent-clock"; +}; + +// ============================================================================== +// PtpTransparentClockArg Validation Tests +// ============================================================================== + +TEST_F(CmdConfigPtpTransparentClockTestFixture, argValidation) { + // Valid values + EXPECT_TRUE(PtpTransparentClockArg({"enable"}).getEnable()); + EXPECT_FALSE(PtpTransparentClockArg({"disable"}).getEnable()); + + // Case-insensitive + EXPECT_TRUE(PtpTransparentClockArg({"ENABLE"}).getEnable()); + EXPECT_FALSE(PtpTransparentClockArg({"DISABLE"}).getEnable()); + EXPECT_TRUE(PtpTransparentClockArg({"Enable"}).getEnable()); + + // Invalid + EXPECT_THROW(PtpTransparentClockArg({}), std::invalid_argument); + EXPECT_THROW( + PtpTransparentClockArg({"enable", "extra"}), std::invalid_argument); + EXPECT_THROW(PtpTransparentClockArg({"on"}), std::invalid_argument); + EXPECT_THROW(PtpTransparentClockArg({"true"}), std::invalid_argument); +} + +// ============================================================================== +// Command Execution Tests +// ============================================================================== + +TEST_F(CmdConfigPtpTransparentClockTestFixture, disableWhenEnabled) { + // Seed has ptpTcEnable=true; disable it + setupTestableConfigSession(cmdPrefix_, "disable"); + CmdConfigPtpTransparentClock cmd; + HostInfo hostInfo("testhost"); + PtpTransparentClockArg arg({"disable"}); + + auto result = cmd.queryClient(hostInfo, arg); + EXPECT_THAT(result, HasSubstr("disable")); + + auto& config = ConfigSession::getInstance().getAgentConfig(); + EXPECT_FALSE(*config.sw()->switchSettings()->ptpTcEnable()); +} + +TEST_F(CmdConfigPtpTransparentClockTestFixture, enableWhenDisabled) { + // First disable, then re-enable + setupTestableConfigSession(cmdPrefix_, "disable"); + CmdConfigPtpTransparentClock cmd; + HostInfo hostInfo("testhost"); + + PtpTransparentClockArg disableArg({"disable"}); + cmd.queryClient(hostInfo, disableArg); + + PtpTransparentClockArg enableArg({"enable"}); + auto result = cmd.queryClient(hostInfo, enableArg); + EXPECT_THAT(result, HasSubstr("enable")); + + auto& config = ConfigSession::getInstance().getAgentConfig(); + EXPECT_TRUE(*config.sw()->switchSettings()->ptpTcEnable()); +} + +TEST_F(CmdConfigPtpTransparentClockTestFixture, alreadyEnabled) { + // Seed has ptpTcEnable=true; enabling again is a no-op + setupTestableConfigSession(cmdPrefix_, "enable"); + CmdConfigPtpTransparentClock cmd; + HostInfo hostInfo("testhost"); + PtpTransparentClockArg arg({"enable"}); + + auto result = cmd.queryClient(hostInfo, arg); + EXPECT_THAT(result, HasSubstr("already")); +} + +} // namespace facebook::fboss diff --git a/fboss/cli/fboss2/test/integration_test/BUCK b/fboss/cli/fboss2/test/integration_test/BUCK index 4c3731cddc0a4..6d93b2a9f8ff0 100644 --- a/fboss/cli/fboss2/test/integration_test/BUCK +++ b/fboss/cli/fboss2/test/integration_test/BUCK @@ -22,6 +22,7 @@ cpp_binary( "ConfigInterfaceProfileTest.cpp", "ConfigL2LearningModeTest.cpp", "ConfigPfcTest.cpp", + "ConfigPtpTest.cpp", "ConfigPortQueueConfigTest.cpp", "ConfigQosPolicyMapTest.cpp", "ConfigSessionClearTest.cpp", diff --git a/fboss/cli/fboss2/test/integration_test/ConfigPtpTest.cpp b/fboss/cli/fboss2/test/integration_test/ConfigPtpTest.cpp new file mode 100644 index 0000000000000..bc1065b702560 --- /dev/null +++ b/fboss/cli/fboss2/test/integration_test/ConfigPtpTest.cpp @@ -0,0 +1,63 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +/** + * End-to-end test for: + * fboss2-dev config ptp transparent-clock + * + * Reads the current ptpTcEnable value, toggles it twice, and restores the + * original state. The change is HITLESS so no agent restart is needed between + * steps. + */ + +#include +#include +#include +#include +#include "fboss/cli/fboss2/test/integration_test/Fboss2IntegrationTest.h" + +using namespace facebook::fboss; + +class ConfigPtpTest : public Fboss2IntegrationTest { + protected: + bool getPtpTcEnable() const { + auto config = getRunningConfig(); + const auto& sw = config["sw"]; + if (!sw.count("switchSettings")) { + return false; + } + const auto& settings = sw["switchSettings"]; + if (!settings.count("ptpTcEnable")) { + return false; + } + return settings["ptpTcEnable"].asBool(); + } + + void setPtpTcEnable(bool enable) { + std::string state = enable ? "enable" : "disable"; + auto result = runCli({"config", "ptp", "transparent-clock", state}); + ASSERT_EQ(result.exitCode, 0) + << "transparent-clock CLI failed: " << result.stderr; + commitConfig(); + } +}; + +TEST_F(ConfigPtpTest, ToggleTransparentClock) { + XLOG(INFO) << "[Step 1] Reading current PTP transparent clock state..."; + bool originalValue = getPtpTcEnable(); + XLOG(INFO) << " Current: " << (originalValue ? "enabled" : "disabled"); + + bool firstValue = !originalValue; + bool secondValue = originalValue; + + XLOG(INFO) << "[Step 2] Setting transparent-clock to '" + << (firstValue ? "enable" : "disable") << "'..."; + setPtpTcEnable(firstValue); + EXPECT_EQ(getPtpTcEnable(), firstValue); + + XLOG(INFO) << "[Step 3] Restoring to '" + << (secondValue ? "enable" : "disable") << "'..."; + setPtpTcEnable(secondValue); + EXPECT_EQ(getPtpTcEnable(), secondValue); + + XLOG(INFO) << "TEST PASSED"; +}