Skip to content

Vport gNMI support #324

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

Merged
merged 11 commits into from
Jan 31, 2025
14 changes: 12 additions & 2 deletions stratum/hal/bin/tdi/es2k/es2k_main.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2018-2019 Barefoot Networks, Inc.
// Copyright 2020-present Open Networking Foundation
// Copyright 2022-2024 Intel Corporation
// Copyright 2022-2025 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include <exception>
Expand All @@ -24,6 +24,7 @@
#include "stratum/hal/lib/tdi/es2k/es2k_port_manager.h"
#include "stratum/hal/lib/tdi/es2k/es2k_sde_wrapper.h"
#include "stratum/hal/lib/tdi/es2k/es2k_switch.h"
#include "stratum/hal/lib/tdi/es2k/es2k_virtual_port_manager.h"
#include "stratum/hal/lib/tdi/tdi_action_profile_manager.h"
#include "stratum/hal/lib/tdi/tdi_counter_manager.h"
#include "stratum/hal/lib/tdi/tdi_fixed_function_manager.h"
Expand Down Expand Up @@ -142,7 +143,16 @@ ::util::Status Main(absl::Notification* ready_sync,

auto port_manager = Es2kPortManager::CreateSingleton();

auto chassis_manager = Es2kChassisManager::CreateInstance(mode, port_manager);
auto virtual_port_manager = Es2kVirtualPortManager::CreateSingleton();

auto chassis_manager = Es2kChassisManager::CreateInstance(
mode, port_manager, virtual_port_manager);

// Es2kVirtualPortManager needs reference to SetTdiSdeInterface &
// TdiFixedFunctionManager
virtual_port_manager->SetTdiSdeInterface(sde_wrapper);
virtual_port_manager->SetTdiFixedFunctionManager(
fixed_function_manager.get());

auto ipsec_manager = TdiIpsecManager::CreateInstance(
sde_wrapper, fixed_function_manager.get());
Expand Down
15 changes: 15 additions & 0 deletions stratum/hal/lib/common/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1564,6 +1564,12 @@ message IPsecOffloadInfo {
int32 spi = 1;
}

message VirtualPortInfo {
oneof value {
uint32 vsi = 1;
}
}

// DataRequest is a message used internally to request data about a component
// or a set of components through SwitchInterface. It is specifically used in
// ConfigMonitoringService, as part of gNMI Get/Subscribe RPC implementation.
Expand Down Expand Up @@ -1594,6 +1600,11 @@ message DataRequest {
message IPsecOffloadInfo {
int32 spi = 1;
}
// Defines data required to get vport.
// Req will only contain global_resource_id to index on
message VirtualPort {
uint32 global_resource_id = 1;
}
oneof request {
Port oper_status = 1;
Port admin_status = 2;
Expand All @@ -1618,6 +1629,9 @@ message DataRequest {
Port sdn_port_id = 22;
Port target_dp_id = 23;
IPsecOffloadInfo ipsec_offload_info = 24;
VirtualPort vport_vsi = 25;
VirtualPort vport_oper_status = 26;
VirtualPort vport_mac_address = 27;
}
}
repeated Request requests = 1;
Expand Down Expand Up @@ -1664,6 +1678,7 @@ message DataResponse {
TargetDatapathId target_dp_id = 34;
PacketDirValue packet_dir = 35;
IPsecOffloadInfo ipsec_offload_info = 36;
VirtualPortInfo vport_vsi = 37;
}
}

Expand Down
18 changes: 17 additions & 1 deletion stratum/hal/lib/common/config_monitoring_service.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2018 Google LLC
// Copyright 2018-present Open Networking Foundation
// Copyright 2021-2024 Intel Corporation.
// Copyright 2021-2025 Intel Corporation.
// SPDX-License-Identifier: Apache-2.0

#include "stratum/hal/lib/common/config_monitoring_service.h"
Expand Down Expand Up @@ -373,6 +373,22 @@ ::grpc::Status ConfigMonitoringService::DoGet(::grpc::ServerContext* context,
});
// Check if the path is supported.
::util::Status status;

// In some cases such as vports yang tree nodes, we use a single node leaf
// to process for all vports. Instead of using a SubscriptionHandler and
// calling HandlePoll(), this will use a simple GET and pass the key
// from the yangpath so that the functor can use that data for interacting
// with SDE/TDI layer and access the correct vport info.
std::vector<std::string> keys;
if (gnmi_publisher_.IsPathSupportedVirtualPorts(path, keys)) {
if (!(status = gnmi_publisher_.HandleGet(path, keys, &stream)).ok()) {
return ::grpc::Status(ToGrpcCode(status.CanonicalCode()),
status.error_message());
}
return ::grpc::Status::OK;
}
// else (not vport)...continue with subscribe + handlePoll()

if ((status = gnmi_publisher_.SubscribePoll(path, &stream, &h)).ok()) {
// Get the value(s) represented by the path.
if (!(status = gnmi_publisher_.HandlePoll(h)).ok()) {
Expand Down
4 changes: 4 additions & 0 deletions stratum/hal/lib/common/gnmi_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,10 @@ using GnmiDeleteWithValHandler = std::function<::util::Status(
const ::gnmi::Path& path, const std::vector<std::string>& val,
CopyOnWriteChassisConfig* config)>;

using GnmiGetWithValHandler = std::function<::util::Status(
const ::gnmi::Path& path, const std::vector<std::string>& val,
GnmiSubscribeStream* stream)>;

// A class used to keep information about a subscription.
class EventHandlerRecord {
public:
Expand Down
49 changes: 48 additions & 1 deletion stratum/hal/lib/common/gnmi_publisher.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2018 Google LLC
// Copyright 2018-present Open Networking Foundation
// Copyright 2023-2024 Intel Corporation
// Copyright 2023-2025 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "stratum/hal/lib/common/gnmi_publisher.h"
Expand Down Expand Up @@ -132,6 +132,25 @@ ::util::Status GnmiPublisher::HandleEvent(
return ::util::OkStatus();
}

::util::Status GnmiPublisher::HandleGet(const ::gnmi::Path& path,
const std::vector<std::string>& val,
GnmiSubscribeStream* stream) {
absl::WriterMutexLock l(&access_lock_);

// Map the input path to the supported one - walk the tree of known elements
// element by element starting from the root and if the element is found the
// move to the next one. If not found, return an error.
const TreeNode* node = parse_tree_.FindNodeOrNull(path);
if (node == nullptr) {
// Ooops... This path is not supported.
return MAKE_ERROR(ERR_INVALID_PARAM)
<< "The path (" << path.ShortDebugString() << ") is unsupported!";
}

// Call the GetWithVal handler and pass the keys
return node->GetOnGetWithValHandler()(path, val, stream);
}

::util::Status GnmiPublisher::HandlePoll(const SubscriptionHandle& handle) {
absl::WriterMutexLock l(&access_lock_);

Expand Down Expand Up @@ -377,5 +396,33 @@ bool GnmiPublisher::IsPathSupportedIPsec(const ::gnmi::Path& path,
return true;
}

bool GnmiPublisher::IsPathSupportedVirtualPorts(
const ::gnmi::Path& path, std::vector<std::string>& keys) const {
std::vector<std::string> supported_path;
supported_path.push_back("virtual-ports");
supported_path.push_back("virtual-port");

int element = 0;
std::vector<std::string>::iterator iter;
for (iter = supported_path.begin(); iter != supported_path.end(); ++iter) {
if (path.elem(element).name() != *iter) {
return false;
}

// This block extracts the key from the path
if (element == 1) { // virtual-port
// get the key
auto* search1 =
gtl::FindOrNull(path.elem(element).key(), "global-resource-id");
if (search1 != nullptr) {
keys.push_back(*search1);
}
}

++element;
}
return true;
}

} // namespace hal
} // namespace stratum
25 changes: 22 additions & 3 deletions stratum/hal/lib/common/gnmi_publisher.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2018 Google LLC
// Copyright 2018-present Open Networking Foundation
// Copyright 2023 Intel Corporation
// Copyright 2023,2025 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#ifndef STRATUM_HAL_LIB_COMMON_GNMI_PUBLISHER_H_
Expand Down Expand Up @@ -96,6 +96,14 @@ class GnmiPublisher {
::util::Status HandleChange(const GnmiEvent& event)
LOCKS_EXCLUDED(access_lock_);

// A simple GET routine to process gNMI requests without making a
// subscription and poll handle calls
// The second argument allows the yangpath keys to be passed to the functor
virtual ::util::Status HandleGet(const ::gnmi::Path& path,
const std::vector<std::string>& val,
GnmiSubscribeStream* stream)
LOCKS_EXCLUDED(access_lock_);

virtual ::util::Status HandlePoll(const SubscriptionHandle& handle)
LOCKS_EXCLUDED(access_lock_);

Expand Down Expand Up @@ -144,13 +152,24 @@ class GnmiPublisher {
// stateless and scale is too high to maintain tree nodes in memory -- tens of
// millions of entries). Instead, a single tree node is maintained without any
// keys that services all gnmi SET/DELETE requests. The tree node is
// initialized to to be at /ipsec-offload/sad/sad-entr/config. The contents of
// the message will contain the key, which is subsequently handled at lower
// initialized to to be at /ipsec-offload/sad/sad-entry/config. The contents
// of the message will contain the key, which is subsequently handled at lower
// layers.
virtual bool IsPathSupportedIPsec(const ::gnmi::Path& path,
std::vector<std::string>& keys) const
LOCKS_EXCLUDED(access_lock_);

// virtual-ports is a special use-case, since yang tree nodes are not
// initialized and maintained for each key of yang list.
// Instead, a single tree node (for each leaf node type) is maintained without
// any keys that services all gnmi SET/GET requests. The tree node is
// initialized to to be at /virtual-ports/virtual-port/... The contents of
// the message will contain the key, which is subsequently handled at lower
// layers.
virtual bool IsPathSupportedVirtualPorts(const ::gnmi::Path& path,
std::vector<std::string>& keys) const
LOCKS_EXCLUDED(access_lock_);

private:
// ReaderArgs encapsulates the arguments for a Channel reader thread.
template <typename T>
Expand Down
4 changes: 3 additions & 1 deletion stratum/hal/lib/tdi/es2k/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Build file for //stratum/hal/lib/tdi/es2k
#
# Copyright 2022-2023 Intel Corporation
# Copyright 2022-2023,2025 Intel Corporation
# SPDX-License-Identifier: Apache 2.0
#

Expand All @@ -24,4 +24,6 @@ target_sources(stratum_tdi_target_o PRIVATE
es2k_sde_wrapper.cc
es2k_switch.cc
es2k_switch.h
es2k_virtual_port_manager.cc
es2k_virtual_port_manager.h
)
59 changes: 52 additions & 7 deletions stratum/hal/lib/tdi/es2k/es2k_chassis_manager.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2018-present Barefoot Networks, Inc.
// Copyright 2022-2023 Intel Corporation
// Copyright 2022-2023,2025 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "stratum/hal/lib/tdi/es2k/es2k_chassis_manager.h"
Expand All @@ -20,6 +20,7 @@
#include "stratum/hal/lib/common/utils.h"
#include "stratum/hal/lib/common/writer_interface.h"
#include "stratum/hal/lib/tdi/es2k/es2k_port_manager.h"
#include "stratum/hal/lib/tdi/es2k/es2k_virtual_port_manager.h"
#include "stratum/hal/lib/tdi/tdi_global_vars.h"
#include "stratum/lib/channel/channel.h"
#include "stratum/lib/constants.h"
Expand All @@ -37,8 +38,9 @@ constexpr int Es2kChassisManager::kMaxPortStatusEventDepth;
/* static */
constexpr int Es2kChassisManager::kMaxXcvrEventDepth;

Es2kChassisManager::Es2kChassisManager(OperationMode mode,
Es2kPortManager* es2k_port_manager)
Es2kChassisManager::Es2kChassisManager(
OperationMode mode, Es2kPortManager* es2k_port_manager,
Es2kVirtualPortManager* es2k_virtual_port_manager)
: mode_(mode),
initialized_(false),
port_status_event_channel_(nullptr),
Expand All @@ -52,7 +54,8 @@ Es2kChassisManager::Es2kChassisManager(OperationMode mode,
node_id_to_port_id_to_sdk_port_id_(),
node_id_to_sdk_port_id_to_port_id_(),
xcvr_port_key_to_xcvr_state_(),
es2k_port_manager_(ABSL_DIE_IF_NULL(es2k_port_manager)) {}
es2k_port_manager_(ABSL_DIE_IF_NULL(es2k_port_manager)),
es2k_virtual_port_manager_(ABSL_DIE_IF_NULL(es2k_virtual_port_manager)) {}

Es2kChassisManager::Es2kChassisManager()
: mode_(OPERATION_MODE_STANDALONE),
Expand All @@ -68,7 +71,8 @@ Es2kChassisManager::Es2kChassisManager()
node_id_to_port_id_to_sdk_port_id_(),
node_id_to_sdk_port_id_to_port_id_(),
xcvr_port_key_to_xcvr_state_(),
es2k_port_manager_(nullptr) {}
es2k_port_manager_(nullptr),
es2k_virtual_port_manager_(nullptr) {}

Es2kChassisManager::~Es2kChassisManager() = default;

Expand Down Expand Up @@ -716,6 +720,45 @@ ::util::StatusOr<DataResponse> Es2kChassisManager::GetPortData(
return resp;
}

::util::StatusOr<DataResponse> Es2kChassisManager::GetVirtualPortData(
const DataRequest::Request& request) {
if (!initialized_) {
return MAKE_ERROR(ERR_NOT_INITIALIZED) << "Not initialized!";
}
DataResponse resp;
using Request = DataRequest::Request;
switch (request.request_case()) {
case Request::kVportVsi: {
ASSIGN_OR_RETURN(auto vsi, es2k_virtual_port_manager_->GetVSI(
request.vport_vsi().global_resource_id()));
resp.mutable_vport_vsi()->set_vsi(vsi);
break;
}
case Request::kVportOperStatus: {
ASSIGN_OR_RETURN(auto oper_status,
es2k_virtual_port_manager_->GetPortState(
request.vport_oper_status().global_resource_id()));
resp.mutable_oper_status()->set_state(oper_status);
break;
}
case Request::kVportMacAddress: {
ASSIGN_OR_RETURN(auto mac_address,
es2k_virtual_port_manager_->GetMacAddress(
request.vport_mac_address().global_resource_id()));
resp.mutable_mac_address()->set_mac_address(mac_address);
break;
}
default:
return MAKE_ERROR(ERR_UNIMPLEMENTED)
<< "DataRequest field "
<< request.descriptor()
->FindFieldByNumber(request.request_case())
->name()
<< " is not supported yet!";
}
return resp;
}

::util::StatusOr<PortState> Es2kChassisManager::GetPortState(
uint64 node_id, uint32 port_id) const {
if (!initialized_) {
Expand Down Expand Up @@ -863,8 +906,10 @@ ::util::Status Es2kChassisManager::ReplayChassisConfig(uint64 node_id) {
}

std::unique_ptr<Es2kChassisManager> Es2kChassisManager::CreateInstance(
OperationMode mode, Es2kPortManager* es2k_port_manager) {
return absl::WrapUnique(new Es2kChassisManager(mode, es2k_port_manager));
OperationMode mode, Es2kPortManager* es2k_port_manager,
Es2kVirtualPortManager* es2k_virtual_port_manager) {
return absl::WrapUnique(new Es2kChassisManager(mode, es2k_port_manager,
es2k_virtual_port_manager));
}

void Es2kChassisManager::SendPortOperStateGnmiEvent(
Expand Down
Loading