From c4012d1c1e70c8f92324e61ddbfe230612c065dc Mon Sep 17 00:00:00 2001
From: Carsten Patzke <carsten.patzke@desy.de>
Date: Thu, 19 Mar 2020 18:08:09 +0100
Subject: [PATCH] Added LibFabric dependency

---
 CMakeLists.txt                                | 13 +++-
 CMakeModules/FindLibFabric.cmake              | 15 ++++
 common/cpp/CMakeLists.txt                     |  2 +
 .../cpp/include/asapo_fabric/asapo_fabric.h   | 76 +++++++++++++++++++
 common/cpp/src/asapo_fabric/CMakeLists.txt    | 23 ++++++
 common/cpp/src/asapo_fabric/asapo_fabric.cpp  | 17 +++++
 .../src/asapo_fabric/fabric_factory_impl.cpp  | 45 +++++++++++
 .../src/asapo_fabric/fabric_factory_impl.h    | 16 ++++
 .../fabric_factory_not_supported.cpp          | 14 ++++
 .../fabric_factory_not_supported.h            | 14 ++++
 .../fabric_internal_impl_common.h             | 23 ++++++
 11 files changed, 257 insertions(+), 1 deletion(-)
 create mode 100644 CMakeModules/FindLibFabric.cmake
 create mode 100644 common/cpp/include/asapo_fabric/asapo_fabric.h
 create mode 100644 common/cpp/src/asapo_fabric/CMakeLists.txt
 create mode 100644 common/cpp/src/asapo_fabric/asapo_fabric.cpp
 create mode 100644 common/cpp/src/asapo_fabric/fabric_factory_impl.cpp
 create mode 100644 common/cpp/src/asapo_fabric/fabric_factory_impl.h
 create mode 100644 common/cpp/src/asapo_fabric/fabric_factory_not_supported.cpp
 create mode 100644 common/cpp/src/asapo_fabric/fabric_factory_not_supported.h
 create mode 100644 common/cpp/src/asapo_fabric/fabric_internal_impl_common.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9eca15771..cbe091aba 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,6 +41,8 @@ option(BUILD_PYTHON_DOCS "Uses sphinx to build the Python documentaion" OFF)
 option(BUILD_CONSUMER_TOOLS "Build consumer tools" OFF)
 option(BUILD_EXAMPLES "Build examples" OFF)
 
+option(ENABLE_LIBFABRIC "Enables LibFabric support for RDMA transfers" OFF)
+
 set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules/)
 
 set (ASAPO_CXX_COMMON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/common/cpp/include)
@@ -61,7 +63,16 @@ if ("${Python_EXECUTABLE}" STREQUAL "")
 endif()
 message (STATUS "Using Python: ${Python_EXECUTABLE}")
 
-
+IF(ENABLE_LIBFABRIC)
+    find_package(LibFabric)
+    if(NOT LIBFABRIC_LIBRARY)
+        message(FATAL_ERROR "Did not find libfabric")
+    endif()
+    message(STATUS "LibFabric support enabled")
+    message(STATUS "LIB_FABRIC: Path: ${LIBFABRIC_LIBRARY} Include: ${LIBFABRIC_INCLUDE_DIR}")
+    SET_PROPERTY(GLOBAL PROPERTY ASAPO_COMMON_FABRIC_LIBRARIES ${ASAPO_COMMON_IO_LIBRARIES} libfabric)
+    add_definitions(-DLIBFABRIC_ENABLED)
+ENDIF()
 
 # format sources
 include(astyle)
diff --git a/CMakeModules/FindLibFabric.cmake b/CMakeModules/FindLibFabric.cmake
new file mode 100644
index 000000000..24b54d5b1
--- /dev/null
+++ b/CMakeModules/FindLibFabric.cmake
@@ -0,0 +1,15 @@
+# FindLibFabric
+# -------------
+#
+# Tries to find LibFabric on the system
+#
+# Available variables
+# LIBFABRIC_LIBRARY         - Path to the library
+# LIBFABRIC_INCLUDE_DIR     - Path to the include dir
+
+cmake_minimum_required(VERSION 2.6)
+
+find_path(LIBFABRIC_INCLUDE_DIR fabric.h)
+find_library(LIBFABRIC_LIBRARY fabric)
+
+mark_as_advanced(LIBFABRIC_INCLUDE_DIR LIBFABRIC_LIBRARY)
diff --git a/common/cpp/CMakeLists.txt b/common/cpp/CMakeLists.txt
index d7770ef6a..cfa9198b4 100644
--- a/common/cpp/CMakeLists.txt
+++ b/common/cpp/CMakeLists.txt
@@ -12,6 +12,8 @@ add_subdirectory(src/logger)
 
 add_subdirectory(src/request)
 
+add_subdirectory(src/asapo_fabric)
+
 if(BUILD_MONGODB_CLIENTLIB)
     add_subdirectory(src/database)
 endif()
diff --git a/common/cpp/include/asapo_fabric/asapo_fabric.h b/common/cpp/include/asapo_fabric/asapo_fabric.h
new file mode 100644
index 000000000..5399c3a3b
--- /dev/null
+++ b/common/cpp/include/asapo_fabric/asapo_fabric.h
@@ -0,0 +1,76 @@
+#ifndef ASAPO_FABRIC_H
+#define ASAPO_FABRIC_H
+
+#include <cstdint>
+#include <string>
+#include <memory>
+#include <common/error.h>
+
+namespace asapo { namespace fabric {
+        typedef uint64_t FabricAddress;
+        typedef uint64_t FabricMessageId;
+
+#pragma pack(push, 1)
+        struct MemoryRegionDetails {
+            uint64_t addr;
+            uint64_t length;
+            uint64_t key;
+        };
+#pragma pack(pop)
+
+        class FabricMemoryRegion {
+        public:
+            virtual ~FabricMemoryRegion() = default;
+            virtual MemoryRegionDetails* GetDetails() = 0;
+        };
+
+        class FabricContext {
+        public:
+            /// If this function is not called, the default timeout is 5000 ms
+            virtual void SetRequestTimeout(uint64_t msTimeout) = 0;
+
+            virtual std::string GetAddress() const = 0;
+
+            virtual std::unique_ptr<FabricMemoryRegion> ShareMemoryRegion(void* src, size_t size, Error* error) = 0;
+
+            virtual void Send(FabricAddress dstAddress, FabricMessageId messageId,
+                              const void* src, size_t size, Error* error) = 0;
+
+            virtual void Recv(FabricAddress srcAddress, FabricMessageId messageId,
+                              void* dst, size_t size, Error* error) = 0;
+
+            virtual void RdmaWrite(FabricAddress dstAddress,
+                                   MemoryRegionDetails* details, const void* buffer, size_t size,
+                                   Error* error) = 0;
+
+            // Since RdmaRead heavily impacts the performance we will not implement this
+            // virtual void RdmaRead(...) = 0;
+
+
+        };
+
+        class FabricClient : public FabricContext {
+        public:
+            virtual ~FabricClient() = default;
+
+            virtual FabricAddress AddServerAddress(const std::string& serverAddress, Error* error) = 0;
+        };
+
+        class FabricServer : public FabricContext {
+        public:
+            virtual ~FabricServer() = default;
+
+            virtual void RecvAny(FabricAddress* srcAddress, FabricMessageId* messageId, void* src, size_t size, Error* error) = 0;
+        };
+
+        class FabricFactory {
+        public:
+            virtual std::unique_ptr<FabricServer> CreateAndBindServer(Error* error) const = 0;
+
+            virtual std::unique_ptr<FabricClient> CreateClient(Error* error) const = 0;
+        };
+
+        std::unique_ptr<FabricFactory> GenerateDefaultFabricFactory();
+}}
+
+#endif //ASAPO_FABRIC_H
diff --git a/common/cpp/src/asapo_fabric/CMakeLists.txt b/common/cpp/src/asapo_fabric/CMakeLists.txt
new file mode 100644
index 000000000..ad7e8b354
--- /dev/null
+++ b/common/cpp/src/asapo_fabric/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(TARGET_NAME asapo-fabric)
+
+include_directories(include)
+
+set(SOURCE_FILES asapo_fabric.cpp)
+
+IF(ENABLE_LIBFABRIC)
+	set(SOURCE_FILES ${SOURCE_FILES}
+		fabric_factory_impl.cpp
+		)
+ELSE()
+	set(SOURCE_FILES ${SOURCE_FILES}
+		fabric_factory_not_supported.cpp
+		)
+ENDIF()
+
+################################
+# Library
+################################
+
+add_library(${TARGET_NAME} STATIC ${SOURCE_FILES})
+
+target_include_directories(${TARGET_NAME} PUBLIC ${ASAPO_CXX_COMMON_INCLUDE_DIR})
diff --git a/common/cpp/src/asapo_fabric/asapo_fabric.cpp b/common/cpp/src/asapo_fabric/asapo_fabric.cpp
new file mode 100644
index 000000000..96aa4fd52
--- /dev/null
+++ b/common/cpp/src/asapo_fabric/asapo_fabric.cpp
@@ -0,0 +1,17 @@
+#include <asapo_fabric/asapo_fabric.h>
+
+#ifdef LIBFABRIC_ENABLED
+#include "fabric_factory_impl.h"
+#else
+#include "fabric_factory_not_supported.h"
+#endif
+
+using namespace asapo::fabric;
+
+std::unique_ptr<FabricFactory> asapo::fabric::GenerateDefaultFabricFactory() {
+#ifdef LIBFABRIC_ENABLED
+    return std::unique_ptr<FabricFactory>(new FabricFactoryImpl());
+#else
+    return std::unique_ptr<FabricFactory>(new FabricFactoryNotSupported());
+#endif
+}
diff --git a/common/cpp/src/asapo_fabric/fabric_factory_impl.cpp b/common/cpp/src/asapo_fabric/fabric_factory_impl.cpp
new file mode 100644
index 000000000..b5c267ef8
--- /dev/null
+++ b/common/cpp/src/asapo_fabric/fabric_factory_impl.cpp
@@ -0,0 +1,45 @@
+#include "fabric_factory_impl.h"
+#include "fabric_internal_impl_common.h"
+#include <rdma/fabric.h>
+
+using namespace asapo::fabric;
+
+std::string fi_version_string(uint32_t version) {
+    return std::to_string(FI_MAJOR(version)) + "." + std::to_string(FI_MINOR(version));
+}
+
+bool FabricFactoryImpl::HasValidVersion(Error* error) const {
+    auto current_version = fi_version();
+
+    if (FI_VERSION_LT(current_version, EXPECTED_FI_VERSION)) {
+        std::string found_version_str = fi_version_string(current_version);
+        std::string expected_version_str = fi_version_string(EXPECTED_FI_VERSION);
+
+        std::string errorText = "LibFabric outdated.";
+        errorText += " (Found " + found_version_str + " but expected at least " + expected_version_str + ")";
+
+        *error = TextError(errorText);
+        return false;
+    }
+
+    return true;
+}
+
+std::unique_ptr<FabricClient>
+FabricFactoryImpl::CreateClient(Error* error) const {
+    if (!HasValidVersion(error)) {
+        return nullptr;
+    }
+
+    *error = TextError("This build of ASAPO does not support LibFabric.");
+    return nullptr;
+}
+
+std::unique_ptr<FabricServer> FabricFactoryImpl::CreateAndBindServer(Error* error) const {
+    if (!HasValidVersion(error)) {
+        return nullptr;
+    }
+
+    *error = TextError("This build of ASAPO does not support LibFabric.");
+    return nullptr;
+}
diff --git a/common/cpp/src/asapo_fabric/fabric_factory_impl.h b/common/cpp/src/asapo_fabric/fabric_factory_impl.h
new file mode 100644
index 000000000..776d42a98
--- /dev/null
+++ b/common/cpp/src/asapo_fabric/fabric_factory_impl.h
@@ -0,0 +1,16 @@
+#include <asapo_fabric/asapo_fabric.h>
+
+#ifndef ASAPO_FABRIC_FACTORY_IMPL_H
+#define ASAPO_FABRIC_FACTORY_IMPL_H
+
+namespace asapo { namespace fabric {
+    class FabricFactoryImpl : public FabricFactory {
+        bool HasValidVersion(Error* error) const;
+
+        std::unique_ptr<FabricServer> CreateAndBindServer(Error* error) const override;
+
+        std::unique_ptr<FabricClient> CreateClient(Error* error) const override;
+    };
+}}
+
+#endif //ASAPO_FABRIC_FACTORY_IMPL_H
diff --git a/common/cpp/src/asapo_fabric/fabric_factory_not_supported.cpp b/common/cpp/src/asapo_fabric/fabric_factory_not_supported.cpp
new file mode 100644
index 000000000..0508d9972
--- /dev/null
+++ b/common/cpp/src/asapo_fabric/fabric_factory_not_supported.cpp
@@ -0,0 +1,14 @@
+#include "fabric_factory_not_supported.h"
+
+using namespace asapo::fabric;
+
+std::unique_ptr<FabricServer> asapo::fabric::FabricFactoryNotSupported::CreateAndBindServer(Error* error) const {
+    *error = TextError("This build of ASAPO does not support LibFabric.");
+    return nullptr;
+}
+
+std::unique_ptr<FabricClient> asapo::fabric::FabricFactoryNotSupported::CreateClient(Error* error) const {
+    *error = TextError("This build of ASAPO does not support LibFabric.");
+    return nullptr;
+}
+
diff --git a/common/cpp/src/asapo_fabric/fabric_factory_not_supported.h b/common/cpp/src/asapo_fabric/fabric_factory_not_supported.h
new file mode 100644
index 000000000..c701ac1a5
--- /dev/null
+++ b/common/cpp/src/asapo_fabric/fabric_factory_not_supported.h
@@ -0,0 +1,14 @@
+#ifndef ASAPO_FABRIC_FACTORY_NOT_SUPPORTED_H
+#define ASAPO_FABRIC_FACTORY_NOT_SUPPORTED_H
+
+#include <asapo_fabric/asapo_fabric.h>
+
+namespace asapo { namespace fabric {
+    class FabricFactoryNotSupported : public FabricFactory {
+        std::unique_ptr<FabricServer> CreateAndBindServer(Error* error) const override;
+
+        std::unique_ptr<FabricClient> CreateClient(Error* error) const override;
+    };
+}}
+
+#endif //ASAPO_FABRIC_FACTORY_NOT_SUPPORTED_H
diff --git a/common/cpp/src/asapo_fabric/fabric_internal_impl_common.h b/common/cpp/src/asapo_fabric/fabric_internal_impl_common.h
new file mode 100644
index 000000000..73882fd0b
--- /dev/null
+++ b/common/cpp/src/asapo_fabric/fabric_internal_impl_common.h
@@ -0,0 +1,23 @@
+#ifndef ASAPO_FABRIC_INTERNAL_IMPL_COMMON_H
+#define ASAPO_FABRIC_INTERNAL_IMPL_COMMON_H
+
+/*
+ * This file contains common features used in ASAPO's integration of libfabric.
+ * Only include this file into *.cpp files, never in *.h files
+ */
+
+#ifndef EXPECTED_FI_VERSION
+#define EXPECTED_FI_VERSION FI_VERSION(1, 9)
+#endif
+
+#pragma pack(push, 1)
+struct HandshakePayload {
+    // Hostnames can be up to 256 Bytes long. We also need to store the port number.
+    char hostnameAndPort[512];
+};
+
+#pragma pack(pop)
+
+#define TODO_UNKNOWN_ADDRESS (FI_ADDR_NOTAVAIL - 1)
+
+#endif //ASAPO_FABRIC_INTERNAL_IMPL_COMMON_H
-- 
GitLab