Skip to content

Commit

Permalink
[Comb] Change hash map to vector of pair to increase readability. (so…
Browse files Browse the repository at this point in the history
…nic-net#445)


Co-authored-by: kishanps <kishanps@google.com>
  • Loading branch information
divyagayathri-hcl and kishanps authored Aug 8, 2024
1 parent 7504393 commit ee6d070
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 238 deletions.
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

0 comments on commit ee6d070

Please sign in to comment.