Skip to content

Commit

Permalink
Move helper functions to utility library & gNMI port interface tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kishanps authored and divyagayathri-hcl committed Dec 10, 2024
1 parent 74fca97 commit 5b20e82
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 115 deletions.
17 changes: 17 additions & 0 deletions tests/qos/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ cc_library(
],
deps = [
":gnmi_parsers",
":qos_test_util",
"//gutil:collections",
"//gutil:overload",
"//gutil:proto",
Expand Down Expand Up @@ -136,3 +137,19 @@ cmd_diff_test(
tools = [":gnmi_parsers_test_runner"],
)

cc_library(
name = "qos_test_util",
srcs = ["qos_test_util.cc"],
hdrs = ["qos_test_util.h"],
deps = [
"//lib/gnmi:gnmi_helper",
"//thinkit:generic_testbed",
"//thinkit/proto:generic_testbed_cc_proto",
"@com_github_gnmi//proto/gnmi:gnmi_cc_proto",
"@com_github_gnmi//proto/gnmi:gnmi_cc_grpc_proto",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
)
116 changes: 1 addition & 115 deletions tests/qos/cpu_qos_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
#include "sai_p4/instantiations/google/sai_pd.pb.h"
#include "tests/forwarding/util.h"
#include "tests/qos/gnmi_parsers.h"
#include "tests/qos/qos_test_util.h"
#include "thinkit/control_device.h"
#include "thinkit/generic_testbed.h"
#include "thinkit/mirror_testbed.h"
Expand Down Expand Up @@ -252,100 +253,6 @@ absl::StatusOr<p4::v1::TableEntry> SetUpPuntToCPUWithRateLimit(
return pi_acl_entry;
}

// These are the counters we track in these tests.
struct QueueCounters {
int64_t num_packets_transmitted = 0;
int64_t num_packet_dropped = 0;
};

std::ostream &operator<<(std::ostream &os, const QueueCounters &counters) {
return os << absl::StreamFormat(
"QueueCounters{"
".num_packets_transmitted = %d, "
".num_packets_dropped = %d"
"}",
counters.num_packets_transmitted, counters.num_packet_dropped);
}

// TODO: Move this to a helper library.
absl::StatusOr<QueueCounters> GetGnmiQueueCounters(
absl::string_view port, absl::string_view queue,
gnmi::gNMI::StubInterface &gnmi_stub) {
QueueCounters counters;
const std::string openconfig_transmit_count_state_path = absl::Substitute(
"qos/interfaces/interface[interface-id=$0]"
"/output/queues/queue[name=$1]/state/transmit-pkts",
port, queue);

ASSIGN_OR_RETURN(
std::string transmit_counter_response,
GetGnmiStatePathInfo(&gnmi_stub, openconfig_transmit_count_state_path,
"openconfig-qos:transmit-pkts"));

if (!absl::SimpleAtoi(StripQuotes(transmit_counter_response),
&counters.num_packets_transmitted)) {
return absl::InternalError(absl::StrCat("Unable to parse counter from ",
transmit_counter_response));
}

const std::string openconfig_drop_count_state_path = absl::Substitute(
"qos/interfaces/interface[interface-id=$0]"
"/output/queues/queue[name=$1]/state/dropped-pkts",
port, queue);

ASSIGN_OR_RETURN(
std::string drop_counter_response,
GetGnmiStatePathInfo(&gnmi_stub, openconfig_drop_count_state_path,
"openconfig-qos:dropped-pkts"));

if (!absl::SimpleAtoi(StripQuotes(drop_counter_response),
&counters.num_packet_dropped)) {
return absl::InternalError(
absl::StrCat("Unable to parse counter from ", drop_counter_response));
}

return counters;
}

// Returns the total number of packets enqueued for the queue with the given
// `QueueCounters`.
int64_t CumulativeNumPacketsEnqueued(const QueueCounters &counters) {
return counters.num_packet_dropped + counters.num_packets_transmitted;
}

absl::Status SetPortSpeed(const std::string &port_speed,
const std::string &iface,
gnmi::gNMI::StubInterface &gnmi_stub) {
std::string ops_config_path = absl::StrCat(
"interfaces/interface[name=", iface, "]/ethernet/config/port-speed");
std::string ops_val =
absl::StrCat("{\"openconfig-if-ethernet:port-speed\":", port_speed, "}");
RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(&gnmi_stub, ops_config_path,
GnmiSetType::kUpdate, ops_val));
return absl::OkStatus();
}

absl::Status SetPortMtu(int port_mtu, const std::string &interface_name,
gnmi::gNMI::StubInterface &gnmi_stub) {
std::string config_path = absl::StrCat(
"interfaces/interface[name=", interface_name, "]/config/mtu");
std::string value = absl::StrCat("{\"config:mtu\":", port_mtu, "}");
RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(&gnmi_stub, config_path,
GnmiSetType::kUpdate, value));
return absl::OkStatus();
}

absl::StatusOr<bool> CheckLinkUp(const std::string &iface,
gnmi::gNMI::StubInterface &gnmi_stub) {
std::string oper_status_state_path =
absl::StrCat("interfaces/interface[name=", iface, "]/state/oper-status");
std::string parse_str = "openconfig-interfaces:oper-status";
ASSIGN_OR_RETURN(
std::string ops_response,
GetGnmiStatePathInfo(&gnmi_stub, oper_status_state_path, parse_str));
return ops_response == "\"UP\"";
}

absl::StatusOr<packetlib::Packet> MakeIpv4PacketWithDscp(
const netaddr::MacAddress &dst_mac, const netaddr::Ipv4Address &dst_ip,
int dscp) {
Expand Down Expand Up @@ -410,27 +317,6 @@ absl::StatusOr<packetlib::Packet> MakeIpv6PacketWithDscp(
return packet;
}

absl::StatusOr<absl::flat_hash_map<int, std::string>>
ParseIpv4DscpToQueueMapping(absl::string_view gnmi_config) {
// TODO: Actually parse config -- hard-coded for now.
absl::flat_hash_map<int, std::string> queue_by_dscp;
for (int dscp = 0; dscp < 64; ++dscp) queue_by_dscp[dscp] = "BE1";
for (int dscp = 8; dscp <= 11; ++dscp) queue_by_dscp[dscp] = "AF1";
queue_by_dscp[13] = "LLQ1";
for (int dscp = 16; dscp <= 19; ++dscp) queue_by_dscp[dscp] = "AF2";
queue_by_dscp[21] = "LLQ2";
for (int dscp = 24; dscp <= 27; ++dscp) queue_by_dscp[dscp] = "AF3";
for (int dscp = 32; dscp <= 35; ++dscp) queue_by_dscp[dscp] = "AF4";
for (int dscp = 48; dscp <= 59; ++dscp) queue_by_dscp[dscp] = "NC1";
return queue_by_dscp;
}

absl::StatusOr<absl::flat_hash_map<int, std::string>>
ParseIpv6DscpToQueueMapping(absl::string_view gnmi_config) {
// TODO: Actually parse config -- hard-coded for now.
return ParseIpv4DscpToQueueMapping(gnmi_config);
}

// Represents a link connecting the switch under test (SUT) to a control device.
struct SutToControlLink {
std::string sut_port_gnmi_name;
Expand Down
143 changes: 143 additions & 0 deletions tests/qos/qos_test_util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#include "tests/qos/qos_test_util.h"

#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "gutil/status.h"
#include "lib/gnmi/gnmi_helper.h"

namespace pins_test {
absl::StatusOr<QueueCounters> GetGnmiQueueCounters(
absl::string_view port, absl::string_view queue,
gnmi::gNMI::StubInterface &gnmi_stub) {
QueueCounters counters;

const std::string openconfig_transmit_count_state_path = absl::Substitute(
"qos/interfaces/interface[interface-id=$0]"
"/output/queues/queue[name=$1]/state/transmit-pkts",
port, queue);

ASSIGN_OR_RETURN(
std::string transmit_counter_response,
GetGnmiStatePathInfo(&gnmi_stub, openconfig_transmit_count_state_path,
"openconfig-qos:transmit-pkts"));

if (!absl::SimpleAtoi(StripQuotes(transmit_counter_response),
&counters.num_packets_transmitted)) {
return absl::InternalError(absl::StrCat("Unable to parse counter from ",
transmit_counter_response));
}

const std::string openconfig_drop_count_state_path = absl::Substitute(
"qos/interfaces/interface[interface-id=$0]"
"/output/queues/queue[name=$1]/state/dropped-pkts",
port, queue);

ASSIGN_OR_RETURN(
std::string drop_counter_response,
GetGnmiStatePathInfo(&gnmi_stub, openconfig_drop_count_state_path,
"openconfig-qos:dropped-pkts"));

if (!absl::SimpleAtoi(StripQuotes(drop_counter_response),
&counters.num_packet_dropped)) {
return absl::InternalError(
absl::StrCat("Unable to parse counter from ", drop_counter_response));
}
return counters;
}

// Returns the total number of packets enqueued for the queue with the given
// `QueueCounters`.
int64_t CumulativeNumPacketsEnqueued(const QueueCounters &counters) {
return counters.num_packet_dropped + counters.num_packets_transmitted;
}

absl::Status SetPortSpeed(const std::string &port_speed,
const std::string &iface,
gnmi::gNMI::StubInterface &gnmi_stub) {
std::string ops_config_path = absl::StrCat(
"interfaces/interface[name=", iface, "]/ethernet/config/port-speed");
std::string ops_val =
absl::StrCat("{\"openconfig-if-ethernet:port-speed\":", port_speed, "}");

RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(&gnmi_stub, ops_config_path,
GnmiSetType::kUpdate, ops_val));

return absl::OkStatus();
}

absl::Status SetPortMtu(int port_mtu, const std::string &interface_name,
gnmi::gNMI::StubInterface &gnmi_stub) {
std::string config_path = absl::StrCat(
"interfaces/interface[name=", interface_name, "]/config/mtu");
std::string value = absl::StrCat("{\"config:mtu\":", port_mtu, "}");

RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(&gnmi_stub, config_path,
GnmiSetType::kUpdate, value));

return absl::OkStatus();
}

absl::StatusOr<bool> CheckLinkUp(const std::string &iface,
gnmi::gNMI::StubInterface &gnmi_stub) {
std::string oper_status_state_path =
absl::StrCat("interfaces/interface[name=", iface, "]/state/oper-status");

std::string parse_str = "openconfig-interfaces:oper-status";
ASSIGN_OR_RETURN(
std::string ops_response,
GetGnmiStatePathInfo(&gnmi_stub, oper_status_state_path, parse_str));

return ops_response == "\"UP\"";
}

// Go over the connections and return vector of connections
// whose links are up.
absl::StatusOr<std::vector<IxiaLink>> GetReadyIxiaLinks(
thinkit::GenericTestbed &generic_testbed,
gnmi::gNMI::StubInterface &gnmi_stub) {
std::vector<IxiaLink> links;

absl::flat_hash_map<std::string, thinkit::InterfaceInfo> interface_info =
generic_testbed.GetSutInterfaceInfo();
// Loop through the interface_info looking for Ixia/SUT interface pairs,
// checking if the link is up. Add the pair to connections.
for (const auto &[interface, info] : interface_info) {
bool sut_link_up = false;
if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR))
{
ASSIGN_OR_RETURN(sut_link_up, CheckLinkUp(interface, gnmi_stub));
if (sut_link_up) {
links.push_back({
.ixia_interface = info.peer_interface_name,
.sut_interface = interface,
});
}
}
}

return links;
}

absl::StatusOr<absl::flat_hash_map<int, std::string>>
ParseIpv4DscpToQueueMapping(absl::string_view gnmi_config) {
// TODO: Actually parse config -- hard-coded for now.
absl::flat_hash_map<int, std::string> queue_by_dscp;
for (int dscp = 0; dscp < 64; ++dscp) queue_by_dscp[dscp] = "BE1";
for (int dscp = 8; dscp <= 11; ++dscp) queue_by_dscp[dscp] = "AF1";
queue_by_dscp[13] = "LLQ1";
for (int dscp = 16; dscp <= 19; ++dscp) queue_by_dscp[dscp] = "AF2";
queue_by_dscp[21] = "LLQ2";
for (int dscp = 24; dscp <= 27; ++dscp) queue_by_dscp[dscp] = "AF3";
for (int dscp = 32; dscp <= 35; ++dscp) queue_by_dscp[dscp] = "AF4";
for (int dscp = 48; dscp <= 59; ++dscp) queue_by_dscp[dscp] = "NC1";
return queue_by_dscp;
}

absl::StatusOr<absl::flat_hash_map<int, std::string>>
ParseIpv6DscpToQueueMapping(absl::string_view gnmi_config) {
// TODO: Actually parse config -- hard-coded for now.
return ParseIpv4DscpToQueueMapping(gnmi_config);
}

} // namespace pins_test
74 changes: 74 additions & 0 deletions tests/qos/qos_test_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#ifndef PINS_TESTS_QOS_QOS_TEST_UTIL_H_
#define PINS_TESTS_QOS_QOS_TEST_UTIL_H_

#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "proto/gnmi/gnmi.grpc.pb.h"
#include "proto/gnmi/gnmi.pb.h"
#include "thinkit/generic_testbed.h"
#include "thinkit/proto/generic_testbed.pb.h"

namespace pins_test {
// These are the counters we track in these tests.
struct QueueCounters {
int64_t num_packets_transmitted = 0;
int64_t num_packet_dropped = 0;
};

// Operator to pretty print Queue Counters.
inline std::ostream &operator<<(std::ostream &os,
const QueueCounters &counters) {
return os << absl::StreamFormat(
"QueueCounters{"
".num_packets_transmitted = %d, "
".num_packets_dropped = %d"
"}",
counters.num_packets_transmitted, counters.num_packet_dropped);
}

// Get queue counters for a port queue.
absl::StatusOr<QueueCounters> GetGnmiQueueCounters(
absl::string_view port, absl::string_view queue,
gnmi::gNMI::StubInterface &gnmi_stub);

// Get total packets (transmitted + dropped) for port queue.
int64_t CumulativeNumPacketsEnqueued(const QueueCounters &counters);

// Set port speed using gNMI.
absl::Status SetPortSpeed(const std::string &port_speed,
const std::string &iface,
gnmi::gNMI::StubInterface &gnmi_stub);

// Set port MTU using gNMI.
absl::Status SetPortMtu(int port_mtu, const std::string &interface_name,
gnmi::gNMI::StubInterface &gnmi_stub);

// Check if switch port link is up.
absl::StatusOr<bool> CheckLinkUp(const std::string &iface,
gnmi::gNMI::StubInterface &gnmi_stub);

// Structure represents a link between SUT and Ixia.
// This is represented by Ixia interface name and the SUT's gNMI interface
// name.
struct IxiaLink {
std::string ixia_interface;
std::string sut_interface;
};

// Go over the connections and return vector of connections
// whose links are up.
absl::StatusOr<std::vector<IxiaLink>> GetReadyIxiaLinks(
thinkit::GenericTestbed &generic_testbed,
gnmi::gNMI::StubInterface &gnmi_stub);

// Parse IPv4 DSCP to queue mapping from gnmi configuration.
absl::StatusOr<absl::flat_hash_map<int, std::string>>
ParseIpv4DscpToQueueMapping(absl::string_view gnmi_config);

// Parse IPv6 DSCP to queue mapping from gnmi configuration.
absl::StatusOr<absl::flat_hash_map<int, std::string>>
ParseIpv6DscpToQueueMapping(absl::string_view gnmi_config);

} // namespace pins_test

#endif // PINS_TESTS_QOS_QOS_TEST_UTIL_H_
2 changes: 2 additions & 0 deletions tests/thinkit_gnmi_interface_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ void BreakoutDuringPortInUse(thinkit::Switch& sut,
GetBreakoutStateInfoForPort(sut_gnmi_stub, port_info.port_name,
port_info.curr_breakout_mode));

LOG(INFO) << "Using port " << port_info.port_name
<< " with current breakout mode " << port_info.curr_breakout_mode;
// Verify that all ports for the selected port are operationally up.
auto resp_parse_str = "openconfig-interfaces:oper-status";
for (const auto& p : orig_breakout_info) {
Expand Down

0 comments on commit 5b20e82

Please sign in to comment.