From e3ba0562500c31e85f35bf1188214ef108e750f2 Mon Sep 17 00:00:00 2001 From: Derek G Foster Date: Tue, 10 Dec 2024 15:33:34 -0800 Subject: [PATCH] [ovsp4rt] Implement Client class (#713) - Implemented the `Client` `ClientInterface`, and `ClientMock` classes, to abstract the interface to the P4Runtime server. Signed-off-by: Derek Foster --- ovs-p4rt/sidecar/CMakeLists.txt | 20 +++-- ovs-p4rt/sidecar/client/CMakeLists.txt | 36 +++++++++ ovs-p4rt/sidecar/client/ovsp4rt_client.cc | 66 ++++++++++++++++ ovs-p4rt/sidecar/client/ovsp4rt_client.h | 77 +++++++++++++++++++ .../sidecar/client/ovsp4rt_client_interface.h | 67 ++++++++++++++++ ovs-p4rt/sidecar/client/ovsp4rt_client_mock.h | 43 +++++++++++ 6 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 ovs-p4rt/sidecar/client/CMakeLists.txt create mode 100644 ovs-p4rt/sidecar/client/ovsp4rt_client.cc create mode 100644 ovs-p4rt/sidecar/client/ovsp4rt_client.h create mode 100644 ovs-p4rt/sidecar/client/ovsp4rt_client_interface.h create mode 100644 ovs-p4rt/sidecar/client/ovsp4rt_client_mock.h diff --git a/ovs-p4rt/sidecar/CMakeLists.txt b/ovs-p4rt/sidecar/CMakeLists.txt index 36caf150..4a3c21a5 100644 --- a/ovs-p4rt/sidecar/CMakeLists.txt +++ b/ovs-p4rt/sidecar/CMakeLists.txt @@ -4,8 +4,11 @@ # SPDX-License-Identifier: Apache 2.0 # +option(BUILD_CLIENT "Build ovs-p4rt with Client class" OFF) option(BUILD_JOURNAL "Build ovs-p4rt with Journal class" OFF) -option(BUILD_SPIES "Build ovs-p4rt with spies" OFF) +option(BUILD_SPIES "Build ovs-p4rt spies library" OFF) + +mark_as_advanced(BUILD_CLIENT) mark_as_advanced(BUILD_JOURNAL) mark_as_advanced(BUILD_SPIES) @@ -113,16 +116,23 @@ else() add_library(ovsp4rt_test ALIAS ovsp4rt) endif() +#----------------------------------------------------------------------- +# libovsp4rt_spies.a +#----------------------------------------------------------------------- +if(BUILD_SPIES) + add_subdirectory(spies) +endif() + #----------------------------------------------------------------------- # libovsp4rt_stubs.a #----------------------------------------------------------------------- add_subdirectory(stubs) #----------------------------------------------------------------------- -# libovsp4rt_spies.a +# libovsp4rt_client_o #----------------------------------------------------------------------- -if(BUILD_SPIES) - add_subdirectory(spies) +if(BUILD_CLIENT) + add_subdirectory(client) endif() #----------------------------------------------------------------------- @@ -168,5 +178,5 @@ if(BUILD_TESTING) endif() add_custom_target(ovsp4rt-unit-tests - DEPENDS ${UNIT_TEST_NAMES} + DEPENDS ${UNIT_TEST_NAMES} ) diff --git a/ovs-p4rt/sidecar/client/CMakeLists.txt b/ovs-p4rt/sidecar/client/CMakeLists.txt new file mode 100644 index 00000000..5b23bc7a --- /dev/null +++ b/ovs-p4rt/sidecar/client/CMakeLists.txt @@ -0,0 +1,36 @@ +# CMake build file for ovs-p4rt/sidecar/client +# +# Copyright 2024 Intel Corporation +# SPDX-License-Identifier: Apache 2.0 +# + +#----------------------------------------------------------------------- +# ovsp4rt_client_o +#----------------------------------------------------------------------- +add_library(ovsp4rt_client_o OBJECT + ovsp4rt_client.cc + ovsp4rt_client.h + ovsp4rt_client_interface.h +) + +target_include_directories(ovsp4rt_client_o PUBLIC + ${SIDECAR_SOURCE_DIR} +) + +#----------------------------------------------------------------------- +# libovsp4rt_client.a +#----------------------------------------------------------------------- +add_library(ovsp4rt_client STATIC + $ +) + +#----------------------------------------------------------------------- +# ovsp4rt_client_so +#----------------------------------------------------------------------- +add_library(ovsp4rt_client_so SHARED EXCLUDE_FROM_ALL + $ +) + +set_target_properties(ovsp4rt_client_so PROPERTIES + OUTPUT_NAME ovsp4rt_client +) diff --git a/ovs-p4rt/sidecar/client/ovsp4rt_client.cc b/ovs-p4rt/sidecar/client/ovsp4rt_client.cc new file mode 100644 index 00000000..ca560e74 --- /dev/null +++ b/ovs-p4rt/sidecar/client/ovsp4rt_client.cc @@ -0,0 +1,66 @@ +// Copyright 2022-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "ovsp4rt_client.h" + +#include "absl/flags/flag.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "session/ovsp4rt_credentials.h" +#include "session/ovsp4rt_session.h" + +#define DEFAULT_ROLE_NAME "ovs-p4rt" + +ABSL_FLAG(uint64_t, device_id, 1, "P4Runtime device ID."); + +ABSL_FLAG(std::string, role_name, DEFAULT_ROLE_NAME, "P4 config role name."); + +namespace ovsp4rt { + +absl::Status Client::connect(const char* grpc_addr) { + // Start a new client session. + auto result = ovsp4rt::OvsP4rtSession::Create( + grpc_addr, GenerateClientCredentials(), absl::GetFlag(FLAGS_device_id), + absl::GetFlag(FLAGS_role_name)); + if (!result.ok()) { + return result.status(); + } + + // Unwrap the session from the StatusOr object. + session_ = std::move(result).value(); + return absl::OkStatus(); +} + +absl::Status Client::getPipelineConfig(::p4::config::v1::P4Info* p4info) { + return GetForwardingPipelineConfig(session_.get(), p4info); +} + +::p4::v1::TableEntry* Client::initReadRequest(::p4::v1::ReadRequest* request) { + return SetupTableEntryToRead(session_.get(), request); +} + +absl::StatusOr<::p4::v1::ReadResponse> Client::sendReadRequest( + const p4::v1::ReadRequest& request) { + return SendReadRequest(session_.get(), request); +} + +::p4::v1::TableEntry* Client::initInsertRequest( + ::p4::v1::WriteRequest* request) { + return SetupTableEntryToInsert(session_.get(), request); +} + +::p4::v1::TableEntry* Client::initModifyRequest( + ::p4::v1::WriteRequest* request) { + return SetupTableEntryToModify(session_.get(), request); +} + +::p4::v1::TableEntry* Client::initDeleteRequest( + ::p4::v1::WriteRequest* request) { + return SetupTableEntryToDelete(session_.get(), request); +} + +absl::Status Client::sendWriteRequest(const p4::v1::WriteRequest& request) { + return SendWriteRequest(session_.get(), request); +} + +} // namespace ovsp4rt diff --git a/ovs-p4rt/sidecar/client/ovsp4rt_client.h b/ovs-p4rt/sidecar/client/ovsp4rt_client.h new file mode 100644 index 00000000..f5e390b1 --- /dev/null +++ b/ovs-p4rt/sidecar/client/ovsp4rt_client.h @@ -0,0 +1,77 @@ +// Copyright 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OVSP4RT_CLIENT_H_ +#define OVSP4RT_CLIENT_H_ + +#include + +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "ovsp4rt_client_interface.h" +#include "p4/v1/p4runtime.pb.h" +#include "session/ovsp4rt_session.h" + +namespace ovsp4rt { + +class Client : public ClientInterface { + public: + Client() {} + virtual ~Client() = default; + + // Connects to the P4Runtime server. + virtual absl::Status connect(const char* grpc_addr); + + // Returns a pointer to the ovsp4rt session object. + virtual OvsP4rtSession* session() const { return session_.get(); } + + // Gets the pipeline configuration from the P4Runtime server. + virtual absl::Status getPipelineConfig(::p4::config::v1::P4Info* p4info); + + //-------------------------------------------------------------------- + + // Initializes a Read Table Entry request message. + virtual ::p4::v1::TableEntry* initReadRequest(::p4::v1::ReadRequest* request); + + // Sends a Read Table Entry request to the P4Runtime server. + virtual absl::StatusOr sendReadRequest( + const p4::v1::ReadRequest& request); + + //-------------------------------------------------------------------- + + // Initializes an Insert Table Entry request message. + virtual ::p4::v1::TableEntry* initInsertRequest( + ::p4::v1::WriteRequest* request); + + // Initializes a Modify Table Entry request message. + virtual ::p4::v1::TableEntry* initModifyRequest( + ::p4::v1::WriteRequest* request); + + // Initializes a Delete Table Entry request message. + virtual ::p4::v1::TableEntry* initDeleteRequest( + ::p4::v1::WriteRequest* request); + + // Initializes an Insert Table Entry or Delete Table Entry request + // message, depending on the value of the `insert_entry` parameter. + virtual ::p4::v1::TableEntry* initWriteRequest( + ::p4::v1::WriteRequest* request, bool insert_entry) { + if (insert_entry) { + return initInsertRequest(request); + } else { + return initDeleteRequest(request); + } + } + + // Sends a Write Table Entry request to the P4Runtime server. + virtual absl::Status sendWriteRequest(const p4::v1::WriteRequest& request); + + private: + // Pointer to a P4Runtime session object. + std::unique_ptr session_; +}; + +} // namespace ovsp4rt + +#endif // OVSP4RT_CLIENT_H_ diff --git a/ovs-p4rt/sidecar/client/ovsp4rt_client_interface.h b/ovs-p4rt/sidecar/client/ovsp4rt_client_interface.h new file mode 100644 index 00000000..f7c41aeb --- /dev/null +++ b/ovs-p4rt/sidecar/client/ovsp4rt_client_interface.h @@ -0,0 +1,67 @@ +// Copyright 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OVSP4RT_CLIENT_INTERFACE_H_ +#define OVSP4RT_CLIENT_INTERFACE_H_ + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "p4/v1/p4runtime.pb.h" +#include "session/ovsp4rt_session.h" + +namespace ovsp4rt { + +class ClientInterface { + public: + virtual ~ClientInterface() = default; + + // Connects to the P4Runtime server. + virtual absl::Status connect(const char* grpc_addr) = 0; + + // Returns a pointer to the ovsp4rt session object. + virtual OvsP4rtSession* session() const = 0; + + // Gets the pipeline configuration from the P4Runtime server. + virtual absl::Status getPipelineConfig(::p4::config::v1::P4Info* p4info) = 0; + + //-------------------------------------------------------------------- + + // Initializes a Read Table Entry request message. + virtual ::p4::v1::TableEntry* initReadRequest( + ::p4::v1::ReadRequest* request) = 0; + + // Sends a Read Table Entry request to the P4Runtime server. + virtual absl::StatusOr sendReadRequest( + const p4::v1::ReadRequest& request) = 0; + + //-------------------------------------------------------------------- + + // Initializes an Insert Table Entry request message. + virtual ::p4::v1::TableEntry* initInsertRequest( + ::p4::v1::WriteRequest* request) = 0; + + // Initializes a Modify Table Entry request message. + virtual ::p4::v1::TableEntry* initModifyRequest( + ::p4::v1::WriteRequest* request) = 0; + + // Initializes a Delete Table Entry request message. + virtual ::p4::v1::TableEntry* initDeleteRequest( + ::p4::v1::WriteRequest* request) = 0; + + // Initializes an Insert Table Entry or Delete Table Entry request + // message, depending on the value of the `insert_entry` parameter. + virtual ::p4::v1::TableEntry* initWriteRequest( + ::p4::v1::WriteRequest* request, bool insert_entry) = 0; + + // Sends a Write Table Entry request to the P4Runtime server. + virtual absl::Status sendWriteRequest( + const p4::v1::WriteRequest& request) = 0; + + protected: + // Default constructor. To be called by the Mock class instance only. + ClientInterface() {} +}; + +} // namespace ovsp4rt + +#endif // OVSP4RT_CLIENT_INTERFACE_H_ diff --git a/ovs-p4rt/sidecar/client/ovsp4rt_client_mock.h b/ovs-p4rt/sidecar/client/ovsp4rt_client_mock.h new file mode 100644 index 00000000..094c299c --- /dev/null +++ b/ovs-p4rt/sidecar/client/ovsp4rt_client_mock.h @@ -0,0 +1,43 @@ +// Copyright 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OVSP4RT_CLIENT_MOCK_H_ +#define OVSP4RT_CLIENT_MOCK_H_ + +#include "gmock/gmock.h" +#include "ovsp4rt_client_interface.h" + +namespace ovsp4rt { + +class ClientMock : public ClientInterface { + public: + MOCK_METHOD(absl::Status, connect, (const char*)); + + MOCK_METHOD(OvsP4rtSession*, session, (), (const)); + + MOCK_METHOD(absl::Status, getPipelineConfig, (::p4::config::v1::P4Info*)); + + MOCK_METHOD(::p4::v1::TableEntry*, initReadRequest, (::p4::v1::ReadRequest*)); + + MOCK_METHOD(absl::StatusOr, sendReadRequest, + (const p4::v1::ReadRequest&)); + + MOCK_METHOD(::p4::v1::TableEntry*, initInsertRequest, + (::p4::v1::WriteRequest*)); + + MOCK_METHOD(::p4::v1::TableEntry*, initModifyRequest, + (::p4::v1::WriteRequest*)); + + MOCK_METHOD(::p4::v1::TableEntry*, initDeleteRequest, + (::p4::v1::WriteRequest*)); + + MOCK_METHOD(::p4::v1::TableEntry*, initWriteRequest, + (::p4::v1::WriteRequest*, bool)); + + MOCK_METHOD(absl::Status, sendWriteRequest, + (const p4::v1::WriteRequest& request)); +}; + +} // namespace ovsp4rt + +#endif // OVSP4RT_CLIENT_MOCK_H_