summaryrefslogtreecommitdiffstats
path: root/hicn-plugin/libvapi-safe
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-plugin/libvapi-safe')
-rw-r--r--hicn-plugin/libvapi-safe/CMakeLists.txt128
-rw-r--r--hicn-plugin/libvapi-safe/includes/vapi/vapi_safe.h33
-rw-r--r--hicn-plugin/libvapi-safe/libsafevapi-config.cmake.in8
-rw-r--r--hicn-plugin/libvapi-safe/src/vapi_safe.cc415
4 files changed, 584 insertions, 0 deletions
diff --git a/hicn-plugin/libvapi-safe/CMakeLists.txt b/hicn-plugin/libvapi-safe/CMakeLists.txt
new file mode 100644
index 000000000..ba647aa34
--- /dev/null
+++ b/hicn-plugin/libvapi-safe/CMakeLists.txt
@@ -0,0 +1,128 @@
+# Copyright (c) 2021-2023 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##############################################################
+# Libs and Bins names
+##############################################################
+set(SAFE_VAPI safevapi CACHE INTERNAL "" FORCE)
+set(SAFE_VAPI_SHARED ${SAFE_VAPI}.shared CACHE INTERNAL "" FORCE)
+set(SAFE_VAPI_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/includes CACHE INTERNAL "" FORCE)
+set(SAFE_VAPI_LIBRARIES ${SAFE_VAPI_SHARED} CACHE INTERNAL "" FORCE)
+
+
+##############################################################
+# C/CXX Standard
+##############################################################
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_C_STANDARD 11)
+
+
+##############################################################
+# Dependencies and third party libs
+##############################################################
+find_package(Vpp ${VPP_DEFAULT_VERSION} EXACT REQUIRED)
+find_package(Asio ${ASIO_DEFAULT_VERSION} REQUIRED)
+
+
+##############################################################
+# Check if building as subproject or as root project
+##############################################################
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+ include(CommonSetup)
+ find_package(HicnPlugin ${CURRENT_VERSION} EXACT REQUIRED)
+else()
+ list(APPEND DEPENDENCIES
+ ${HICNPLUGIN_SHARED}
+ )
+endif()
+
+
+##############################################################
+# Sources
+##############################################################
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/includes/vapi/vapi_safe.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/vapi_safe.cc
+)
+
+
+##############################################################
+# Compiler Options
+##############################################################
+set(COMPILER_OPTIONS
+ ${DEFAULT_COMPILER_OPTIONS}
+ ${MARCH_COMPILER_OPTIONS}
+)
+
+
+##############################################################
+# Libraries to link
+##############################################################
+set (LIBRARIES
+ ${VPP_LIBRARY_VAPICLIENT}
+)
+
+
+##############################################################
+# Include directories
+##############################################################
+list (APPEND INCLUDE_DIRS
+ PUBLIC
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
+ $<BUILD_INTERFACE:${HICNPLUGIN_INCLUDE_DIRS}>
+ $<BUILD_INTERFACE:${VPP_INCLUDE_DIR}>
+ $<BUILD_INTERFACE:${SAFE_VAPI_INCLUDE_DIRS}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+
+##############################################################
+# Compiler definitions
+##############################################################
+list(APPEND COMPILER_DEFINITIONS
+ PUBLIC "-DASIO_STANDALONE"
+)
+
+
+##############################################################
+# Build library
+##############################################################
+build_library(${SAFE_VAPI}
+ SHARED
+ SOURCES ${SOURCE_FILES} ${HEADER_FILES}
+ INSTALL_HEADERS ${HEADER_FILES}
+ LINK_LIBRARIES PRIVATE ${LIBRARIES}
+ COMPONENT ${HICN_PLUGIN}
+ INCLUDE_DIRS ${INCLUDE_DIRS}
+ HEADER_ROOT_DIR ""
+ DEFINITIONS PRIVATE ${COMPILER_DEFINITIONS}
+ DEPENDS ${DEPENDENCIES}
+ VERSION ${CURRENT_VERSION}
+ EXPORT_NAME "libsafevapi"
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
+)
+
+
+##############################################################
+# Create cmake configuration
+##############################################################
+create_cmake_config (
+ "libsafevapi"
+ INCLUDE_DIRS ${SAFE_VAPI_INCLUDE_DIRS}
+ VERSION ${CURRENT_VERSION}
+ COMPONENT ${HICN_PLUGIN}
+ NAMESPACE hicn
+)
diff --git a/hicn-plugin/libvapi-safe/includes/vapi/vapi_safe.h b/hicn-plugin/libvapi-safe/includes/vapi/vapi_safe.h
new file mode 100644
index 000000000..e13e73556
--- /dev/null
+++ b/hicn-plugin/libvapi-safe/includes/vapi/vapi_safe.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021-2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VAPI_SAFE__
+#define __VAPI_SAFE__
+
+#include <vapi/vapi.h>
+#include <pthread.h>
+
+#include <vapi/hicn.api.vapi.h>
+#include <vapi/interface.api.vapi.h>
+#include <vapi/ip.api.vapi.h>
+#include <vapi/memif.api.vapi.h>
+#include <vapi/udp.api.vapi.h>
+
+vapi_error_e vapi_connect_safe (vapi_ctx_t *vapi_ctx_ret, int async);
+vapi_error_e vapi_disconnect_safe ();
+void vapi_lock ();
+void vapi_unlock ();
+
+#endif
diff --git a/hicn-plugin/libvapi-safe/libsafevapi-config.cmake.in b/hicn-plugin/libvapi-safe/libsafevapi-config.cmake.in
new file mode 100644
index 000000000..feb278c1f
--- /dev/null
+++ b/hicn-plugin/libvapi-safe/libsafevapi-config.cmake.in
@@ -0,0 +1,8 @@
+@PACKAGE_INIT@
+
+set(Libsafevapi_VERSION_MAJOR "@VERSION_MAJOR@")
+set(Libsafevapi_VERSION_MINOR "@VERSION_MINOR@")
+set(Libsafevapi_VERSION_PATCH "@VERSION_PATCH@")
+
+set_and_check(Libsafe_vapi_INCLUDE_DIRS "@PACKAGE_Libsafevapi_INCLUDE_DIRS@")
+include("${CMAKE_CURRENT_LIST_DIR}/libsafevapi-targets.cmake")
diff --git a/hicn-plugin/libvapi-safe/src/vapi_safe.cc b/hicn-plugin/libvapi-safe/src/vapi_safe.cc
new file mode 100644
index 000000000..8747ca738
--- /dev/null
+++ b/hicn-plugin/libvapi-safe/src/vapi_safe.cc
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C"
+{
+#include <stdio.h>
+#include <stdlib.h>
+#include <vapi/vapi_safe.h>
+}
+
+#include <thread>
+#include <random>
+#include <asio.hpp>
+#include <iostream>
+
+namespace
+{
+class NonCopyable
+{
+protected:
+ NonCopyable () = default;
+ ~NonCopyable () = default;
+
+ NonCopyable (const NonCopyable &) = delete;
+ NonCopyable &operator= (const NonCopyable &) = delete;
+};
+
+template <typename T> class Singleton : NonCopyable
+{
+public:
+ static T &
+ getInstance ()
+ {
+ static T instance;
+ return instance;
+ }
+
+protected:
+ Singleton () {}
+ ~Singleton () {}
+};
+
+template <typename T> class ThreadLocalSingleton : NonCopyable
+{
+public:
+ static T &
+ getInstance ()
+ {
+ static thread_local T instance;
+ return instance;
+ }
+
+protected:
+ ThreadLocalSingleton () {}
+ ~ThreadLocalSingleton () {}
+};
+
+class EventThread
+{
+public:
+ EventThread (asio::io_service &io_service, bool detached = false)
+ : internal_io_service_ (nullptr), io_service_ (std::ref (io_service)),
+ work_guard_ (asio::make_work_guard (io_service_.get ())),
+ thread_ (nullptr), detached_ (detached)
+ {
+ run ();
+ }
+
+ explicit EventThread (bool detached = false)
+ : internal_io_service_ (std::make_unique<asio::io_service> ()),
+ io_service_ (std::ref (*internal_io_service_)),
+ work_guard_ (asio::make_work_guard (io_service_.get ())),
+ thread_ (nullptr), detached_ (detached)
+ {
+ run ();
+ }
+
+ EventThread (const EventThread &) = delete;
+ EventThread &operator= (const EventThread &) = delete;
+
+ EventThread (EventThread &&other) noexcept
+ : internal_io_service_ (std::move (other.internal_io_service_)),
+ io_service_ (std::move (other.io_service_)),
+ work_guard_ (std::move (other.work_guard_)),
+ thread_ (std::move (other.thread_)),
+ detached_ (other.detached_)
+ {
+ }
+
+ ~EventThread () { stop (); }
+
+ void
+ run ()
+ {
+ if (stopped ())
+ {
+ io_service_.get ().stopped ();
+ }
+
+ thread_ =
+ std::make_unique<std::thread> ([this] () { io_service_.get ().run (); });
+
+ if (detached_)
+ {
+ thread_->detach ();
+ }
+ }
+
+ std::thread::id
+ getThreadId () const
+ {
+ if (thread_)
+ {
+ return thread_->get_id ();
+ }
+ else
+ {
+ throw std::runtime_error ("Event thread is not running.");
+ }
+ }
+
+ template <typename Func>
+ void
+ add (Func &&f)
+ {
+ io_service_.get ().post (std::forward<Func> (f));
+ }
+
+ template <typename Func>
+ void
+ tryRunHandlerNow (Func &&f)
+ {
+ io_service_.get ().dispatch (std::forward<Func> (f));
+ }
+
+ template <typename Func>
+ void
+ addAndWaitForExecution (Func &&f) const
+ {
+ auto promise = std::promise<void> ();
+ auto future = promise.get_future ();
+
+ asio::dispatch (io_service_.get (),
+ [&promise, f = std::forward<Func> (f)] () {
+ f ();
+ promise.set_value ();
+ });
+
+ future.wait ();
+ }
+
+ void
+ stop ()
+ {
+ add ([this] () { work_guard_.reset (); });
+
+ if (thread_ && thread_->joinable ())
+ {
+ thread_->join ();
+ }
+
+ thread_.reset ();
+ }
+
+ bool
+ stopped () const
+ {
+ return io_service_.get ().stopped ();
+ }
+
+ asio::io_service &
+ getIoService ()
+ {
+ return io_service_;
+ }
+
+private:
+ std::unique_ptr<asio::io_service> internal_io_service_;
+ std::reference_wrapper<asio::io_service> io_service_;
+ asio::executor_work_guard<asio::io_context::executor_type> work_guard_;
+ std::unique_ptr<std::thread> thread_;
+ bool detached_;
+};
+
+class UUID : public Singleton<UUID>
+{
+ friend class Singleton<UUID>;
+ static inline unsigned char hex_chars[16] = { '0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f' };
+
+public:
+ static inline constexpr unsigned int UUID_LEN = 64;
+
+ ~UUID () = default;
+ std::string
+ generate ()
+ {
+ return generate_hex (UUID_LEN);
+ }
+
+ std::string
+ generate_hex (const unsigned int len)
+ {
+ std::string ret (len, 0);
+
+ for (auto &c : ret)
+ {
+ c = random_char ();
+ }
+
+ return ret;
+ }
+
+private:
+ UUID () : rd_ (), gen_ (rd_ ()), dis_ (0, sizeof (hex_chars) - 1) {}
+
+ unsigned char
+ random_char ()
+ {
+ return hex_chars[dis_ (gen_)];
+ }
+
+private:
+ std::random_device rd_;
+ std::mt19937 gen_;
+ std::uniform_int_distribution<> dis_;
+};
+
+} // namespace
+
+DEFINE_VAPI_MSG_IDS_HICN_API_JSON
+DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON
+DEFINE_VAPI_MSG_IDS_IP_API_JSON
+DEFINE_VAPI_MSG_IDS_UDP_API_JSON
+DEFINE_VAPI_MSG_IDS_MEMIF_API_JSON
+
+class VapiGlobalConnection : public Singleton<VapiGlobalConnection>
+{
+ friend class Singleton<VapiGlobalConnection>;
+
+ static inline char kapp_name[] = "hicn_app";
+ static inline char kapi_prefix[] = "";
+ static inline int kresponse_queue_size = 32;
+ static inline int kmax_outstanding_requests = 32;
+ static inline uint32_t ktimeout_seconds = 1;
+
+public:
+ vapi_error_e
+ vapiConnectSafe (vapi_ctx_t *vapi_ctx_ret)
+ {
+ if (isConnected ())
+ {
+ *vapi_ctx_ret = vapi_ctx_;
+ return VAPI_OK;
+ }
+
+ std::unique_lock<std::mutex> lock (vapi_mtx_);
+
+ auto rv = vapi_ctx_alloc (&vapi_ctx_);
+ if (rv != VAPI_OK)
+ {
+ return rv;
+ }
+
+ rv = vapi_connect (vapi_ctx_, app_name_.c_str (), nullptr,
+ max_outstanding_requests_, response_queue_size_,
+ VAPI_MODE_BLOCKING, 1);
+ connected_ = true;
+
+ vapi_set_generic_event_cb (vapi_ctx_, &VapiGlobalConnection::genericCb,
+ nullptr);
+
+ if (rv == VAPI_OK)
+ {
+ // startDispatcher ();
+ *vapi_ctx_ret = vapi_ctx_;
+ }
+
+ return rv;
+ }
+
+ void
+ vapiLock ()
+ {
+ vapi_mtx_.lock ();
+ }
+
+ void
+ vapiUnLock ()
+ {
+ vapi_mtx_.unlock ();
+ }
+
+ bool
+ isConnected ()
+ {
+ return connected_;
+ }
+
+ ~VapiGlobalConnection ()
+ {
+ std::cout << "\"adios1" << std::endl;
+ if (!isConnected ())
+ {
+ return;
+ }
+ std::cout << "\"adios" << std::endl;
+ std::unique_lock<std::mutex> lock (vapi_mtx_);
+ vapi_disconnect (vapi_ctx_);
+ vapi_ctx_free (vapi_ctx_);
+ timer_.cancel ();
+ }
+
+private:
+ VapiGlobalConnection (
+ const std::string &app_name = std::string (kapp_name) + "_" +
+ UUID::getInstance ().generate_hex (5),
+ const std::string &api_prefix = kapi_prefix,
+ int max_outstanding_requests = kmax_outstanding_requests,
+ int response_queue_size = kresponse_queue_size)
+ : app_name_ (app_name), api_prefix_ (api_prefix),
+ max_outstanding_requests_ (max_outstanding_requests),
+ response_queue_size_ (response_queue_size), vapi_mtx_ (),
+ vapi_ctx_ (nullptr), connected_ (false), thread_ (),
+ timer_ (thread_.getIoService ())
+ {
+ }
+
+ void
+ timerHandler (const std::error_code &ec)
+ {
+ if (ec)
+ {
+ // Timer was canceled
+ return;
+ }
+
+ if (!isConnected ())
+ {
+ return;
+ }
+
+ std::unique_lock<std::mutex> lock (vapi_mtx_);
+ auto err = vapi_dispatch (vapi_ctx_);
+ if (err != VAPI_OK)
+ {
+ return;
+ }
+
+ startDispatcher ();
+ }
+
+ void
+ startDispatcher ()
+ {
+ timer_.expires_after (std::chrono::seconds (ktimeout_seconds));
+ timer_.async_wait (std::bind (&VapiGlobalConnection::timerHandler, this,
+ std::placeholders::_1));
+ }
+
+ static vapi_error_e
+ genericCb (vapi_ctx_t ctx, void *callback_ctx, vapi_msg_id_t id, void *msg)
+ {
+ std::cout << "Called" << std::endl;
+ return VAPI_OK;
+ }
+
+private:
+ std::string app_name_;
+ std::string api_prefix_;
+ int max_outstanding_requests_;
+ int response_queue_size_;
+ std::mutex vapi_mtx_;
+ vapi_ctx_t vapi_ctx_;
+ std::atomic_bool connected_;
+ EventThread thread_;
+ asio::steady_timer timer_;
+};
+
+vapi_error_e
+vapi_connect_safe (vapi_ctx_t *vapi_ctx_ret, int async)
+{
+ return VapiGlobalConnection::getInstance ().vapiConnectSafe (vapi_ctx_ret);
+}
+
+vapi_error_e
+vapi_disconnect_safe ()
+{
+ return VAPI_OK;
+}
+
+void
+vapi_lock ()
+{
+ VapiGlobalConnection::getInstance ().vapiLock ();
+}
+
+void
+vapi_unlock ()
+{
+ VapiGlobalConnection::getInstance ().vapiUnLock ();
+}