diff --git a/lib/gnmi/BUILD.bazel b/lib/gnmi/BUILD.bazel index 9cc4cd0a..a8824a7b 100644 --- a/lib/gnmi/BUILD.bazel +++ b/lib/gnmi/BUILD.bazel @@ -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", ], diff --git a/lib/gnmi/gnmi_helper.cc b/lib/gnmi/gnmi_helper.cc index a8ced728..c796b50d 100644 --- a/lib/gnmi/gnmi_helper.cc +++ b/lib/gnmi/gnmi_helper.cc @@ -19,13 +19,13 @@ #include #include #include +#include #include #include #include #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" @@ -925,6 +925,18 @@ absl::StatusOr GetInterfacesAsProto( return config.interfaces(); } +absl::StatusOr 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 GetMatchingInterfacesAsProto( gnmi::gNMI::StubInterface& stub, gnmi::GetRequest::DataType type, std::function predicate, @@ -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({ + {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(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 GetPortSpeedInBitsPerSecond( const std::string& interface_name, gnmi::gNMI::StubInterface& gnmi_stub) { // Map keyed on openconfig speed string to value in bits per second. @@ -1653,65 +1695,6 @@ absl::StatusOr CheckLinkUp(const std::string& interface_name, return ops_response == "\"UP\""; } -absl::StatusOr AppendSflowConfigIfNotPresent( - absl::string_view gnmi_config, absl::string_view agent_addr_ipv6, - const absl::flat_hash_map& collector_address_to_port, - const absl::flat_hash_set& 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 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 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> GetAllInterfaceCounters(gnmi::gNMI::StubInterface& gnmi_stub) { ASSIGN_OR_RETURN( diff --git a/lib/gnmi/gnmi_helper.h b/lib/gnmi/gnmi_helper.h index b22ca6e4..6d431100 100644 --- a/lib/gnmi/gnmi_helper.h +++ b/lib/gnmi/gnmi_helper.h @@ -270,6 +270,9 @@ absl::StatusOr GetInterfacesAsProto( gnmi::gNMI::StubInterface& stub, gnmi::GetRequest::DataType type, absl::Duration timeout = absl::Seconds(60)); +// Gets gNMIConfig for the entire switch. +absl::StatusOr GetGnmiConfig(gnmi::gNMI::StubInterface& gnmi_stub); + // Gets interfaces satisfying `predicate` from the switch and returns them as a // proto. absl::StatusOr GetMatchingInterfacesAsProto( @@ -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 GetPortSpeedInBitsPerSecond( const std::string& interface_name, gnmi::gNMI::StubInterface& gnmi_stub); @@ -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 AppendSflowConfigIfNotPresent( - absl::string_view gnmi_config, absl::string_view agent_addr_ipv6, - const absl::flat_hash_map& collector_address_to_port, - const absl::flat_hash_set& sflow_enabled_interfaces, - const int sampling_rate, const int sampling_header_size); - // Gets counters for all interfaces. absl::StatusOr> GetAllInterfaceCounters(gnmi::gNMI::StubInterface& gnmi_stub); diff --git a/lib/gnmi/gnmi_helper_test.cc b/lib/gnmi/gnmi_helper_test.cc index ea651dd8..04ae7ddc 100644 --- a/lib/gnmi/gnmi_helper_test.cc +++ b/lib/gnmi/gnmi_helper_test.cc @@ -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"( { diff --git a/p4rt_app/tests/BUILD.bazel b/p4rt_app/tests/BUILD.bazel index 4c0481e7..481e7f60 100644 --- a/p4rt_app/tests/BUILD.bazel +++ b/p4rt_app/tests/BUILD.bazel @@ -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", ], )