Skip to content

Commit

Permalink
[Thinkit] gNMI port breakout tests, Make const parameters const or st…
Browse files Browse the repository at this point in the history
…ring_view & gNMI port interface tests.

PiperOrigin-RevId: 424183653
  • Loading branch information
kishanps authored and divyagayathri-hcl committed Nov 22, 2024
1 parent 328baa6 commit 66f45f1
Show file tree
Hide file tree
Showing 4 changed files with 518 additions and 70 deletions.
7 changes: 5 additions & 2 deletions tests/thinkit_gnmi_interface_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,8 @@ void BreakoutDuringPortInUse(thinkit::Switch& sut,
grpc::ClientContext context;
ASSERT_OK_AND_ASSIGN(auto port_index, GetPortIndex(platform_json_contents,
port_info.port_name));
ASSERT_OK(GetBreakoutModeConfigFromString(req, port_index,
ASSERT_OK(GetBreakoutModeConfigFromString(req, sut_gnmi_stub, port_index,
port_info.port_name,
port_info.supported_breakout_mode));

// Apply breakout config on port. Expect the set operation to fail
Expand Down Expand Up @@ -454,8 +455,10 @@ void BreakoutDuringPortInUse(thinkit::Switch& sut,
non_existing_port_list));

// Restore original port breakout config on port under test.
ASSERT_OK(GetBreakoutModeConfigFromString(req, port_index,
ASSERT_OK(GetBreakoutModeConfigFromString(req, sut_gnmi_stub, port_index,
port_info.port_name,
port_info.curr_breakout_mode));

LOG(INFO) << "Restoring original breakout mode "
<< port_info.curr_breakout_mode << " on port "
<< port_info.port_name << " on DUT";
Expand Down
157 changes: 113 additions & 44 deletions tests/thinkit_gnmi_interface_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
Expand All @@ -33,17 +35,17 @@ namespace {

using ::nlohmann::json;

} // namespace

void StripSymbolFromString(std::string& str, const char symbol) {
void StripSymbolFromString(std::string& str, char symbol) {
str.erase(remove(str.begin(), str.end(), symbol), str.end());
}

std::string ConstructSupportedBreakoutMode(std::string& num_breakouts,
std::string& breakout_speed) {
StripSymbolFromString(num_breakouts, ' ');
StripSymbolFromString(breakout_speed, ' ');
return absl::StrCat(num_breakouts, "x", breakout_speed);
} // namespace

std::string ConstructSupportedBreakoutMode(absl::string_view num_breakouts,
absl::string_view breakout_speed) {
std::string breakout_mode = absl::StrCat(num_breakouts, "x", breakout_speed);
StripSymbolFromString(breakout_mode, ' ');
return breakout_mode;
}

absl::StatusOr<std::vector<std::string>> GetSupportedBreakoutModesForPort(
Expand Down Expand Up @@ -105,8 +107,8 @@ absl::StatusOr<std::vector<std::string>> GetSupportedBreakoutModesForPort(
if (breakout_type == BreakoutType::kChannelized) {
for (const auto& mode : modes) {
// A breakout mode is a channelized mode if it is either a mixed mode (eg.
// 1x200G+2x100G) or it results in more than one number of interfaces
// (eg. 2x200G).
// 1x200G(4)+2x100G(4)) or it results in more than one number of
// interfaces (eg. 2x200G).
auto num_breakouts_str = mode.substr(0, mode.find('x'));
int num_breakouts;
if (!absl::SimpleAtoi(num_breakouts_str, &num_breakouts)) {
Expand Down Expand Up @@ -266,8 +268,8 @@ GetExpectedPortInfoForBreakoutMode(const std::string& port,
}

// For a mixed breakout mode, get "+" separated breakout groups.
// Eg. For a mixed breakout mode of "2x100G + 1x200G"; modes = {2x100G,
// 1x200G}
// Eg. For a mixed breakout mode of "2x100G(4) + 1x200G(4)"; modes =
// {2x100G(4), 1x200G(4)}
std::vector<std::string> modes = absl::StrSplit(breakout_mode, '+');
// Get maximum physical channels in a breakout group which is max
// lanes per physical port/number of groups in a breakout mode.
Expand Down Expand Up @@ -298,9 +300,9 @@ GetExpectedPortInfoForBreakoutMode(const std::string& port,

// For each resulting interface, construct the front panel interface name
// using offset from the parent port. For a breakout mode of Ethernet0 =>
// 2x100G+1x200G, the max channels per group would be 4 (8 max lanes per
// port/2 groups). Hence, breakout mode 2x100G (numBreakouts=2) would have
// an offset of 2 and 1x200G(numBreakouts=1) would have an offset of 1
// 2x100(4)G+1x200G(4), the max channels per group would be 4 (8 max lanes
// per port/2 groups). Hence, breakout mode 2x100G (numBreakouts=2) would
// have an offset of 2 and 1x200G(numBreakouts=1) would have an offset of 1
// leading to interfaces Ethernet0, Ethernet2 for mode 2x100G and
// Ethernet4 for mode 1x200G.
for (int i = 0; i < num_breakouts; i++) {
Expand Down Expand Up @@ -332,7 +334,8 @@ absl::StatusOr<absl::flat_hash_map<std::string, pins_test::PortBreakoutInfo>>
GetBreakoutStateInfoForPort(gnmi::gNMI::StubInterface* sut_gnmi_stub,
const std::string& port,
absl::string_view breakout_mode) {
ASSIGN_OR_RETURN(auto port_info,
absl::flat_hash_map<std::string, pins_test::PortBreakoutInfo> port_info;
ASSIGN_OR_RETURN(port_info,
GetExpectedPortInfoForBreakoutMode(port, breakout_mode));
for (auto& p : port_info) {
auto if_state_path = absl::StrCat("interfaces/interface[name=", p.first,
Expand Down Expand Up @@ -378,8 +381,46 @@ absl::StatusOr<std::string> GenerateComponentBreakoutConfig(
return component_config;
}

absl::StatusOr<bool> IsCopperPort(gnmi::gNMI::StubInterface* sut_gnmi_stub,
absl::string_view port) {
// Get transceiver name for the port.
auto state_path =
absl::StrCat("interfaces/interface[name=", port, "]/state/transceiver");
auto resp_parse_str = "openconfig-platform-transceiver:transceiver";
ASSIGN_OR_RETURN(
auto xcvrd_name,
GetGnmiStatePathInfo(sut_gnmi_stub, state_path, resp_parse_str),
_ << "Failed to get GNMI state path value for port transceiver for "
"port "
<< port);
StripSymbolFromString(xcvrd_name, '\"');

// TODO: Replace with PMD type when supported.
// Get cable length for the port transceiver.
state_path =
absl::StrCat("components/component[name=", xcvrd_name,
"]/transceiver/state/openconfig-platform-ext:cable-length");
resp_parse_str = "openconfig-platform-ext:cable-length";
ASSIGN_OR_RETURN(
auto cable_length_str,
GetGnmiStatePathInfo(sut_gnmi_stub, state_path, resp_parse_str),
_ << "Failed to get GNMI state path value for cable-length for "
"port "
<< port);
StripSymbolFromString(cable_length_str, '\"');

// Only cable lengths of copper ports are a positive value.
float cable_length;
if (!absl::SimpleAtof(cable_length_str, &cable_length)) {
return gutil::InternalErrorBuilder().LogError()
<< "Failed to convert string (" << cable_length_str << ") to float";
}
return (cable_length > 0);
}

absl::StatusOr<std::string> GenerateInterfaceBreakoutConfig(
absl::string_view port, const int id, absl::string_view breakout_speed) {
absl::string_view port, const int id, absl::string_view breakout_speed,
const bool is_copper_port) {
auto interface_config = absl::Substitute(
R"pb({
"config": {
Expand All @@ -406,18 +447,50 @@ absl::StatusOr<std::string> GenerateInterfaceBreakoutConfig(
}
)pb",
port, breakout_speed);
if (is_copper_port) {
interface_config = absl::Substitute(
R"pb({
"config": {
"enabled": true,
"loopback-mode": false,
"mtu": 9216,
"name": "$0",
"type": "iana-if-type:ethernetCsmacd"
},
"name": "$0",
"openconfig-if-ethernet:ethernet": {
"config": {
"port-speed": "openconfig-if-ethernet:SPEED_$1B",
"standalone-link-training": true
}
},
"subinterfaces": {
"subinterface":
[ {
"config": { "index": 0 },
"index": 0,
"openconfig-if-ip:ipv6": {
"unnumbered": { "config": { "enabled": true } }
}
}]
}
}
)pb",
port, breakout_speed);
}
return interface_config;
}

absl::Status GetBreakoutModeConfigFromString(
gnmi::SetRequest& req, const absl::string_view port_index,
gnmi::SetRequest& req, gnmi::gNMI::StubInterface* sut_gnmi_stub,
const absl::string_view port_index, const absl::string_view intf_name,
const absl::string_view breakout_mode) {
std::string kBreakoutPath = absl::StrCat("components/component[name=1/",
port_index, "]/port/breakout-mode");
// Get breakout groups corresponding to breakout mode.
// For a mixed breakout mode, get "+" separated breakout groups.
// Eg. For a mixed breakout mode of "2x100G + 1x200G"; modes = {2x100G,
// 1x200G}
// Eg. For a mixed breakout mode of "2x100G(4) + 1x200G(4)"; modes =
// {2x100G(4), 1x200G(4)}
std::vector<std::string> modes = absl::StrSplit(breakout_mode, '+');
std::vector<std::string> group_configs;
std::vector<std::string> interface_configs;
Expand All @@ -432,15 +505,18 @@ absl::Status GetBreakoutModeConfigFromString(
}
curr_port_number = (curr_port_number - 1) * kMaxPortLanes;

for (auto& mode : modes) {
ASSIGN_OR_RETURN(bool is_copper_port, IsCopperPort(sut_gnmi_stub, intf_name));

for (const auto& mode : modes) {
auto num_breakouts_str = mode.substr(0, mode.find('x'));
int num_breakouts;
if (!absl::SimpleAtoi(num_breakouts_str, &num_breakouts)) {
return gutil::InternalErrorBuilder().LogError()
<< "Failed to convert string (" << num_breakouts_str
<< ") to integer";
}
auto breakout_speed = mode.substr(mode.find('x') + 1);
auto xpos = mode.find('x');
auto breakout_speed = mode.substr(xpos + 1, mode.find('(') - xpos - 1);
auto num_physical_channels = max_channels_in_group / num_breakouts;
ASSIGN_OR_RETURN(
auto group_config,
Expand All @@ -452,26 +528,19 @@ absl::Status GetBreakoutModeConfigFromString(
// group.
for (int i = 0; i < num_breakouts; i++) {
auto port = absl::StrCat(kEthernet, std::to_string(curr_port_number));
ASSIGN_OR_RETURN(auto interfaceConfig,
GenerateInterfaceBreakoutConfig(port, curr_port_number,
breakout_speed));
interface_configs.push_back(interfaceConfig);
ASSIGN_OR_RETURN(
auto interface_config,
GenerateInterfaceBreakoutConfig(port, curr_port_number,
breakout_speed, is_copper_port));
interface_configs.push_back(interface_config);
int offset = max_channels_in_group / num_breakouts;
curr_port_number += offset;
}
index += 1;
}

std::string componentConfig, interfaceConfig;
for (auto& group_config : group_configs) {
componentConfig += absl::StrCat(group_config, ",");
}
for (auto& interface_config : interface_configs) {
interfaceConfig += absl::StrCat(interface_config, ",");
}
// Pop the last comma from the component and interface config array.
componentConfig.pop_back();
interfaceConfig.pop_back();
std::string full_component_config = absl::StrJoin(group_configs, ",");
std::string full_interface_config = absl::StrJoin(interface_configs, ",");

auto kBreakoutConfig = absl::Substitute(
R"pb({
Expand All @@ -488,21 +557,20 @@ absl::Status GetBreakoutModeConfigFromString(
}]
}
})pb",
interfaceConfig, absl::StrCat("1/", port_index), port_index,
componentConfig);
full_interface_config, absl::StrCat("1/", port_index), port_index,
full_component_config);
// Build GNMI config set request for given port breakout mode.
ASSIGN_OR_RETURN(
req, BuildGnmiSetRequest("", GnmiSetType::kReplace, kBreakoutConfig));
return absl::OkStatus();
}

std::vector<std::string> GetNonExistingPortsAfterBreakout(
absl::flat_hash_map<std::string, PortBreakoutInfo>& orig_port_info,
absl::flat_hash_map<std::string, PortBreakoutInfo>& new_port_info,
const absl::flat_hash_map<std::string, PortBreakoutInfo>& orig_port_info,
const absl::flat_hash_map<std::string, PortBreakoutInfo>& new_port_info,
bool expected_success) {
std::vector<std::string> nonExistingPortList;
absl::flat_hash_map<std::string, PortBreakoutInfo>*orig_map = &orig_port_info,
*new_map = &new_port_info;
const auto *orig_map = &orig_port_info, *new_map = &new_port_info;
if (!expected_success) {
orig_map = &new_port_info;
new_map = &orig_port_info;
Expand All @@ -517,8 +585,9 @@ std::vector<std::string> GetNonExistingPortsAfterBreakout(

absl::Status ValidateBreakoutState(
gnmi::gNMI::StubInterface* sut_gnmi_stub,
absl::flat_hash_map<std::string, PortBreakoutInfo>& expected_port_info,
std::vector<std::string>& non_existing_ports_list) {
const absl::flat_hash_map<std::string, PortBreakoutInfo>&
expected_port_info,
const std::vector<std::string>& non_existing_ports_list) {
if (expected_port_info.empty()) {
return gutil::InternalErrorBuilder().LogError()
<< "Expected port info map is empty";
Expand Down
26 changes: 16 additions & 10 deletions tests/thinkit_gnmi_interface_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@

namespace pins_test {

const int kMaxPortLanes = 8;
const int kEthernetLen = 8;
constexpr char kEthernet[] = "Ethernet";
inline constexpr int kMaxPortLanes = 8;
inline constexpr int kEthernetLen = 8;
inline constexpr char kEthernet[] = "Ethernet";

// // PortBreakoutInfo contains physical channels and operational status for an
// // interface.
Expand Down Expand Up @@ -94,7 +94,8 @@ GetExpectedPortInfoForBreakoutMode(const std::string& port,
// breakoutSpeed1 + numBreakouts2 x breakoutSpeed2 + ... Eg: "1x400G", 2x100G +
// 1x200G"
absl::Status GetBreakoutModeConfigFromString(
gnmi::SetRequest& req, const absl::string_view index,
gnmi::SetRequest& req, gnmi::gNMI::StubInterface* sut_gnmi_stub,
const absl::string_view port_index, const absl::string_view intf_name,
const absl::string_view breakout_mode);

// GetNonExistingPortsAfterBreakout returns list of ports that were part of a
Expand All @@ -107,8 +108,8 @@ absl::Status GetBreakoutModeConfigFromString(
// the port, ports in original breakout config that were not in new breakout
// config should no longer exist as new breakout is now applied.
std::vector<std::string> GetNonExistingPortsAfterBreakout(
absl::flat_hash_map<std::string, PortBreakoutInfo>& orig_port_info,
absl::flat_hash_map<std::string, PortBreakoutInfo>& new_port_info,
const absl::flat_hash_map<std::string, PortBreakoutInfo>& orig_port_info,
const absl::flat_hash_map<std::string, PortBreakoutInfo>& new_port_info,
bool expected_success);

// ValidateBreakoutState checks the breakout related state paths with the
Expand All @@ -121,13 +122,18 @@ std::vector<std::string> GetNonExistingPortsAfterBreakout(
// new mode.
absl::Status ValidateBreakoutState(
gnmi::gNMI::StubInterface* sut_gnmi_stub,
absl::flat_hash_map<std::string, PortBreakoutInfo>& expected_port_info,
std::vector<std::string>& non_existing_ports_list);
const absl::flat_hash_map<std::string, PortBreakoutInfo>&
expected_port_info,
const std::vector<std::string>& non_existing_ports_list);

absl::StatusOr<std::string> GetPortIndex(
const std::string& platform_json_contents, absl::string_view port);

std::string ConstructSupportedBreakoutMode(std::string& num_breakouts,
std::string& breakout_speed);
std::string ConstructSupportedBreakoutMode(absl::string_view num_breakouts,
absl::string_view breakout_speed);

// IsCopperPort returns whether the port is copper or optic.
absl::StatusOr<bool> IsCopperPort(gnmi::gNMI::StubInterface* sut_gnmi_stub,
absl::string_view port);
} // namespace pins_test
#endif // PINS_TESTS_THINKIT_GNMI_INTERFACE_UTIL_H_
Loading

0 comments on commit 66f45f1

Please sign in to comment.