Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Comb] Change hash map to vector of pair to increase readability. #445

Merged
merged 4 commits into from
Aug 8, 2024
Merged
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: 0 additions & 1 deletion lib/gnmi/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ cc_library(
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:span",
"@com_google_protobuf//:protobuf",
"@com_google_protobuf//:protobuf_lite",
"@com_googlesource_code_re2//:re2",
"@com_jsoncpp//:json",
],
Expand Down
103 changes: 43 additions & 60 deletions lib/gnmi/gnmi_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
#include <memory>
#include <optional>
#include <ostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include "absl/algorithm/container.h"
#include "absl/base/log_severity.h"
#include "absl/container/btree_map.h"
#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
Expand Down Expand Up @@ -925,6 +925,18 @@ absl::StatusOr<openconfig::Interfaces> GetInterfacesAsProto(
return config.interfaces();
}

absl::StatusOr<std::string> GetGnmiConfig(
gnmi::gNMI::StubInterface& gnmi_stub) {
ASSIGN_OR_RETURN(
gnmi::GetRequest request,
pins_test::BuildGnmiGetRequest(/*oc_path=*/"", gnmi::GetRequest::CONFIG));
gnmi::GetResponse response;
grpc::ClientContext context;
RETURN_IF_ERROR(gutil::GrpcStatusToAbslStatus(
gnmi_stub.Get(&context, request, &response)));
return json_yang::FormatJsonBestEffort(response.DebugString());
}

absl::StatusOr<openconfig::Interfaces> GetMatchingInterfacesAsProto(
gnmi::gNMI::StubInterface& stub, gnmi::GetRequest::DataType type,
std::function<bool(const openconfig::Interfaces::Interface&)> predicate,
Expand Down Expand Up @@ -1602,6 +1614,36 @@ absl::Status SetPortSpeedInBitsPerSecond(const std::string& port_speed,
return absl::OkStatus();
}

absl::Status SetPortSpeedInBitsPerSecond(PortSpeed port_speed,
const std::string& interface_name,
gnmi::gNMI::StubInterface& gnmi_stub) {
// Map keyed on openconfig speed string to value in bits per second.
// http://ops.openconfig.net/branches/models/master/docs/openconfig-interfaces.html#mod-openconfig-if-ethernet
const auto kPortSpeedTable =
absl::flat_hash_map<uint64_t, absl::string_view>({
{100000000000, "openconfig-if-ethernet:SPEED_100GB"},
{200000000000, "openconfig-if-ethernet:SPEED_200GB"},
{400000000000, "openconfig-if-ethernet:SPEED_400GB"},
});

auto oc_speed = kPortSpeedTable.find(static_cast<int64_t>(port_speed));
if (oc_speed == kPortSpeedTable.end()) {
return absl::InvalidArgumentError(
absl::StrCat("Port speed ", port_speed, " not found"));
}

std::string ops_val = absl::StrCat(
"{\"openconfig-if-ethernet:port-speed\": \"", oc_speed->second, "\"}");

std::string ops_config_path =
absl::StrCat("interfaces/interface[name=", interface_name,
"]/ethernet/config/port-speed");
RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(&gnmi_stub, ops_config_path,
GnmiSetType::kUpdate, ops_val));

return absl::OkStatus();
}

absl::StatusOr<int64_t> GetPortSpeedInBitsPerSecond(
const std::string& interface_name, gnmi::gNMI::StubInterface& gnmi_stub) {
// Map keyed on openconfig speed string to value in bits per second.
Expand Down Expand Up @@ -1653,65 +1695,6 @@ absl::StatusOr<bool> CheckLinkUp(const std::string& interface_name,
return ops_response == "\"UP\"";
}

absl::StatusOr<std::string> AppendSflowConfigIfNotPresent(
absl::string_view gnmi_config, absl::string_view agent_addr_ipv6,
const absl::flat_hash_map<std::string, int>& collector_address_to_port,
const absl::flat_hash_set<std::string>& sflow_enabled_interfaces,
const int sampling_rate, const int sampling_header_size) {
ASSIGN_OR_RETURN(auto gnmi_config_json, json_yang::ParseJson(gnmi_config));
if (gnmi_config_json.find("openconfig-sampling:sampling") !=
gnmi_config_json.end()) {
return std::string(gnmi_config);
}
if (agent_addr_ipv6.empty()) {
return absl::FailedPreconditionError(
"loopback_address parameter cannot be empty.");
}
if (sflow_enabled_interfaces.empty()) {
return absl::FailedPreconditionError(
"sflow_enabled_interfaces parameter cannot be empty.");
}
gnmi_config_json["openconfig-sampling:sampling"]
["openconfig-sampling-sflow:sflow"]["config"]["enabled"] =
true;
gnmi_config_json["openconfig-sampling:sampling"]
["openconfig-sampling-sflow:sflow"]["config"]["sample-size"] =
sampling_header_size;
gnmi_config_json["openconfig-sampling:sampling"]
["openconfig-sampling-sflow:sflow"]["config"]
["polling-interval"] = 0;
gnmi_config_json["openconfig-sampling:sampling"]
["openconfig-sampling-sflow:sflow"]["config"]
["agent-id-ipv6"] = agent_addr_ipv6;
absl::btree_map<std::string, int> sorted_collector_addresses(
collector_address_to_port.begin(), collector_address_to_port.end());
for (const auto& [address, port] : sorted_collector_addresses) {
nlohmann::basic_json<> sflow_collector_config;
sflow_collector_config["address"] = address;
sflow_collector_config["port"] = port;
sflow_collector_config["config"]["address"] = address;
sflow_collector_config["config"]["port"] = port;
gnmi_config_json["openconfig-sampling:sampling"]
["openconfig-sampling-sflow:sflow"]["collectors"]
["collector"]
.push_back(sflow_collector_config);
}
absl::btree_set<std::string> sorted_interface_names(
sflow_enabled_interfaces.begin(), sflow_enabled_interfaces.end());
for (const auto& interface_name : sorted_interface_names) {
nlohmann::basic_json<> sflow_interface_config;
sflow_interface_config["name"] = interface_name;
sflow_interface_config["config"]["name"] = interface_name;
sflow_interface_config["config"]["enabled"] = true;
sflow_interface_config["config"]["ingress-sampling-rate"] = sampling_rate;
gnmi_config_json["openconfig-sampling:sampling"]
["openconfig-sampling-sflow:sflow"]["interfaces"]
["interface"]
.push_back(sflow_interface_config);
}
return gnmi_config_json.dump();
}

absl::StatusOr<absl::flat_hash_map<std::string, Counters>>
GetAllInterfaceCounters(gnmi::gNMI::StubInterface& gnmi_stub) {
ASSIGN_OR_RETURN(
Expand Down
28 changes: 17 additions & 11 deletions lib/gnmi/gnmi_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ absl::StatusOr<openconfig::Interfaces> GetInterfacesAsProto(
gnmi::gNMI::StubInterface& stub, gnmi::GetRequest::DataType type,
absl::Duration timeout = absl::Seconds(60));

// Gets gNMIConfig for the entire switch.
absl::StatusOr<std::string> GetGnmiConfig(gnmi::gNMI::StubInterface& gnmi_stub);

// Gets interfaces satisfying `predicate` from the switch and returns them as a
// proto.
absl::StatusOr<openconfig::Interfaces> GetMatchingInterfacesAsProto(
Expand Down Expand Up @@ -408,6 +411,20 @@ absl::Status SetPortSpeedInBitsPerSecond(const std::string& port_speed,
const std::string& interface_name,
gnmi::gNMI::StubInterface& gnmi_stub);

enum class PortSpeed : int64_t {
kSpeed100G = 100000000000,
kSpeed200G = 200000000000,
kSpeed400G = 400000000000
};

// Set port speed using gNMI.
// Currently following speed sets are supported:
// 100 Gbps, 200 Gbps, 400 Gbps.
// Function will return InvalidArgumentError for other speeds.
absl::Status SetPortSpeedInBitsPerSecond(PortSpeed port_speed,
const std::string& interface_name,
gnmi::gNMI::StubInterface& gnmi_stub);

// Get configured port speed.
absl::StatusOr<int64_t> GetPortSpeedInBitsPerSecond(
const std::string& interface_name, gnmi::gNMI::StubInterface& gnmi_stub);
Expand All @@ -421,17 +438,6 @@ absl::Status SetPortLoopbackMode(bool port_loopback,
absl::string_view interface_name,
gnmi::gNMI::StubInterface& gnmi_stub);

// Appends sFlow config to `gnmi_config` and returns modified config if success.
// The modified config would sort collector IPs and interface names by string
// order. This function would return original `gnmi_config` if sFlow config is
// already present in `gnmi_config`. Returns an FailedPreconditionError if
// `agent_addr_ipv6` or `sflow_enabled_interfaces` is empty.
absl::StatusOr<std::string> AppendSflowConfigIfNotPresent(
absl::string_view gnmi_config, absl::string_view agent_addr_ipv6,
const absl::flat_hash_map<std::string, int>& collector_address_to_port,
const absl::flat_hash_set<std::string>& sflow_enabled_interfaces,
const int sampling_rate, const int sampling_header_size);

// Gets counters for all interfaces.
absl::StatusOr<absl::flat_hash_map<std::string, Counters>>
GetAllInterfaceCounters(gnmi::gNMI::StubInterface& gnmi_stub);
Expand Down
166 changes: 0 additions & 166 deletions lib/gnmi/gnmi_helper_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2276,172 +2276,6 @@ TEST(BreakoutModeMatchTest, LocalFileTestDataTest) {
IsOkAndHolds(10));
}

TEST(SflowconfigTest, AppendSflowConfigSuccess) {
const std::string kOpenConfig = R"({
"openconfig-interfaces:interfaces":{
"interface":[
{
"name":"bond0",
"state":{"oper-status":"UP","openconfig-p4rt:id":1}
}
]
}
})";
const std::string kSflowConfig = R"({
"openconfig-interfaces:interfaces":{
"interface":[
{
"name":"bond0",
"state":{"oper-status":"UP","openconfig-p4rt:id":1}
}
]
},
"openconfig-sampling:sampling" : {
"openconfig-sampling-sflow:sflow" : {
"collectors" : {
"collector" : [
{
"address" : "2001:4860:f802::be",
"config" : {
"address" : "2001:4860:f802::be",
"port" : 6343
},
"port" : 6343
}
]
},
"config" : {
"agent-id-ipv6" : "8002:12::aab0",
"enabled" : true,
"polling-interval" : 0,
"sample-size" : 128
},
"interfaces" : {
"interface" : [
{
"config" : {
"enabled" : true,
"name" : "Ethernet1",
"ingress-sampling-rate" : 1000
},
"name" : "Ethernet1"
},
{
"config" : {
"enabled" : true,
"name" : "Ethernet2",
"ingress-sampling-rate" : 1000
},
"name" : "Ethernet2"
}
]
}
}
}
})";
ASSERT_OK_AND_ASSIGN(
auto json_str,
AppendSflowConfigIfNotPresent(
kOpenConfig,
/*agent_addr_ipv6=*/"8002:12::aab0",
/*collector_address_to_port=*/{{"2001:4860:f802::be", 6343}},
/*sflow_enabled_interfaces=*/{"Ethernet1", "Ethernet2"},
/*sampling_rate=*/1000,
/*sampling_header_size=*/128));
ASSERT_EQ(::nlohmann::json::parse(json_str),
::nlohmann::json::parse(kSflowConfig));
}

TEST(SflowconfigTest, AppendSflowConfigNoopIfPresent) {
const std::string kGnmiConfig = R"({
"openconfig-interfaces:interfaces":{
"interface":[
{
"name":"bond0",
"state":{"oper-status":"UP","openconfig-p4rt:id":1}
}
]
},
"openconfig-sampling:sampling" : {
"openconfig-sampling-sflow:sflow" : {
"collectors" : {
"collector" : [
{
"address" : "2001:4860:f802::be",
"config" : {
"address" : "2001:4860:f802::be",
"port" : 6343
},
"port" : 6343
}
]
},
"config" : {
"agent-id-ipv6" : "8002:12::aab0",
"enabled" : true,
"polling-interval" : 0,
"sample-size" : 128
},
"interfaces" : {
"interface" : [
{
"config" : {
"enabled" : true,
"name" : "Ethernet1",
"ingress-sampling-rate" : 1000
},
"name" : "Ethernet1"
},
{
"config" : {
"enabled" : true,
"name" : "Ethernet2",
"ingress-sampling-rate" : 1000
},
"name" : "Ethernet2"
}
]
}
}
}
})";
ASSERT_OK_AND_ASSIGN(
auto json_str,
AppendSflowConfigIfNotPresent(
kGnmiConfig,
/*agent_addr_ipv6=*/"8002:12::aab0",
/*collector_address_to_port=*/{{"12:34:56::78", 6343}},
/*sflow_enabled_interfaces=*/{"Ethernet3", "Ethernet4"},
/*sampling_rate=*/100,
/*sampling_header_size=*/12));
ASSERT_EQ(::nlohmann::json::parse(json_str),
::nlohmann::json::parse(kGnmiConfig));
}

TEST(SflowconfigTest, AppendSflowConfigWrongParameterFail) {
EXPECT_THAT(
AppendSflowConfigIfNotPresent(
/*gnmi_config=*/"",
/*agent_addr_ipv6=*/"",
/*collector_address_to_port=*/{{"2001:4860:f802::be", 6343}},
/*sflow_enabled_interfaces=*/{"Ethernet1", "Ethernet2"},
/*sampling_rate=*/1000,
/*sampling_header_size=*/128),
StatusIs(absl::StatusCode::kFailedPrecondition,
HasSubstr("loopback_address parameter cannot be empty.")));
EXPECT_THAT(
AppendSflowConfigIfNotPresent(
/*gnmi_config=*/"",
/*agent_addr_ipv6=*/"8002:12::aab0",
/*collector_address_to_port=*/{{"2001:4860:f802::be", 6343}},
/*sflow_enabled_interfaces=*/{},
/*sampling_rate=*/1000,
/*sampling_header_size=*/128),
StatusIs(
absl::StatusCode::kFailedPrecondition,
HasSubstr("sflow_enabled_interfaces parameter cannot be empty.")));
}

TEST(GetAllInterfaceCounters, Works) {
static constexpr absl::string_view kInterfaceJson = R"(
{
Expand Down
1 change: 1 addition & 0 deletions p4rt_app/tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ cc_test(
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
"@com_google_protobuf//:protobuf",
"@sonic_swss_common//:common",
],
)
Expand Down
Loading