diff options
author | Luca Muscariello <lumuscar@cisco.com> | 2022-03-30 22:29:28 +0200 |
---|---|---|
committer | Mauro Sardara <msardara@cisco.com> | 2022-03-31 19:51:47 +0200 |
commit | c46e5df56b67bb8ea7a068d39324c640084ead2b (patch) | |
tree | eddeb17785938e09bc42eec98ee09b8a28846de6 /hicn-light | |
parent | 18fa668f25d3cc5463417ce7df6637e31578e898 (diff) |
feat: boostrap hicn 22.02
The current patch provides several new features, improvements,
bug fixes and also complete rewrite of entire components.
- lib
The hicn packet parser has been improved with a new packet
format fully based on UDP. The TCP header is still temporarily
supported but the UDP header will replace completely the new hicn
packet format. Improvements have been made to make sure every
packet parsing operation is made via this library. The current
new header can be used as header between the payload and the
UDP header or as trailer in the UDP surplus area to be tested
when UDP options will start to be used.
- hicn-light
The portable packet forwarder has been completely rewritten from
scratch with the twofold objective to improve performance and
code size but also to drop dependencies such as libparc which is
now removed by the current implementation.
- hicn control
the control library is the agent that is used to program the
packet forwarders via their binary API. This component has
benefited from significant improvements in terms of interaction
model which is now event driven and more robust to failures.
- VPP plugin has been updated to support VPP 22.02
- transport
Major improvement have been made to the RTC protocol, to the
support of IO modules and to the security sub system. Signed
manifests are the default data authenticity and integrity framework.
Confidentiality can be enabled by sharing the encryption key to the
prod/cons layer. The library has been tested with group key based
applications such as broadcast/multicast and real-time on-line
meetings with trusted server keys or MLS.
- testing
Unit testing has been introduced using GoogleTest. One third of
the code base is covered by unit testing with priority on
critical features. Functional testing has also been introduce
using Docker, linux bridging and Robot Framework to define
test with Less Code techniques to facilitate the extension
of the coverage.
Co-authored-by: Mauro Sardara <msardara@cisco.com>
Co-authored-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Co-authored-by: Michele Papalini <micpapal@cisco.com>
Co-authored-by: Angelo Mantellini <manangel@cisco.com>
Co-authored-by: Jacques Samain <jsamain@cisco.com>
Co-authored-by: Olivier Roques <oroques+fdio@cisco.com>
Co-authored-by: Enrico Loparco <eloparco@cisco.com>
Co-authored-by: Giulio Grassi <gigrassi@cisco.com>
Change-Id: I75d0ef70f86d921e3ef503c99271216ff583c215
Signed-off-by: Luca Muscariello <muscariello@ieee.org>
Signed-off-by: Mauro Sardara <msardara@cisco.com>
Diffstat (limited to 'hicn-light')
357 files changed, 24894 insertions, 33032 deletions
diff --git a/hicn-light/src/hicn/command_line/daemon/CMakeLists.txt b/hicn-light/.clang-format index a86826f09..2dc5c0c54 100644 --- a/hicn-light/src/hicn/command_line/daemon/CMakeLists.txt +++ b/hicn-light/.clang-format @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021 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: @@ -11,20 +11,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -list(APPEND DAEMON_SRC - hicnLightDaemon_main.c -) - -if (WIN32) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:\"LIBCMT\"") -endif() - -if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android") - build_executable(${HICN_LIGHT_DAEMON} - SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${LIBHICN_LIGHT_STATIC} - DEPENDS ${LIBHICN_LIGHT_STATIC} - COMPONENT ${HICN_LIGHT} - DEFINITIONS ${COMPILER_DEFINITIONS} - ) -endif () +BasedOnStyle: Google +SortIncludes: false diff --git a/hicn-light/CMakeLists.txt b/hicn-light/CMakeLists.txt index 64b93d997..337e22b7f 100644 --- a/hicn-light/CMakeLists.txt +++ b/hicn-light/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -11,115 +11,109 @@ # See the License for the specific language governing permissions and # limitations under the License. +############################################################## +# Project and cmake version +############################################################## cmake_minimum_required(VERSION 3.10 FATAL_ERROR) - project(hicn-light) -if (NOT CMAKE_BUILD_TYPE) - message(STATUS "${PROJECT_NAME}: No build type selected, default to Release") - set(CMAKE_BUILD_TYPE "Release") -endif() +############################################################## +# Libs and Bins names +############################################################## +set(LIBHICN_LIGHT hicn-light) +set(LIBHICN_LIGHT_STATIC ${LIBHICN_LIGHT}.static) + + +############################################################## +# Packaging and versioning +############################################################## +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/packaging.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/../versions.cmake) + + +############################################################## +# Cmake modules +############################################################## set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" ) + +############################################################## +# C Standard +############################################################## set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) -option(ENABLE_PUNTING "Enable punting on linux systems" ON) - -include( CTest ) -include( detectCacheSize ) -if(NOT WIN32) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") -else () - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996") -endif () +############################################################## +# Libs and Bins names +############################################################## +set(HICN_LIGHT hicn-light CACHE INTERNAL "" FORCE) +set(HICN_LIGHT_CONTROL ${HICN_LIGHT}-control CACHE INTERNAL "" FORCE) +set(HICN_LIGHT_SHELL ${HICN_LIGHT}-shell CACHE INTERNAL "" FORCE) +set(HICN_LIGHT_DAEMON ${HICN_LIGHT}-daemon CACHE INTERNAL "" FORCE) -if(${CMAKE_SYSTEM_NAME} STREQUAL "Android") - message("############ Detected cross compile for $ENV{CMAKE_SYSTEM_NAME}") - # Android uses static libs, so we need to link all the dependencies to the executable - find_package(OpenSSL REQUIRED) - find_package(LibEvent REQUIRED) - set(ANDROID_LIBRARIES ${LIBEVENT_LIBRARIES} ${OPENSSL_LIBRARIES}) -endif() -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DLIBRTA_DISABLE_VALIDATION -DPARCLibrary_DISABLE_VALIDATION") +############################################################## +# Dependencies and third party libs +############################################################## +find_package(LibEvent ${LIBEVENT_DEFAULT_VERSION} REQUIRED) +find_package(Threads REQUIRED) -include(IosMacros) -include(WindowsMacros) -find_package(Libparc REQUIRED) +############################################################## +# Check if building as subproject or as root project +############################################################## +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + include(CommonSetup) + find_package(Libhicn ${CURRENT_VERSION} REQUIRED NO_MODULE) + find_package(Libhicnctrl ${CURRENT_VERSION} REQUIRED NO_MODULE) -set(HICN_LIGHT hicn-light CACHE INTERNAL "" FORCE) -set(HICN_LIGHT_CONTROL ${HICN_LIGHT}-control CACHE INTERNAL "" FORCE) -set(HICN_LIGHT_DAEMON ${HICN_LIGHT}-daemon CACHE INTERNAL "" FORCE) + if (DISABLE_SHARED_LIBRARIES) + set(LIBTYPE static) + else() + set(LIBTYPE shared) + endif() -if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - find_package(Libhicn REQUIRED) + list(APPEND HICN_LIBRARIES hicn::hicn.${LIBTYPE}) + list(APPEND LIBHICNCTRL_LIBRARIES hicn::hicnctrl.${LIBTYPE}) else() if (DISABLE_SHARED_LIBRARIES) - if (WIN32) - set(HICN_LIBRARIES ${LIBHICN_STATIC}) + if (WIN32) + set(HICN_LIBRARIES ${LIBHICN_STATIC} ${LIBHICNCTRL_STATIC}) else () - set(HICN_LIBRARIES ${LIBHICN_STATIC} log) + set(HICN_LIBRARIES ${LIBHICN_STATIC} ${LIBHICNCTRL_STATIC} log) endif () list(APPEND DEPENDENCIES ${LIBHICN_STATIC} + ${LIBHICNCTRL_STATIC} ) else () - set(HICN_LIBRARIES ${LIBHICN_SHARED}) + set(HICN_LIBRARIES + ${LIBHICN_SHARED} + ${LIBHICNCTRL_SHARED} + ) list(APPEND DEPENDENCIES ${LIBHICN_SHARED} + ${LIBHICNCTRL_SHARED} ) endif () endif() -include(Packaging) - -find_package(Threads REQUIRED) - -set(LIBHICN_LIGHT hicn-light) -set(LIBHICN_LIGHT_STATIC ${LIBHICN_LIGHT}.static) - -set(LIBRARIES - ${LIBPARC_LIBRARIES} - ${HICN_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - ${WINDOWS_LIBRARIES} - ${ANDROID_LIBRARIES} -) - -set(HICN_LIGHT_LIBRARIES_LIST "${LIBPARC_LIBRARIES};${CMAKE_THREAD_LIBS_INIT};${WINDOWS_LIBRARIES}" CACHE INTERNAL "HICN_LIGHT_LIBRARIES_LIST") - - -# Include dirs -- Order does matter! -list(APPEND HICN_LIGHT_INCLUDE_DIRS - ${HICN_INCLUDE_DIRS} - ${LIBPARC_INCLUDE_DIRS} - ${WINDOWS_INCLUDE_DIRS} -) - -if (UNIX) - list(APPEND LIBRARIES - m - ) -endif() - -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") - -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") - set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS} -undefined dynamic_lookup") - message(STATUS "Set \"-undefined dynamic_lookup\" for shared libraries") -endif() +############################################################## +# Subdirectories +############################################################## add_subdirectory(src/hicn) + +############################################################## # Install service file in linux systems +############################################################## include(ServiceScript) install_service_script( ${CMAKE_CURRENT_SOURCE_DIR}/config/hicn-light.service diff --git a/hicn-light/cmake/Modules/Packaging.cmake b/hicn-light/cmake/packaging.cmake index 2b9f4a7b9..ccf567e41 100644 --- a/hicn-light/cmake/Modules/Packaging.cmake +++ b/hicn-light/cmake/packaging.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -21,7 +21,7 @@ set(${HICN_LIGHT}_DESCRIPTION ) set(${HICN_LIGHT}_DEB_DEPENDENCIES - "lib${LIBHICN} (>= stable_version), libparc (>= 1.0)" + "lib${LIBHICN} (= stable_version)" CACHE STRING "Dependencies for deb/rpm package." ) @@ -31,7 +31,7 @@ set(${HICN_LIGHT}_DEB_PACKAGE_CONTROL_EXTRA ) set(${HICN_LIGHT}_RPM_DEPENDENCIES - "lib${LIBHICN} >= stable_version, libparc >= 1.0" + "lib${LIBHICN} = stable_version" CACHE STRING "Dependencies for deb/rpm package." ) diff --git a/hicn-light/config/hicn-light.service b/hicn-light/config/hicn-light.service index f269b2f26..79d5ced93 100644 --- a/hicn-light/config/hicn-light.service +++ b/hicn-light/config/hicn-light.service @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021 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: diff --git a/hicn-light/config/post b/hicn-light/config/post index 91f596050..f2f566426 100755 --- a/hicn-light/config/post +++ b/hicn-light/config/post @@ -2,4 +2,4 @@ if pidof systemd; then systemctl enable hicn-light -fi +fi
\ No newline at end of file diff --git a/hicn-light/config/postinst b/hicn-light/config/postinst index dced2a093..f2f566426 100755 --- a/hicn-light/config/postinst +++ b/hicn-light/config/postinst @@ -1,3 +1,5 @@ #!/bin/bash -systemctl enable hicn-light
\ No newline at end of file +if pidof systemd; then + systemctl enable hicn-light +fi
\ No newline at end of file diff --git a/hicn-light/config/prerm b/hicn-light/config/prerm index 4584c7057..c1d3d55a1 100755 --- a/hicn-light/config/prerm +++ b/hicn-light/config/prerm @@ -1,3 +1,5 @@ #!/bin/bash -systemctl disable hicn-light
\ No newline at end of file +if pidof systemd; then + systemctl disable hicn-light +fi
\ No newline at end of file diff --git a/hicn-light/config/preun b/hicn-light/config/preun index 4584c7057..c1d3d55a1 100755 --- a/hicn-light/config/preun +++ b/hicn-light/config/preun @@ -1,3 +1,5 @@ #!/bin/bash -systemctl disable hicn-light
\ No newline at end of file +if pidof systemd; then + systemctl disable hicn-light +fi
\ No newline at end of file diff --git a/hicn-light/src/hicn/CMakeLists.txt b/hicn-light/src/hicn/CMakeLists.txt index 639bfa179..401ae84eb 100644 --- a/hicn-light/src/hicn/CMakeLists.txt +++ b/hicn-light/src/hicn/CMakeLists.txt @@ -1,55 +1,129 @@ -# Define a few configuration variables that we want accessible in the software +# Copyright (c) 2021-2022 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. -include(BuildMacros) +############################################################## +# Libraries to link +############################################################## +set(LIBRARIES + PUBLIC ${HICN_LIBRARIES} + PUBLIC ${LIBHICNCTRL_LIBRARIES} + PRIVATE ${LIBEVENT_LIBRARIES} + PRIVATE ${CMAKE_THREAD_LIBS_INIT} +) + +if (UNIX) + list(APPEND LIBRARIES + m + ) +endif() + + +############################################################## +# Configuration file +############################################################## configure_file(config.h.in hicn-light/config.h @ONLY) -if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND ENABLE_PUNTING) + +############################################################## +# Compiler definitions +############################################################## +list(APPEND COMPILER_DEFINITIONS + PRIVATE -DLIBRTA_DISABLE_VALIDATION +) + +list(APPEND COMPILER_DEFINITIONS +# "-DWITH_GRO" +# "-DWITH_GSO" +# "-DWITH_ZEROCOPY" + PRIVATE "-DWITH_POLICY_STATS" + PRIVATE "-DWITH_CLI" +# "-DNDEBUG=1" # disable assertions +) + +if (UNIX AND NOT APPLE) list(APPEND COMPILER_DEFINITIONS - "-DPUNTING" + "-D_GNU_SOURCE" # batching support through struct mmsghdr ) endif() -list(APPEND COMPILER_DEFINITIONS - "-DWITH_MAPME" - "-DWITH_POLICY" + +############################################################## +# Compiler options +############################################################## +set(COMPILER_OPTIONS + ${DEFAULT_COMPILER_OPTIONS} ) +############################################################## +# Sources +############################################################## if (NOT DISABLE_EXECUTABLES) - add_subdirectory(command_line) + add_subdirectory(cli) endif() +add_subdirectory(base) add_subdirectory(config) add_subdirectory(content_store) add_subdirectory(core) add_subdirectory(io) -add_subdirectory(messenger) add_subdirectory(platforms) -add_subdirectory(processor) add_subdirectory(socket) add_subdirectory(strategies) add_subdirectory(utils) +list(APPEND TO_INSTALL_HEADER_FILES + ${HEADER_FILES} +) + list(APPEND HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/hicn-light/config.h ) -list(INSERT HICN_LIGHT_INCLUDE_DIRS 0 - ${CMAKE_CURRENT_SOURCE_DIR}/.. - ${CMAKE_CURRENT_BINARY_DIR}/.. + +############################################################## +# Includes +############################################################## +list(APPEND HICN_LIGHT_INCLUDE_DIRS + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..> + $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/..> + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + PRIVATE + ${LIBEVENT_INCLUDE_DIRS} + ${WINDOWS_INCLUDE_DIRS} ) list(APPEND TO_INSTALL_HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/hicn-light/config.h ) + +############################################################## +# Build type +############################################################## +set(LIB_BUILD_TYPE STATIC) if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android") - set(LIB_BUILD_TYPE "NO_DEV") -else() - set(LIB_BUILD_TYPE "") + list(APPEND LIB_BUILD_TYPE + "NO_DEV" + ) endif() + +############################################################## +# Build forwarder library +############################################################## build_library(${LIBHICN_LIGHT} - STATIC ${LIB_BUILD_TYPE} + ${LIB_BUILD_TYPE} SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} LINK_LIBRARIES ${LIBRARIES} @@ -57,6 +131,14 @@ build_library(${LIBHICN_LIGHT} COMPONENT ${HICN_LIGHT} INCLUDE_DIRS ${HICN_LIGHT_INCLUDE_DIRS} HEADER_ROOT_DIR hicn - DEFINITIONS ${COMPILER_DEFINITIONS} + DEFINITIONS PUBLIC ${COMPILER_DEFINITIONS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} ) + +############################################################## +# Build tests +############################################################## +if (BUILD_TESTS) + add_subdirectory(test) +endif() diff --git a/hicn-light/src/hicn/messenger/CMakeLists.txt b/hicn-light/src/hicn/base/CMakeLists.txt index 69a6c32d1..1180ed05b 100644 --- a/hicn-light/src/hicn/messenger/CMakeLists.txt +++ b/hicn-light/src/hicn/base/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -12,19 +12,28 @@ # limitations under the License. list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/missiveDeque.h - ${CMAKE_CURRENT_SOURCE_DIR}/missive.h - ${CMAKE_CURRENT_SOURCE_DIR}/missiveType.h - ${CMAKE_CURRENT_SOURCE_DIR}/messenger.h - ${CMAKE_CURRENT_SOURCE_DIR}/messengerRecipient.h + ${CMAKE_CURRENT_SOURCE_DIR}/bitmap.h + ${CMAKE_CURRENT_SOURCE_DIR}/common.h + ${CMAKE_CURRENT_SOURCE_DIR}/hash.h + ${CMAKE_CURRENT_SOURCE_DIR}/khash.h + ${CMAKE_CURRENT_SOURCE_DIR}/loop.h + ${CMAKE_CURRENT_SOURCE_DIR}/pool.h + ${CMAKE_CURRENT_SOURCE_DIR}/ring.h + ${CMAKE_CURRENT_SOURCE_DIR}/vector.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/messenger.c - ${CMAKE_CURRENT_SOURCE_DIR}/messengerRecipient.c - ${CMAKE_CURRENT_SOURCE_DIR}/missive.c - ${CMAKE_CURRENT_SOURCE_DIR}/missiveDeque.c + ${CMAKE_CURRENT_SOURCE_DIR}/loop.c + ${CMAKE_CURRENT_SOURCE_DIR}/pool.c + ${CMAKE_CURRENT_SOURCE_DIR}/ring.c + ${CMAKE_CURRENT_SOURCE_DIR}/vector.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) + +set(TO_INSTALL_HEADER_FILES + ${TO_INSTALL_HEADER_FILES} + ${HEADER_FILES} + PARENT_SCOPE +) diff --git a/hicn-light/src/hicn/base/bitmap.h b/hicn-light/src/hicn/base/bitmap.h new file mode 100644 index 000000000..ed3fac2fd --- /dev/null +++ b/hicn-light/src/hicn/base/bitmap.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file bitmap.h + * \brief Bitmap + * + * A bitmap is implemented as a wrapper over a vector made of bit elements + */ + +#ifndef UTIL_BITMAP_H +#define UTIL_BITMAP_H + +#include <assert.h> +#include <string.h> +#include <sys/param.h> // MIN, MAX + +#include <hicn/util/log.h> + +#include "common.h" +#include "vector.h" + +typedef uint_fast32_t bitmap_t; + +#define BITMAP_WIDTH(bitmap) (sizeof((bitmap)[0]) * 8) + +/** + * @brief Allocate and initialize a bitmap + * + * @param[in,out] bitmap Bitmap to allocate and initialize + * @param[in] max_size Bitmap max_size + */ +#define bitmap_init(bitmap, init_size, max_size) \ + vector_init( \ + bitmap, next_pow2((init_size) / BITMAP_WIDTH(bitmap)), \ + max_size == 0 ? 0 : next_pow2((max_size) / BITMAP_WIDTH(bitmap))) + +/* + * @brief Ensures a bitmap is sufficiently large to hold an element at the + * given position. + * + * @param[in] bitmap The bitmap for which to validate the position. + * @param[in] pos The position to validate. + * + * NOTE: + * - This function should always be called before writing to a bitmap element + * to eventually make room for it (the bitmap will eventually be resized). + */ +static inline int bitmap_ensure_pos(bitmap_t** bitmap, off_t pos) { + size_t offset = pos / BITMAP_WIDTH(*bitmap); + return vector_ensure_pos(*bitmap, offset); +} + +/** + * @brief Returns the allocated size of a bitmap. + * + * @see listener_table_get_by_id + */ +#define bitmap_get_alloc_size(bitmap) vector_get_alloc_size(bitmap) + +/** + * @brief Retrieve the state of the i-th bit in the bitmap. + * + * @param[in] bitmap The bitmap to access. + * @param[in] i The bit position. + */ +static inline int bitmap_get(const bitmap_t* bitmap, off_t i) { + size_t offset = i / BITMAP_WIDTH(bitmap); + assert(offset < bitmap_get_alloc_size(bitmap)); + size_t pos = i % BITMAP_WIDTH(bitmap); + size_t shift = BITMAP_WIDTH(bitmap) - pos - 1; + return (bitmap[offset] >> shift) & 1; +} + +/* + * @brief Returns whether the i-th bit is set (equal to 1) in a bitmap. + * + * @param[in] bitmap The bitmap to access. + * @param[in] i The bit position. + * + * @return bool + */ +#define bitmap_is_set(bitmap, i) (bitmap_get((bitmap), (i)) == 1) +#define bitmap_is_unset(bitmap, i) (bitmap_get((bitmap), (i)) == 0) + +/* + * @brief Returns whether the i-th bit is unset (equal to 0) in a bitmap. + * + * @param[in] bitmap The bitmap to access. + * @param[in] i The bit position. + * + * @return bool + */ +#define bitmap_set(bitmap, i) _bitmap_set((bitmap_t**)&bitmap, i) + +/* + * @brief Returns whether the i-th bit is unset (equal to 0) in a bitmap + * (helper). + * + * @param[in] bitmap The bitmap to access. + * @param[in] i The bit position. + * + * @return bool + */ +static inline int _bitmap_set(bitmap_t** bitmap, off_t i) { + if (bitmap_ensure_pos(bitmap, i) < 0) return -1; + size_t offset = i / BITMAP_WIDTH(bitmap); + size_t pos = i % BITMAP_WIDTH(bitmap); + size_t shift = BITMAP_WIDTH(bitmap) - pos - 1; + (*bitmap)[offset] |= (bitmap_t)1 << shift; + return 0; +} + +static inline int bitmap_unset(bitmap_t* bitmap, off_t i) { + if (bitmap_ensure_pos(&bitmap, i) < 0) return -1; + size_t offset = i / BITMAP_WIDTH(bitmap); + size_t pos = i % BITMAP_WIDTH(bitmap); + size_t shift = BITMAP_WIDTH(bitmap) - pos - 1; + bitmap[offset] &= ~(1ul << shift); + return 0; +} + +static inline int bitmap_set_range(bitmap_t* bitmap, off_t from, off_t to) { + assert(from <= to); + ssize_t offset_from = from / BITMAP_WIDTH(bitmap); + ssize_t offset_to = to / BITMAP_WIDTH(bitmap); + size_t pos_from = from % BITMAP_WIDTH(bitmap); + size_t pos_to = to % BITMAP_WIDTH(bitmap); + + /* + * First block initialization is needed if <from> is not aligned with the + * bitmap element size or if to is within the same one. + */ + if ((pos_from != 0) || + ((offset_to == offset_from) && (pos_to != BITMAP_WIDTH(bitmap) - 1))) { + size_t from_end = MIN(to, (offset_from + 1) * BITMAP_WIDTH(bitmap)); + for (size_t k = from; k < from_end; k++) { + if (bitmap_set(bitmap, k) < 0) goto END; + } + } + + /* + * Second block is needed if <to> is not aligned with the bitmap element + * size + */ + if ((pos_to != BITMAP_WIDTH(bitmap) - 1) && (offset_to != offset_from)) { + size_t to_start = MAX(from, offset_to * BITMAP_WIDTH(bitmap)); + for (size_t k = to_start; k < (size_t)to; k++) { + if (bitmap_set(bitmap, k) < 0) goto END; + } + } + + if (pos_from != 0) offset_from += 1; + if (pos_to != BITMAP_WIDTH(bitmap) - 1) offset_to -= 1; + + /* + * We need to cover both elements at position offset_from and offset_to + * provided that offset_from is not bigger + */ + if (offset_to >= offset_from) { + memset(&bitmap[offset_from], 0xFF, + (offset_to - offset_from + 1) * sizeof(bitmap[0])); + } + + return 0; + +END: + ERROR("Error setting bitmap range\n"); + return -1; +} + +#define bitmap_set_to(bitmap, to) bitmap_set_range((bitmap), 0, (to)) + +#define bitmap_free(bitmap) vector_free(bitmap) + +#endif /* UTIL_BITMAP_H */ diff --git a/hicn-light/src/hicn/base/common.h b/hicn-light/src/hicn/base/common.h new file mode 100644 index 000000000..9f7e3beec --- /dev/null +++ b/hicn-light/src/hicn/base/common.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file array.h + * \brief Fixed-size pool allocator + */ + +#ifndef UTIL_COMMON_H +#define UTIL_COMMON_H + +#define round_pow2(x, pow2) ((x + pow2 - 1) & ~(pow2 - 1)) + +#define _SIZEOF_ALIGNED(x, size) round_pow2(sizeof(x), size) +#define SIZEOF_ALIGNED(x) _SIZEOF_ALIGNED(x, sizeof(void*)) + +/* Definitions for builtins unavailable on MSVC */ +#if defined(_MSC_VER) && !defined(__clang__) +#include <intrin.h> + +uint32_t __inline __builtin_ctz(uint32_t value) { + uint32_t trailing_zero = 0; + if (_BitScanForward(&trailing_zero, value)) + return trailing_zero; + else + return 32; +} + +uint32_t __inline __builtin_clz(uint32_t value) { + uint32_t leading_zero = 0; + if (_BitScanReverse(&leading_zero, value)) + return 31 - leading_zero; + else + return 32; +} + +uint32_t __inline __builtin_clzl2(uint64_t value) { + uint32_t leading_zero = 0; + if (_BitScanReverse64(&leading_zero, value)) + return 63 - leading_zero; + else + return 64; +} + +#define __builtin_clzl __builtin_clzll +#endif + +#define next_pow2(x) (x <= 1 ? 1 : 1ul << (64 - __builtin_clzl(x - 1))) + +#endif /* UTIL_COMMON_H */ diff --git a/hicn-light/src/hicn/base/hash.h b/hicn-light/src/hicn/base/hash.h new file mode 100644 index 000000000..3c54feb29 --- /dev/null +++ b/hicn-light/src/hicn/base/hash.h @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2021 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. + */ + +/* + * \file hash.h + * \brief Simple non-cryptographic hash implementation. + * + * Two helpers are provided : + * hash(buf, len) : hash a buffer <buf> of length <len> + * hash_struct(buf) : hash a buffer corresponding to an allocated struct + * + * This file consists in excerpts from Jenkins hash (public domain). + * http://www.burtleburtle.net/bob/c/lookup3.c + */ +#ifndef UTIL_HASH_H +#define UTIL_HASH_H + +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || \ + defined(MIPSEL)) +#define HASH_LITTLE_ENDIAN 1 +#define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 1 +#else +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1 << (n)) +#define hashmask(n) (hashsize(n) - 1) +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) + +#define mix(a, b, c) \ + { \ + a -= c; \ + a ^= rot(c, 4); \ + c += b; \ + b -= a; \ + b ^= rot(a, 6); \ + a += c; \ + c -= b; \ + c ^= rot(b, 8); \ + b += a; \ + a -= c; \ + a ^= rot(c, 16); \ + c += b; \ + b -= a; \ + b ^= rot(a, 19); \ + a += c; \ + c -= b; \ + c ^= rot(b, 4); \ + b += a; \ + } + +#define final(a, b, c) \ + { \ + c ^= b; \ + c -= rot(b, 14); \ + a ^= c; \ + a -= rot(c, 11); \ + b ^= a; \ + b -= rot(a, 25); \ + c ^= b; \ + c -= rot(b, 16); \ + a ^= c; \ + a -= rot(c, 4); \ + b ^= a; \ + b -= rot(a, 14); \ + c ^= b; \ + c -= rot(b, 24); \ + } + +static inline uint32_t hashlittle(const void *key, size_t length, + uint32_t initval) { + uint32_t a, b, c; /* internal state */ + union { + const void *ptr; + size_t i; + } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += k[2] & 0xffffff; + b += k[1]; + a += k[0]; + break; + case 10: + c += k[2] & 0xffff; + b += k[1]; + a += k[0]; + break; + case 9: + c += k[2] & 0xff; + b += k[1]; + a += k[0]; + break; + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += k[1] & 0xffffff; + a += k[0]; + break; + case 6: + b += k[1] & 0xffff; + a += k[0]; + break; + case 5: + b += k[1] & 0xff; + a += k[0]; + break; + case 4: + a += k[0]; + break; + case 3: + a += k[0] & 0xffffff; + break; + case 2: + a += k[0] & 0xffff; + break; + case 1: + a += k[0] & 0xff; + break; + case 0: + return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch (length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t)k8[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t)k8[9]) << 8; /* fall through */ + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += ((uint32_t)k8[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t)k8[5]) << 8; /* fall through */ + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0]; + break; + case 3: + a += ((uint32_t)k8[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t)k8[1]) << 8; /* fall through */ + case 1: + a += k8[0]; + break; + case 0: + return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) { + a += k[0] + (((uint32_t)k[1]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + c += k[4] + (((uint32_t)k[5]) << 16); + mix(a, b, c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch (length) { + case 12: + c += k[4] + (((uint32_t)k[5]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 11: + c += ((uint32_t)k8[10]) << 16; /* fall through */ + case 10: + c += k[4]; + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 7: + b += ((uint32_t)k8[6]) << 16; /* fall through */ + case 6: + b += k[2]; + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 3: + a += ((uint32_t)k8[2]) << 16; /* fall through */ + case 2: + a += k[0]; + break; + case 1: + a += k8[0]; + break; + case 0: + return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) { + a += k[0]; + a += ((uint32_t)k[1]) << 8; + a += ((uint32_t)k[2]) << 16; + a += ((uint32_t)k[3]) << 24; + b += k[4]; + b += ((uint32_t)k[5]) << 8; + b += ((uint32_t)k[6]) << 16; + b += ((uint32_t)k[7]) << 24; + c += k[8]; + c += ((uint32_t)k[9]) << 8; + c += ((uint32_t)k[10]) << 16; + c += ((uint32_t)k[11]) << 24; + mix(a, b, c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch (length) /* all the case statements fall through */ + { + case 12: + c += ((uint32_t)k[11]) << 24; + case 11: + c += ((uint32_t)k[10]) << 16; + case 10: + c += ((uint32_t)k[9]) << 8; + case 9: + c += k[8]; + case 8: + b += ((uint32_t)k[7]) << 24; + case 7: + b += ((uint32_t)k[6]) << 16; + case 6: + b += ((uint32_t)k[5]) << 8; + case 5: + b += k[4]; + case 4: + a += ((uint32_t)k[3]) << 24; + case 3: + a += ((uint32_t)k[2]) << 16; + case 2: + a += ((uint32_t)k[1]) << 8; + case 1: + a += k[0]; + break; + case 0: + return c; + } + } + + final(a, b, c); + return c; +} + +/* Helpers */ + +#define HASH_INITVAL 1 +//#define hash(buf, len) (hash_t)hashlittle(buf, len, HASH_INITVAL) +#define hash(buf, len) hashlittle(buf, len, HASH_INITVAL) +#define hash_struct(buf) hash(buf, sizeof(*buf)) + +#define str_hash(str) (hash(str, strlen(str))) +#define str_hash_eq(a, b) (str_hash(b) - str_hash(a)) + +#endif /* UTIL_JENKINS_HASH_H */ diff --git a/hicn-light/src/hicn/base/khash.h b/hicn-light/src/hicn/base/khash.h new file mode 100644 index 000000000..4c62b0260 --- /dev/null +++ b/hicn-light/src/hicn/base/khash.h @@ -0,0 +1,748 @@ +/* The MIT License + + Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/* + An example: + +#include "khash.h" +KHASH_MAP_INIT_INT(32, char) +int main() { + int ret, is_missing; + khiter_t k; + khash_t(32) *h = kh_init(32); + k = kh_put(32, h, 5, &ret); + kh_value(h, k) = 10; + k = kh_get(32, h, 10); + is_missing = (k == kh_end(h)); + k = kh_get(32, h, 5); + kh_del(32, h, k); + for (k = kh_begin(h); k != kh_end(h); ++k) + if (kh_exist(h, k)) kh_value(h, k) = 1; + kh_destroy(32, h); + return 0; +} +*/ + +/* + 2013-05-02 (0.2.8): + + * Use quadratic probing. When the capacity is power of 2, stepping + function i*(i+1)/2 guarantees to traverse each bucket. It is better than + double hashing on cache performance and is more robust than linear probing. + + In theory, double hashing should be more robust than quadratic + probing. However, my implementation is probably not for large hash tables, + because the second hash function is closely tied to the first hash function, + which reduce the effectiveness of double hashing. + + Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php + + 2011-12-29 (0.2.7): + + * Minor code clean up; no actual effect. + + 2011-09-16 (0.2.6): + + * The capacity is a power of 2. This seems to dramatically improve the + speed for simple keys. Thank Zilong Tan for the suggestion. Reference: + + - http://code.google.com/p/ulib/ + - http://nothings.org/computer/judy/ + + * Allow to optionally use linear probing which usually has better + performance for random input. Double hashing is still the default as + it is more robust to certain non-random input. + + * Added Wang's integer hash function (not used by default). This hash + function is more robust to certain non-random input. + + 2011-02-14 (0.2.5): + + * Allow to declare global functions. + + 2009-09-26 (0.2.4): + + * Improve portability + + 2008-09-19 (0.2.3): + + * Corrected the example + * Improved interfaces + + 2008-09-11 (0.2.2): + + * Improved speed a little in kh_put() + + 2008-09-10 (0.2.1): + + * Added kh_clear() + * Fixed a compiling error + + 2008-09-02 (0.2.0): + + * Changed to token concatenation which increases flexibility. + + 2008-08-31 (0.1.2): + + * Fixed a bug in kh_get(), which has not been tested previously. + + 2008-08-31 (0.1.1): + + * Added destructor +*/ + +#ifndef __AC_KHASH_H +#define __AC_KHASH_H + +/*! + @header + + Generic hash table library. + */ + +#define AC_VERSION_KHASH_H "0.2.8" + +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +/* compiler specific configuration */ + +#if UINT_MAX == 0xffffffffu +typedef unsigned int khint32_t; +#elif ULONG_MAX == 0xffffffffu +typedef unsigned long khint32_t; +#endif + +#if ULONG_MAX == ULLONG_MAX +typedef unsigned long khint64_t; +#else +typedef unsigned long long khint64_t; +#endif + +#ifndef kh_inline +#ifdef _MSC_VER +#define kh_inline __inline +#else +#define kh_inline inline +#endif +#endif /* kh_inline */ + +#ifndef klib_unused +#if (defined __clang__ && __clang_major__ >= 3) || \ + (defined __GNUC__ && __GNUC__ >= 3) +#define klib_unused __attribute__((__unused__)) +#else +#define klib_unused +#endif +#endif /* klib_unused */ + +typedef khint32_t khint_t; +typedef khint_t khiter_t; + +#define __ac_isempty(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 2) +#define __ac_isdel(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 1) +#define __ac_iseither(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 3) +#define __ac_set_isdel_false(flag, i) \ + (flag[i >> 4] &= ~(1ul << ((i & 0xfU) << 1))) +#define __ac_set_isempty_false(flag, i) \ + (flag[i >> 4] &= ~(2ul << ((i & 0xfU) << 1))) +#define __ac_set_isboth_false(flag, i) \ + (flag[i >> 4] &= ~(3ul << ((i & 0xfU) << 1))) +#define __ac_set_isdel_true(flag, i) (flag[i >> 4] |= 1ul << ((i & 0xfU) << 1)) + +#define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4) + +#ifndef kroundup32 +#define kroundup32(x) \ + (--(x), (x) |= (x) >> 1, (x) |= (x) >> 2, (x) |= (x) >> 4, (x) |= (x) >> 8, \ + (x) |= (x) >> 16, ++(x)) +#endif + +#ifndef kcalloc +#define kcalloc(N, Z) calloc(N, Z) +#endif +#ifndef kmalloc +#define kmalloc(Z) malloc(Z) +#endif +#ifndef krealloc +#define krealloc(P, Z) realloc(P, Z) +#endif +#ifndef kfree +#define kfree(P) free(P) +#endif + +static const double __ac_HASH_UPPER = 0.77; + +#define __KHASH_TYPE(name, khkey_t, khval_t) \ + typedef struct kh_##name##_s { \ + khint_t n_buckets, size, n_occupied, upper_bound; \ + khint32_t *flags; \ + khkey_t *keys; \ + khval_t *vals; \ + } kh_##name##_t; + +#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ + extern kh_##name##_t *kh_init_##name(void); \ + extern void kh_destroy_##name(kh_##name##_t *h); \ + extern void kh_clear_##name(kh_##name##_t *h); \ + extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ + extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ + extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ + extern void kh_del_##name(kh_##name##_t *h, khint_t x); + +#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ + __hash_equal) \ + SCOPE kh_##name##_t *kh_init_##name(void) { \ + return (kh_##name##_t *)kcalloc(1, sizeof(kh_##name##_t)); \ + } \ + SCOPE void kh_destroy_##name(kh_##name##_t *h) { \ + if (h) { \ + kfree((void *)h->keys); \ + kfree(h->flags); \ + kfree((void *)h->vals); \ + kfree(h); \ + } \ + } \ + SCOPE void kh_clear_##name(kh_##name##_t *h) { \ + if (h && h->flags) { \ + memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ + h->size = h->n_occupied = 0; \ + } \ + } \ + SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) { \ + if (h->n_buckets) { \ + khint_t k, i, last, mask, step = 0; \ + mask = h->n_buckets - 1; \ + k = __hash_func(key); \ + i = k & mask; \ + last = i; \ + while (!__ac_isempty(h->flags, i) && \ + (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ + i = (i + (++step)) & mask; \ + if (i == last) return h->n_buckets; \ + } \ + return __ac_iseither(h->flags, i) ? h->n_buckets : i; \ + } else \ + return 0; \ + } \ + SCOPE int kh_resize_##name( \ + kh_##name##_t *h, \ + khint_t new_n_buckets) { /* This function uses 0.25*n_buckets bytes of \ + working space instead of \ + [sizeof(key_t+val_t)+.25]*n_buckets. */ \ + khint32_t *new_flags = 0; \ + khint_t j = 1; \ + { \ + kroundup32(new_n_buckets); \ + if (new_n_buckets < 4) new_n_buckets = 4; \ + if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) \ + j = 0; /* requested size is too small */ \ + else { /* hash table size to be changed (shrink or expand); rehash */ \ + new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) * \ + sizeof(khint32_t)); \ + if (!new_flags) return -1; \ + memset(new_flags, 0xaa, \ + __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ + if (h->n_buckets < new_n_buckets) { /* expand */ \ + khkey_t *new_keys = (khkey_t *)krealloc( \ + (void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ + if (!new_keys) { \ + kfree(new_flags); \ + return -1; \ + } \ + h->keys = new_keys; \ + if (kh_is_map) { \ + khval_t *new_vals = (khval_t *)krealloc( \ + (void *)h->vals, new_n_buckets * sizeof(khval_t)); \ + if (!new_vals) { \ + kfree(new_flags); \ + return -1; \ + } \ + h->vals = new_vals; \ + } \ + } /* otherwise shrink */ \ + } \ + } \ + if (j) { /* rehashing is needed */ \ + for (j = 0; j != h->n_buckets; ++j) { \ + if (__ac_iseither(h->flags, j) == 0) { \ + khkey_t key = h->keys[j]; \ + khval_t val; \ + khint_t new_mask; \ + new_mask = new_n_buckets - 1; \ + if (kh_is_map) val = h->vals[j]; \ + __ac_set_isdel_true(h->flags, j); \ + while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ + khint_t k, i, step = 0; \ + k = __hash_func(key); \ + i = k & new_mask; \ + while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \ + __ac_set_isempty_false(new_flags, i); \ + if (i < h->n_buckets && \ + __ac_iseither(h->flags, i) == \ + 0) { /* kick out the existing element */ \ + { \ + khkey_t tmp = h->keys[i]; \ + h->keys[i] = key; \ + key = tmp; \ + } \ + if (kh_is_map) { \ + khval_t tmp = h->vals[i]; \ + h->vals[i] = val; \ + val = tmp; \ + } \ + __ac_set_isdel_true( \ + h->flags, i); /* mark it as deleted in the old hash table */ \ + } else { /* write the element and jump out of the loop */ \ + h->keys[i] = key; \ + if (kh_is_map) h->vals[i] = val; \ + break; \ + } \ + } \ + } \ + } \ + if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ + h->keys = (khkey_t *)krealloc((void *)h->keys, \ + new_n_buckets * sizeof(khkey_t)); \ + if (kh_is_map) \ + h->vals = (khval_t *)krealloc((void *)h->vals, \ + new_n_buckets * sizeof(khval_t)); \ + } \ + kfree(h->flags); /* free the working space */ \ + h->flags = new_flags; \ + h->n_buckets = new_n_buckets; \ + h->n_occupied = h->size; \ + h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ + } \ + return 0; \ + } \ + SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) { \ + khint_t x; \ + if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ + if (h->n_buckets > (h->size << 1)) { \ + if (kh_resize_##name(h, h->n_buckets - 1) < \ + 0) { /* clear "deleted" elements */ \ + *ret = -1; \ + return h->n_buckets; \ + } \ + } else if (kh_resize_##name(h, h->n_buckets + 1) < \ + 0) { /* expand the hash table */ \ + *ret = -1; \ + return h->n_buckets; \ + } \ + } /* TODO: to implement automatically shrinking; resize() already support \ + shrinking */ \ + { \ + khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ + x = site = h->n_buckets; \ + k = __hash_func(key); \ + i = k & mask; \ + if (__ac_isempty(h->flags, i)) \ + x = i; /* for speed up */ \ + else { \ + last = i; \ + while (!__ac_isempty(h->flags, i) && \ + (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ + if (__ac_isdel(h->flags, i)) site = i; \ + i = (i + (++step)) & mask; \ + if (i == last) { \ + x = site; \ + break; \ + } \ + } \ + if (x == h->n_buckets) { \ + if (__ac_isempty(h->flags, i) && site != h->n_buckets) \ + x = site; \ + else \ + x = i; \ + } \ + } \ + } \ + if (__ac_isempty(h->flags, x)) { /* not present at all */ \ + h->keys[x] = key; \ + __ac_set_isboth_false(h->flags, x); \ + ++h->size; \ + ++h->n_occupied; \ + *ret = 1; \ + } else if (__ac_isdel(h->flags, x)) { /* deleted */ \ + h->keys[x] = key; \ + __ac_set_isboth_false(h->flags, x); \ + ++h->size; \ + *ret = 2; \ + } else \ + *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ + return x; \ + } \ + SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) { \ + if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ + __ac_set_isdel_true(h->flags, x); \ + --h->size; \ + } \ + } + +#define KHASH_DECLARE(name, khkey_t, khval_t) \ + __KHASH_TYPE(name, khkey_t, khval_t) \ + __KHASH_PROTOTYPES(name, khkey_t, khval_t) + +#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ + __hash_equal) \ + __KHASH_TYPE(name, khkey_t, khval_t) \ + __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ + __hash_equal) + +#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, \ + __hash_equal) \ + KHASH_INIT2(name, static kh_inline klib_unused, khkey_t, khval_t, kh_is_map, \ + __hash_func, __hash_equal) + +/* --- BEGIN OF HASH FUNCTIONS --- */ + +/*! @function + @abstract Integer hash function + @param key The integer [khint32_t] + @return The hash value [khint_t] + */ +#define kh_int_hash_func(key) (khint32_t)(key) +/*! @function + @abstract Integer comparison function + */ +#define kh_int_hash_equal(a, b) ((a) == (b)) +/*! @function + @abstract 64-bit integer hash function + @param key The integer [khint64_t] + @return The hash value [khint_t] + */ +#define kh_int64_hash_func(key) (khint32_t)((key) >> 33 ^ (key) ^ (key) << 11) +/*! @function + @abstract 64-bit integer comparison function + */ +#define kh_int64_hash_equal(a, b) ((a) == (b)) +/*! @function + @abstract const char* hash function + @param s Pointer to a null terminated string + @return The hash value + */ +static kh_inline khint_t __ac_X31_hash_string(const char *s) { + khint_t h = (khint_t)*s; + if (h) + for (++s; *s; ++s) h = (h << 5) - h + (khint_t)*s; + return h; +} +/*! @function + @abstract Another interface to const char* hash function + @param key Pointer to a null terminated string [const char*] + @return The hash value [khint_t] + */ +#define kh_str_hash_func(key) __ac_X31_hash_string(key) +/*! @function + @abstract Const char* comparison function + */ +#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) + +static kh_inline khint_t __ac_Wang_hash(khint_t key) { + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return key; +} +#define kh_int_hash_func2(key) __ac_Wang_hash((khint_t)key) + +/* --- END OF HASH FUNCTIONS --- */ + +/* Other convenient macros... */ + +/*! + @abstract Type of the hash table. + @param name Name of the hash table [symbol] + */ +#define khash_t(name) kh_##name##_t + +/*! @function + @abstract Initiate a hash table. + @param name Name of the hash table [symbol] + @return Pointer to the hash table [khash_t(name)*] + */ +#define kh_init(name) kh_init_##name() + +/*! @function + @abstract Destroy a hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + */ +#define kh_destroy(name, h) kh_destroy_##name(h) + +/*! @function + @abstract Reset a hash table without deallocating memory. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + */ +#define kh_clear(name, h) kh_clear_##name(h) + +/*! @function + @abstract Resize a hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param s New size [khint_t] + */ +#define kh_resize(name, h, s) kh_resize_##name(h, s) + +/*! @function + @abstract Insert a key to the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Key [type of keys] + @param r Extra return code: -1 if the operation failed; + 0 if the key is present in the hash table; + 1 if the bucket is empty (never used); 2 if the element in + the bucket has been deleted [int*] + @return Iterator to the inserted element [khint_t] + */ +#define kh_put(name, h, k, r) kh_put_##name(h, k, r) + +/*! @function + @abstract Retrieve a key from the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Key [type of keys] + @return Iterator to the found element, or kh_end(h) if the element is + absent [khint_t] + */ +#define kh_get(name, h, k) kh_get_##name(h, k) + +/*! @function + @abstract Remove a key from the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Iterator to the element to be deleted [khint_t] + */ +#define kh_del(name, h, k) kh_del_##name(h, k) + +/*! @function + @abstract Test whether a bucket contains data. + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return 1 if containing data; 0 otherwise [int] + */ +#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x))) + +/*! @function + @abstract Get key given an iterator + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return Key [type of keys] + */ +#define kh_key(h, x) ((h)->keys[x]) + +/*! @function + @abstract Get value given an iterator + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return Value [type of values] + @discussion For hash sets, calling this results in segfault. + */ +#define kh_val(h, x) ((h)->vals[x]) + +/*! @function + @abstract Alias of kh_val() + */ +#define kh_value(h, x) ((h)->vals[x]) + +/*! @function + @abstract Get the start iterator + @param h Pointer to the hash table [khash_t(name)*] + @return The start iterator [khint_t] + */ +#define kh_begin(h) (khint_t)(0) + +/*! @function + @abstract Get the end iterator + @param h Pointer to the hash table [khash_t(name)*] + @return The end iterator [khint_t] + */ +#define kh_end(h) ((h)->n_buckets) + +/*! @function + @abstract Get the number of elements in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @return Number of elements in the hash table [khint_t] + */ +#define kh_size(h) ((h)->size) + +/*! @function + @abstract Get the number of buckets in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @return Number of buckets in the hash table [khint_t] + */ +#define kh_n_buckets(h) ((h)->n_buckets) + +/*! @function + @abstract Iterate over the entries in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @param kvar Variable to which key will be assigned + @param vvar Variable to which value will be assigned + @param code Block of code to execute + */ +#define kh_foreach(h, kvar, vvar, code) \ + { \ + khint_t __i; \ + for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ + if (!kh_exist(h, __i)) continue; \ + (kvar) = kh_key(h, __i); \ + (vvar) = kh_val(h, __i); \ + code; \ + } \ + } + +/*! @function + @abstract Iterate over the values in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @param vvar Variable to which value will be assigned + @param code Block of code to execute + */ +#define kh_foreach_value(h, vvar, code) \ + { \ + khint_t __i; \ + for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ + if (!kh_exist(h, __i)) continue; \ + (vvar) = kh_val(h, __i); \ + code; \ + } \ + } + +/* More convenient interfaces */ + +/*! @function + @abstract Instantiate a hash set containing integer keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_INT(name) \ + KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing integer keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_INT(name, khval_t) \ + KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) + +/*! @function + @abstract Instantiate a hash set containing 64-bit integer keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_INT64(name) \ + KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing 64-bit integer keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_INT64(name, khval_t) \ + KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, \ + kh_int64_hash_equal) + +typedef const char *kh_cstr_t; +/*! @function + @abstract Instantiate a hash map containing const char* keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_STR(name) \ + KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing const char* keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_STR(name, khval_t) \ + KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) + +/****************************************************************************** + * Custom + *high-level interface + ******************************************************************************/ + +#define _kh_var(x) _kh_var_##x + +/** + * @brief Return the value corresponding to a key in the hashtable. + * @return The value associated with the key or null if not found + */ +#define kh_get_val(kname, hashtable, key, default_val) \ + ({ \ + khiter_t _kh_var(k) = kh_get(kname, hashtable, key); \ + (_kh_var(k) != kh_end(hashtable) ? kh_val(hashtable, _kh_var(k)) \ + : default_val); \ + }) + +/** + * @brief Add key/value pair in the hashtable. + * @return 0 if an existing value (corresponding to the provided key) + * has been replaced; 1 if a new key/value pair has been added + * (the key was not already present in the hash table); + * 2 if a new key/value pair has been added in correspondence + * of a key previously deleted key + */ +#define kh_put_val(kname, hashtable, key, val) \ + ({ \ + int _kh_var(ret); \ + khiter_t _kh_var(k) = kh_put(kname, hashtable, key, &_kh_var(ret)); \ + kh_value(hashtable, _kh_var(k)) = val; \ + _kh_var(ret); \ + }) + +/** + * @brief Remove a key/value pair from the hashtable. + * @return void + */ +#define kh_remove_val(kname, hashtable, key) \ + ({ \ + khiter_t _kh_var(k) = kh_get(kname, hashtable, key); \ + if (_kh_var(k) != kh_end(hashtable)) { \ + free((void *)kh_key(hashtable, _kh_var(k))); \ + kh_del(kname, hashtable, _kh_var(k)); \ + } \ + }) + +/** + * @brief Free the hashtable. + * @return void + */ +#define kh_free(kname, hashtable) \ + ({ \ + const void *_kh_var(key); \ + unsigned _kh_var(val); \ + (void)_kh_var(val); \ + \ + kh_foreach(hashtable, _kh_var(key), _kh_var(val), \ + { free((void *)_kh_var(key)); }) kh_destroy(kname, hashtable); \ + }) + +#endif /* __AC_KHASH_H */ diff --git a/hicn-light/src/hicn/base/loop.c b/hicn-light/src/hicn/base/loop.c new file mode 100644 index 000000000..68970ed3a --- /dev/null +++ b/hicn-light/src/hicn/base/loop.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file loop.c + * @brief Implementation of event loop based on libevent + */ + +#include <assert.h> +#include <event2/event.h> +#include <event2/event_struct.h> +#include <event2/thread.h> +#include <fcntl.h> // fcntl +#ifdef WITH_THREAD +#include <pthread.h> +#endif /* WITH_THREAD */ +#include <hicn/util/log.h> +#include <stdlib.h> +#include <unistd.h> // fcntl + +#include "loop.h" + +loop_t *MAIN_LOOP = NULL; + +/** + * \brief Holds all callback parameters + */ +typedef struct { + void *owner; + fd_callback_t callback; + void *data; +} cb_wrapper_args_t; + +typedef enum { + EVTYPE_TIMER, + EVTYPE_FD, +} event_type_t; + +struct loop_s { + /* Libevent-based implementation */ + struct event_base *event_base; +}; + +struct event_s { + /* Reference to loop */ + loop_t *loop; + + /* Event type*/ + event_type_t event_type; + + /* Raw event */ + struct event raw_event; + + /* Callback on event */ + cb_wrapper_args_t callback; +}; + +loop_t *loop_create() { + loop_t *loop = malloc(sizeof(loop_t)); + + if (!loop) { + ERROR("[loop_create] Failed to allocate memory"); + goto ERR_MALLOC; + } + +#ifdef WITH_THREAD + evthread_use_pthreads(); +#endif /* WITH_THREAD */ + + loop->event_base = event_base_new(); + if (!loop->event_base) goto ERR_EVENT; + + event_set_log_callback(NULL); + + return loop; + +ERR_EVENT: +ERR_MALLOC: + return NULL; +} + +void loop_free(loop_t *loop) { + event_base_free(loop->event_base); + free(loop); +} + +int _loop_dispatch(loop_t *loop, int flags) { + event_base_loop(loop->event_base, flags); + return 0; +} + +int loop_dispatch(loop_t *loop) { + return _loop_dispatch(loop, EVLOOP_NO_EXIT_ON_EMPTY); +} + +int loop_break(loop_t *loop) { return event_base_loopbreak(loop->event_base); } + +int loop_undispatch(loop_t *loop) { return 0; } + +void cb_wrapper(evutil_socket_t fd, short what, void *arg) { + cb_wrapper_args_t *cb_wrapper_args = arg; + cb_wrapper_args->callback(cb_wrapper_args->owner, fd, cb_wrapper_args->data); +} + +static inline void _event_create(event_t **event, loop_t *loop, + event_type_t type, void *callback_owner, + fd_callback_t callback, void *callback_data) { + *event = malloc(sizeof(event_t)); + (*event)->callback = (cb_wrapper_args_t){ + .owner = callback_owner, + .callback = callback, + .data = callback_data, + }; + (*event)->event_type = type; + (*event)->loop = loop; +} + +int loop_fd_event_create(event_t **event, loop_t *loop, int fd, + void *callback_owner, fd_callback_t callback, + void *callback_data) { + _event_create(event, loop, EVTYPE_FD, callback_owner, callback, + callback_data); + + evutil_make_socket_nonblocking(fd); + event_assign(&(*event)->raw_event, loop->event_base, fd, EV_READ | EV_PERSIST, + cb_wrapper, &(*event)->callback); + + return 0; +} + +int loop_fd_event_register(event_t *event) { + assert(event->event_type == EVTYPE_FD); + + if (event_add(&event->raw_event, NULL) < 0) { + ERROR("[loop_fd_event_register] event_add"); + goto ERR_EVENT_ADD; + } + + return 0; + +ERR_EVENT_ADD: + return -1; +} + +int loop_event_unregister(event_t *event) { + event_del(&event->raw_event); + return 0; +} + +int loop_timer_create(event_t **timer, loop_t *loop, void *callback_owner, + fd_callback_t callback, void *callback_data) { + _event_create(timer, loop, EVTYPE_TIMER, callback_owner, callback, + callback_data); + + evtimer_assign(&(*timer)->raw_event, loop->event_base, cb_wrapper, + &(*timer)->callback); + + return 0; +} + +static inline void _ms_to_timeval(unsigned delay_ms, struct timeval *tv) { + tv->tv_sec = delay_ms / 1000; + tv->tv_usec = (delay_ms % 1000) * 1000; +} + +int loop_timer_register(event_t *timer, unsigned delay_ms) { + assert(timer->event_type == EVTYPE_TIMER); + + struct timeval tv; + _ms_to_timeval(delay_ms, &tv); + + if (tv.tv_sec == 0 && tv.tv_usec == 0) { + event_active(&timer->raw_event, EV_TIMEOUT, 0); + } else { + event_add(&timer->raw_event, &tv); + } + + return 0; +} + +int loop_timer_is_enabled(event_t *timer) { + return evtimer_pending(&timer->raw_event, NULL) != 0; +} + +int loop_event_free(event_t *event) { + int ret = loop_event_unregister(event); + free(event); + return ret; +} diff --git a/hicn-light/src/hicn/base/loop.h b/hicn-light/src/hicn/base/loop.h new file mode 100644 index 000000000..f81af333b --- /dev/null +++ b/hicn-light/src/hicn/base/loop.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file loop.h + * \brief Face manager main loop + */ + +#ifndef UTIL_LOOP_H +#define UTIL_LOOP_H + +/* fd & timer callbacks */ + +typedef int (*fd_callback_t)(void *owner, int fd, void *data); + +typedef struct { + int fd; + void *owner; + fd_callback_t callback; + void *data; +} fd_callback_data_t; + +/* loop */ + +typedef struct loop_s loop_t; +typedef struct event_s event_t; + +extern loop_t *MAIN_LOOP; + +/** + * \brief Creates a main loop + * \return Pointer to the newly created loop, or NULL in case of error + */ +loop_t *loop_create(); + +/** + * \brief Releases a loop instance and frees all associated memory + * \param [in] loop - Pointer to the loop instance to free + */ +void loop_free(loop_t *loop); + +/** + * \brief Runs the loop instance to process events (helper). + * \param [in] loop - Pointer to the loop instance + * \param [in] flags - Loop mode: EVLOOP_ONCE, EVLOOP_NONBLOCK or + * EVLOOP_NO_EXIT_ON_EMPTY \return 0 if successful, -1 otherwise + */ +int _loop_dispatch(loop_t *loop, int flags); + +/** + * \brief Runs the loop instance to process events. + * \param [in] loop - Pointer to the loop instance + * \return 0 if successful, -1 otherwise + */ +int loop_dispatch(loop_t *loop); + +/** + * \brief Terminates the dispatching of events + * \param [in] loop - Pointer to the loop instance + */ +int loop_break(loop_t *loop); + +int loop_undispatch(loop_t *loop); + +/** Create new event associated with given fd. + * \param [out] event - Struct representing new fd event + * \param [in] loop - Loop running events + * \param [in] fd - fd to register + * \param [in] callback_owner - Pointer to the owner of the callack (first + * parameter of callback function) + * \param [in] callback - Callback function + * \param [in] callback_data - User data to pass alongside callback invocation + * \return 0 in case of success, -1 otherwise + */ +int loop_fd_event_create(event_t **event, loop_t *loop, int fd, + void *callback_owner, fd_callback_t callback, + void *callback_data); + +/** + * Register event in corresponding event loop. + * \param [in] event - Struct representing fd event + * \return 0 in case of success, -1 otherwise + */ +int loop_fd_event_register(event_t *event); + +/** + * Unregister event from corresponding event loop. + * \param [in] event - Struct representing fd event + * \return 0 in case of success, -1 otherwise + */ +int loop_event_unregister(event_t *event); + +/** + * Free event object. + * \param [in] event - Struct representing the event + * \return 0 in case of success, -1 otherwise + */ +int loop_event_free(event_t *event); + +/** Create new timer event. + * \param [out] event - Struct representing new timer event + * \param [in] loop - Loop running events + * \param [in] callback_owner - Pointer to the owner of the callack (first + * parameter of callback function) + * \param [in] callback - Callback function + * \param [in] callback_data - User data to pass alongside callback invocation + * \return 0 in case of success, -1 otherwise + */ +int loop_timer_create(event_t **timer, loop_t *loop, void *callback_owner, + fd_callback_t callback, void *callback_data); + +/** + * Register event in corresponding event loop. + * \param [in] timer - Struct representing timer event + * \return 0 in case of success, -1 otherwise + */ +int loop_timer_register(event_t *timer, unsigned delay_ms); + +/** + * Check if timer is enabled. + * \param [in] timer - Struct representing timer event + * \return 1 if enabled, 0 otherwise + */ +int loop_timer_is_enabled(event_t *timer); + +#endif /* UTIL_LOOP_H */ diff --git a/hicn-light/src/hicn/base/pool.c b/hicn-light/src/hicn/base/pool.c new file mode 100644 index 000000000..ba2a14c5f --- /dev/null +++ b/hicn-light/src/hicn/base/pool.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file pool.c + * \brief Implementation of fixed-size pool allocator. + * + * NOTE: + * - Ideally, we should have a single realloc per resize, that would encompass + * both the free indices vector and bitmap, by nesting data structures. Because + * of the added complexity, and by lack of evidence of the need for this, we + * currently rely on a simpler implementation. + */ + +#include <assert.h> +#include <stdlib.h> // calloc + +#include "common.h" +#include "pool.h" + +#include <stdio.h> // XXX + +void _pool_init(void** pool_ptr, size_t elt_size, size_t init_size, + size_t max_size) { + assert(pool_ptr); + assert(elt_size); + + init_size = next_pow2(init_size); + + if (max_size && init_size > max_size) goto ERR_MAX_SIZE; + + /* The initial pool size is rounded to the next power of two */ + size_t alloc_size = next_pow2(init_size); + + pool_hdr_t* ph = calloc(POOL_HDRLEN + alloc_size * elt_size, 1); + if (!ph) goto ERR_MALLOC; + + ph->elt_size = elt_size; + ph->alloc_size = alloc_size; + ph->max_size = max_size; + + /* Free indices */ + off_t* free_indices; + vector_init(free_indices, init_size, max_size); + for (unsigned i = 0; i < init_size; i++) + free_indices[i] = (init_size - 1) - i; + vector_len(free_indices) = init_size; + ph->free_indices = free_indices; + + /* Free bitmap */ + uint_fast32_t* fb = ph->free_bitmap; + bitmap_init(fb, init_size, max_size); + bitmap_set_to(fb, init_size); + ph->free_bitmap = fb; + + *pool_ptr = (uint8_t*)ph + POOL_HDRLEN; + + return; + +ERR_MALLOC: +ERR_MAX_SIZE: + *pool_ptr = NULL; + return; +} + +void _pool_free(void** pool_ptr) { + pool_hdr_t* ph = pool_hdr(*pool_ptr); + vector_free(ph->free_indices); + bitmap_free(ph->free_bitmap); + + free(pool_hdr(*pool_ptr)); + *pool_ptr = NULL; +} + +bool _pool_validate_id(void** pool_ptr, off_t id) { + pool_hdr_t* ph = pool_hdr(*pool_ptr); + size_t pool_size = pool_get_alloc_size(*pool_ptr); + if (id >= pool_size || !bitmap_is_unset(ph->free_bitmap, id)) return false; + + return true; +} + +void _pool_resize(void** pool_ptr, size_t elt_size) { + pool_hdr_t* ph = pool_hdr(*pool_ptr); + size_t old_size = ph->alloc_size; + size_t new_size = old_size * 2; + + TRACE("pool_resize to %lu", new_size); + + if (ph->max_size && new_size > ph->max_size) goto ERR_MAX_SIZE; + + /* Double pool storage */ + ph = realloc(ph, POOL_HDRLEN + new_size * elt_size); + if (!ph) goto ERR_REALLOC; + ph->elt_size = elt_size; + ph->alloc_size = new_size; + + /* + * After resize, the pool will have new free indices, ranging from + * old_size to (new_size - 1) + */ + vector_ensure_pos(ph->free_indices, old_size); + for (unsigned i = 0; i < old_size; i++) + ph->free_indices[i] = new_size - 1 - i; + vector_len(ph->free_indices) = old_size; + + /* We also need to update the bitmap */ + bitmap_ensure_pos(&(ph->free_bitmap), new_size - 1); + bitmap_set_range(ph->free_bitmap, old_size, new_size - 1); + + /* Reassign pool pointer */ + *pool_ptr = (uint8_t*)ph + POOL_HDRLEN; + + return; + +ERR_REALLOC: +ERR_MAX_SIZE: + *pool_ptr = NULL; + return; +} + +off_t _pool_get(void** pool_ptr, void** elt, size_t elt_size) { + pool_hdr_t* ph = pool_hdr(*pool_ptr); + uint64_t l = vector_len(ph->free_indices); + if (l == 0) { + _pool_resize(pool_ptr, elt_size); + ph = pool_hdr(*pool_ptr); + l = vector_len(ph->free_indices); + } + off_t free_id = ph->free_indices[l - 1]; + vector_len(ph->free_indices)--; + bitmap_unset(ph->free_bitmap, free_id); + *elt = *pool_ptr + free_id * elt_size; + memset(*elt, 0, elt_size); + return free_id; +} + +void _pool_put(void** pool_ptr, void** elt, size_t elt_size) { + pool_hdr_t* ph = pool_hdr(*pool_ptr); + uint64_t l = vector_len(ph->free_indices); + vector_ensure_pos(ph->free_indices, l); + off_t freed_id = (*elt - *pool_ptr) / elt_size; + ph->free_indices[l] = freed_id; + vector_len(ph->free_indices)++; + bitmap_set(ph->free_bitmap, freed_id); +} diff --git a/hicn-light/src/hicn/base/pool.h b/hicn-light/src/hicn/base/pool.h new file mode 100644 index 000000000..b6573195c --- /dev/null +++ b/hicn-light/src/hicn/base/pool.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file pool.h + * \brief Fixed-size pool allocator. + * + * This memory pool allocates a single block of memory that is used to + * efficiently allocate/deallocate fixed-size blocks for high churn data + * structures. + * + * Internally this data structure leverages a vector for managing elements (and + * it thus resizeable if needed), as well as a list of free indices (in the + * form of another vector) and a bitmap marking free indices also (for fast + * iteration). + * + * The internal API manipulates a pointer to the vector that that is can be + * seamlessly resized, and a more convenient user interface is provided through + * macros. + * + * The vector of free indices is managed as a stack where elements indices are + * retrieved from and put back to the end of the vector. In the bitmap, + * available elements are set to 1, and unset to 0 when in use. + * + * The pool is not currently resized down when releasing elements. + * + * It is freely inspired (and simplified) from the VPP infra infrastructure + * library. + */ + +#ifndef UTIL_POOL_H +#define UTIL_POOL_H + +#include <stdint.h> +#include <stdbool.h> + +#include "bitmap.h" +#include "vector.h" + +/* Pool header */ + +typedef struct { + size_t elt_size; + size_t alloc_size; + size_t max_size; + bitmap_t *free_bitmap; /* bitmap of free indices */ + off_t *free_indices; /* vector of free indices */ +} pool_hdr_t; + +#define POOL_HDRLEN SIZEOF_ALIGNED(pool_hdr_t) + +/* This header actually prepends the actual content of the pool. */ +#define pool_hdr(pool) ((pool_hdr_t *)((uint8_t *)(pool)-POOL_HDRLEN)) + +/******************************************************************************/ +/* Helpers */ + +/** Local variable naming macro. */ +#define _pool_var(v) _pool_##v + +/** + * @brief Allocate and initialize a pool data structure (helper). + * + * @param[in,out] pool_ptr Pointer to the pool data structure. + * @param[in] elt_size Size of elements in vector. + * @param[in] max_size Maximum size. + * + * NOTE: that an empty pool might be equal to NULL. + */ +void _pool_init(void **pool_ptr, size_t elt_size, size_t init_size, + size_t max_size); + +/** + * @brief Free a pool data structure (helper). + * + * @param[in] pool_ptr Pointer to the pool data structure. + */ +void _pool_free(void **pool_ptr); + +/** + * @brief Resize a pool data structure (helper). + * + * @param pool_ptr Pointer to the pool data structure. + * + * This function should only be called internally, as the resize is implicitly + * done (if allowed by the maximum size) when the user tries to get a new slot. + */ +void _pool_resize(void **pool_ptr, size_t elt_size); + +/** + * @brief Get a free element from the pool data structure (helper). + * + * @param[in] pool Pointer to the pool data structure to use. + * @param[in,out] elt Pointer to an empty element that will be used to return + * the allocated one from the pool. + * + * NOTES: + * - The memory chunk is cleared upon attribution + */ +off_t _pool_get(void **pool, void **elt, size_t elt_size); + +/** + * @brief Put an element back into the pool data structure (helper). + * + * @param[in] pool_ptr Pointer to the pool data structure to use. + * @param[in] elt Pointer to the pool element to put back. + */ +void _pool_put(void **pool, void **elt, size_t elt_size); + +/** + * @brief Validate a pool element by index (helper). + * + * @param[in] pool The pool data structure to use. + * @param[in] id The index of the element to validate. + * + * @return bool A flag indicating whether the index is valid or not. + */ +bool _pool_validate_id(void **pool_ptr, off_t id); +/******************************************************************************/ +/* Public API */ + +/** + * @brief Allocate and initialize a pool data structure. + * + * @param[in,out] pool Pointer to the pool data structure. + * @param[in] elt_size Size of elements in pool. + * @param[in] max_size Maximum size. + * + * NOTE: that an empty pool might be equal to NULL. + */ +#define pool_init(pool, init_size, max_size) \ + _pool_init((void **)&pool, sizeof(pool[0]), init_size, max_size); + +/** + * @brief Free a pool data structure. + * + * @param[in] pool The pool data structure to free. + */ +#define pool_free(pool) _pool_free((void **)&pool); + +/** + * @brief Get a free element from the pool data structure. + * + * @param[in] pool The pool data structure to use. + * @param[in,out] elt An empty element that will be used to return the + * allocated one from the pool. + * + * NOTES: + * - The memory chunk is cleared upon attribution + */ +#define pool_get(pool, elt) \ + _pool_get((void **)&pool, (void **)&elt, sizeof(*elt)) + +/** + * @brief Put an element back into the pool data structure. + * + * @param[in] pool The pool data structure to use. + * @param[in] elt The pool element to put back. + */ +#define pool_put(pool, elt) \ + _pool_put((void **)&pool, (void **)&elt, sizeof(*elt)) + +/** + * @brief Validate a pool element by index. + * + * @param[in] pool The pool data structure to use. + * @param[in] id The index of the element to validate. + * + * @return bool A flag indicating whether the index is valid or not. + */ +#define pool_validate_id(pool, id) _pool_validate_id((void **)&pool, (id)) + +#define pool_get_free_indices_size(pool) \ + vector_len(pool_hdr(pool)->free_indices) + +/** + * @brief Returns the current length of the pool. + * + * @param[in] pool The pool data structure for which to return the length. + * + * @return size_t The current length of the pool. + * + * NOTE: + * - The pool length corresponds to the number of allocated elements, not the + * size of the pool. + */ +#define pool_len(pool) \ + (pool_hdr(pool)->alloc_size - pool_get_free_indices_size(pool)) + +/** + * @brief Enumerate elements from a pool. + * + * @param[in] pool The pool data structure to enumerate. + * @param[in, out] i An integer that will be used for enumeration. + * @param[in, out] eltp A pointer to the element type that will be used for + * enumeration. + * @param[in] BODY Block to execute during enumeration. + * + * Enumeration will iteratively execute BODY with (i, eltp) corresponding + * respectively to the index and element found in the pool. + * + * NOTE: i stars at 0. + */ +#define pool_enumerate(pool, i, eltp, BODY) \ + do { \ + pool_hdr_t *_pool_var(ph) = pool_hdr(pool); \ + bitmap_t *_pool_var(fb) = _pool_var(ph)->free_bitmap; \ + for ((i) = 0; (i) < _pool_var(ph)->alloc_size; (i)++) { \ + if (bitmap_is_set(_pool_var(fb), (i))) continue; \ + eltp = (pool) + (i); \ + do { \ + BODY; \ + } while (0); \ + } \ + } while (0) + +/** + * @brief Iterate over elements in a pool. + * + * @param[in] pool The pool data structure to iterate over. + * @param[in,out] eltp A pointer to the element type that will be used for + * iteration. + * @param[in] BODY Block to execute during iteration. + * + * Iteration will execute BODY with eltp corresponding successively to all + * elements found in the pool. It is implemented using the more generic + * enumeration function. + */ +#define pool_foreach(pool, eltp, BODY) \ + do { \ + unsigned _pool_var(i); \ + pool_enumerate((pool), _pool_var(i), (eltp), BODY); \ + } while (0) + +#define pool_get_alloc_size(pool) pool_hdr(pool)->alloc_size + +#ifdef WITH_TESTS +#define pool_get_free_indices(pool) pool_hdr(pool)->free_indices +#define pool_get_free_bitmap(pool) pool_hdr(pool)->free_bitmap +#endif /* WITH_TESTS */ + +#endif /* UTIL_POOL_H */ diff --git a/hicn-light/src/hicn/base/ring.c b/hicn-light/src/hicn/base/ring.c new file mode 100644 index 000000000..29727886a --- /dev/null +++ b/hicn-light/src/hicn/base/ring.c @@ -0,0 +1,45 @@ + +/* + * Copyright (c) 2021 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. + */ + +/** + * \file ring.c + * \brief Implementation of ring buffer. + */ + +#include <stdlib.h> + +#include "ring.h" + +void _ring_init(void** ring_ptr, size_t elt_size, size_t max_size) { + assert(ring_ptr); + assert(elt_size > 0); + // we use a static array, not a vector (for now) + assert(max_size != 0); + + ring_hdr_t* rh = malloc(RING_HDRLEN + max_size * elt_size); + + rh->roff = 0; + rh->woff = 0; + rh->size = 0; + rh->max_size = max_size; + + *ring_ptr = (uint8_t*)rh + RING_HDRLEN; +} + +void _ring_free(void** ring_ptr) { + free(ring_hdr(*ring_ptr)); + *ring_ptr = NULL; +} diff --git a/hicn-light/src/hicn/base/ring.h b/hicn-light/src/hicn/base/ring.h new file mode 100644 index 000000000..492a8fdac --- /dev/null +++ b/hicn-light/src/hicn/base/ring.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file ring.h + * \brief Fixed-size pool allocator. + */ + +#ifndef UTIL_RING_H +#define UTIL_RING_H + +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <sys/param.h> // MIN +#include <sys/types.h> + +#include <stdio.h> // XXX debug + +#include "common.h" + +/******************************************************************************/ +/* Ring header */ + +typedef struct { + size_t roff; + size_t woff; + size_t size; + size_t max_size; +} ring_hdr_t; + +/* Make sure elements following the header are aligned */ +#define RING_HDRLEN SIZEOF_ALIGNED(ring_hdr_t) + +/* This header actually prepends the actual content of the vector */ +#define ring_hdr(ring) ((ring_hdr_t *)((uint8_t *)ring - RING_HDRLEN)) + +/******************************************************************************/ +/* Helpers */ + +/** Local variable naming macro. */ +#define _ring_var(v) _ring_##v + +/** + * @brief Allocate and initialize a ring data structure (helper function). + * + * @param[in,out] ring_ptr Ring buffer to allocate and initialize. + * @param[in] elt_size Size of a ring element. + * @param[in] max_size Maximum vector size (O = unlimited). + */ +void _ring_init(void **ring_ptr, size_t elt_size, size_t max_size); + +/** + * @brief Free a ring data structure. + * + * @param ring_ptr[in] Pointer to the ring data structure to free. + */ +void _ring_free(void **ring_ptr); + +static inline int _ring_add(void **ring_ptr, size_t elt_size, void *eltp) { + assert(*ring_ptr); + ring_hdr_t *rh = ring_hdr(*ring_ptr); + + /* We always write ! */ + memcpy((uint8_t *)*ring_ptr + rh->woff * elt_size, eltp, elt_size); + rh->woff++; + if (rh->woff == rh->max_size) rh->woff = 0; + if (rh->size < rh->max_size) { + rh->size++; + } else { + /* One packet was dropped */ + rh->roff++; + if (rh->roff == rh->max_size) rh->roff = 0; + } + return 0; +} + +static inline unsigned _ring_get_fullness(void **ring_ptr) { + assert(*ring_ptr); + ring_hdr_t *rh = ring_hdr(*ring_ptr); + return rh->size * 100 / rh->max_size; +} + +static inline unsigned _ring_is_full(void **ring_ptr) { + assert(*ring_ptr); + ring_hdr_t *rh = ring_hdr(*ring_ptr); + return rh->size == rh->max_size; +} + +static inline size_t _ring_get_size(void **ring_ptr) { + assert(*ring_ptr); + ring_hdr_t *rh = ring_hdr(*ring_ptr); + return rh->size; +} + +static inline int _ring_advance(void **ring_ptr, unsigned n) { + assert(*ring_ptr); + ring_hdr_t *rh = ring_hdr(*ring_ptr); + assert(n <= rh->size); + + rh->roff += n; + rh->size -= n; + while (rh->roff >= rh->max_size) rh->roff -= rh->max_size; + return 0; +} + +static inline int _ring_get(void **ring_ptr, size_t elt_size, unsigned i, + void *eltp) { + assert(*ring_ptr); + ring_hdr_t *rh = ring_hdr(*ring_ptr); + assert(i <= rh->size); + size_t pos = rh->roff + i; + if (pos >= rh->max_size) pos -= rh->max_size; + memcpy(eltp, (uint8_t *)*ring_ptr + pos * elt_size, elt_size); + return 0; +} + +/******************************************************************************/ +/* Public API */ + +/** + * @brief Allocate and initialize a ring data structure. + * + * @param[in,out] ring Ring to allocate and initialize. + * @param[in] max_size Maximum ring size (nonzero). + * + * NOTE: + * - Allocated memory is set to 0 (used by bitmap) + */ + +#define ring_init(RING, MAX_SIZE) \ + _ring_init((void **)&(RING), sizeof((RING)[0]), (MAX_SIZE)) + +#define ring_free(RING) _ring_free((void **)&(RING)) + +#define ring_get_fullness(RING) _ring_get_fullness((void **)&(RING)) + +#define ring_is_full(RING) _ring_is_full((void **)&(RING)) + +#define ring_get_size(RING) _ring_get_size((void **)&(RING)) + +#define ring_add(RING, ELT) _ring_add((void **)&(RING), sizeof(RING[0]), ELT) + +#define ring_add_value(RING, VALUE) \ + do { \ + typeof(VALUE) _ring_var(v) = VALUE; \ + _ring_add((void **)&(RING), sizeof(RING[0]), &_ring_var(v)); \ + } while (0) + +#define ring_advance(RING, N) _ring_advance((void **)&(RING), (N)) + +#define ring_get(RING, I, ELTP) \ + _ring_get((void **)&RING, sizeof(RING[0]), (I), (ELTP)) + +/** + * @brief Helper function used by ring_foreach(). + */ +#define ring_enumerate_n(RING, I, ELTP, COUNT, BODY) \ + ({ \ + for ((I) = 0; (I) < MIN(ring_get_size(RING), (COUNT)); (I)++) { \ + ring_get((RING), (I), (ELTP)); \ + { BODY; } \ + } \ + }) + +#define ring_enumerate(ring, i, eltp, BODY) \ + ring_enumerate_n((ring), (i), (eltp), 1, (BODY)) + +/** + * @brief Iterate over elements in a ring. + * + * @param[in] pool The ring data structure to iterate over + * @param[in, out] eltp A pointer to the element that will be used for + * iteration + * @param[in] BODY Block to execute during iteration + * + * @note Iteration will execute BODY with eltp corresponding successively to all + * elements found in the ring. It is implemented using the more generic + * enumeration function. + */ +#define ring_foreach_n(ring, eltp, count, BODY) \ + ({ \ + unsigned _ring_var(i); \ + ring_enumerate_n((ring), _ring_var(i), (eltp), (count), BODY); \ + }) + +#define ring_foreach(ring, eltp, BODY) ring_foreach_n((ring), (eltp), 1, (BODY)) + +#endif /* UTIL_RING_H */ diff --git a/hicn-light/src/hicn/base/vector.c b/hicn-light/src/hicn/base/vector.c new file mode 100644 index 000000000..36d808932 --- /dev/null +++ b/hicn-light/src/hicn/base/vector.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file vector.c + * \brief Implementation of resizeable static array + */ + +#include <assert.h> +#include <stddef.h> // size_t +#include <stdlib.h> // calloc +#include <stdio.h> + +#include "vector.h" + +#define DEFAULT_VECTOR_SIZE 64 + +void _vector_init(void** vector_ptr, size_t elt_size, size_t init_size, + size_t max_size) { + assert(vector_ptr); + assert(max_size == 0 || init_size < max_size); + + if (init_size == 0) init_size = DEFAULT_VECTOR_SIZE; + + *vector_ptr = NULL; + _vector_resize(vector_ptr, elt_size, init_size); + + vector_hdr_t* vh = vector_hdr(*vector_ptr); + vh->cur_size = 0; + vh->max_size = max_size; +} + +void _vector_free(void** vector_ptr) { + free(vector_hdr(*vector_ptr)); + *vector_ptr = NULL; +} + +int _vector_resize(void** vector_ptr, size_t elt_size, off_t pos) { + vector_hdr_t* vh; + + size_t old_size; + + if (*vector_ptr) { + vh = vector_hdr(*vector_ptr); + old_size = vh->alloc_size; + } else { + vh = NULL; + old_size = 0; + } + + /* Round the allocated size to the next power of 2 of the requested position + */ + size_t new_size = next_pow2(pos); + + /* Don't grow the vector back */ + if (new_size < old_size) return 0; + + /* Don't exceed maximum size (for init, check is done beforehand) */ + if (vh && vh->max_size && new_size > vh->max_size) return -1; + + vh = realloc(vh, VECTOR_HDRLEN + new_size * elt_size); + if (!vh) return -1; + vh->alloc_size = new_size; + + /* Zero out the newly allocated memory (except headers) */ + memset((uint8_t*)vh + VECTOR_HDRLEN + old_size * elt_size, 0, + (new_size - old_size) * elt_size); + + /* Reassign vector pointer */ + *vector_ptr = (uint8_t*)vh + VECTOR_HDRLEN; + + return 0; +} diff --git a/hicn-light/src/hicn/base/vector.h b/hicn-light/src/hicn/base/vector.h new file mode 100644 index 000000000..0b7a74aeb --- /dev/null +++ b/hicn-light/src/hicn/base/vector.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file vector.h + * \brief Resizeable static array + * + * A vector is a resizeable area of contiguous memory that contains elements of + * fixed size. It is mostly useful to serve as the basis for more advanced data + * structures such as memory pools. + * + * The internal API manipulates a pointer to the vector so that it can be + * seamlessly resized, and a more convenient user interface is provided through + * macros. + * + * A vector starts at index 0, and is typed according to the elements it + * contains. For that matter, the data structure header precedes the returned + * pointer which corresponds to the storage area. + * + * A vector is by default used as a stack where an end marker is maintained and + * new elements are pushed right after this end marker (an indication of + * the size of the vector) after ensuring the vector is sufficiently large. + * + * A user should not store any pointer to vector elements as this might change + * during reallocations, but should use indices instead. + * + * NOTE: a maximum size is currently not implemented. + * + * It is freely inspired (and simplified) from the VPP infra infrastructure + * library. + */ + +#ifndef UTIL_VECTOR_H +#define UTIL_VECTOR_H + +#include <stdint.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> + +#include "common.h" + +/******************************************************************************/ +/* Vector header */ + +typedef struct { + size_t cur_size; /** Vector current size (corresponding to the highest used + element). */ + size_t alloc_size; /** The currently allocated size. */ + size_t max_size; /** The maximum allowed size (0 = no limit) */ +} vector_hdr_t; + +/* Make sure elements following the header are aligned */ +#define VECTOR_HDRLEN SIZEOF_ALIGNED(vector_hdr_t) + +/* This header actually prepends the actual content of the vector */ +#define vector_hdr(vector) ((vector_hdr_t *)((uint8_t *)vector - VECTOR_HDRLEN)) + +/******************************************************************************/ +/* Helpers */ + +/** Local variable naming macro. */ +#define _vector_var(v) _vector_##v + +/** + * @brief Allocate and initialize a vector data structure (helper function). + * + * @param[in,out] vector_ptr Vector to allocate and initialize. + * @param[in] elt_size Size of a vector element. + * @param[in] init_size Initial vector size. + * @param[in] max_size Maximum vector size (O = unlimited). + */ +void _vector_init(void **vector_ptr, size_t elt_size, size_t init_size, + size_t max_size); + +/** + * @brief Free a vector data structure. + * + * @param vector_ptr[in] Pointer to the vector data structure to free. + */ +void _vector_free(void **vector_ptr); + +/** + * @brief Resize a vector data structure. + * + * @param[in] vector_ptr A pointer to the vector data structure to resize. + * @param[in] elt_size The size of a vector element. + * @param[in] pos The position at which the vector should be able to hold an + * element. + * + * @return int Flag indicating whether the vector has been correctly resized. + * + * NOTE: + * - The resize operation does not specify the final size of the vector but + * instead ensure that it is large enough to hold an element at the specified + * position. This allows the caller not to care about doing successive calls to + * this API while the vector is growing in size. + */ +int _vector_resize(void **vector_ptr, size_t elt_size, off_t pos); + +/** + * @brief Ensures a vector is sufficiently large to hold an element at the + * given position. + * + * @param[in] vector_ptr A pointer to the vector data structure to resize. + * @param[in] elt_size The size of a vector element. + * @param[in] pos The position to validate. + * + * @return int Flag indicating whether the vector is available. + * + * NOTE: + * - This function should always be called before writing to a vector element + * to eventually make room for it (the vector will eventually be resized). + * - This function can fail if the vector is full and for any reason it cannot + * be resized. + */ +static inline int _vector_ensure_pos(void **vector_ptr, size_t elt_size, + off_t pos) { + vector_hdr_t *vh = vector_hdr(*vector_ptr); + if (pos >= (off_t)vh->alloc_size) + return _vector_resize(vector_ptr, elt_size, pos + 1); + return 0; +} + +/** + * @brief Push an element at the end of a vector. + * + * @param[in] vector_ptr A pointer to the vector data structure to resize. + * @param[in] elt_size The size of a vector element. + * @param[in] elt The element to insert. + * + * NOTE: + * - This function ensures there is sufficient room for inserting the element, + * and evenutually resizes the vector to make room for it (if allowed by + * maximum size). + */ +static inline int _vector_push(void **vector_ptr, size_t elt_size, void *elt) { + vector_hdr_t *vh = vector_hdr(*vector_ptr); + if (_vector_ensure_pos(vector_ptr, elt_size, vh->cur_size) < 0) return -1; + + /* Always get header after a potential resize */ + vh = vector_hdr(*vector_ptr); + memcpy((uint8_t *)*vector_ptr + vh->cur_size * elt_size, elt, elt_size); + vh = vector_hdr(*vector_ptr); + vh->cur_size++; + return 0; +} + +/** + * @brief Remove all the occurrencies of an element from the vector. + * The order of the elements is NOT maintained. + * + * @param[in, out] vector The vector data structure to resize + * @param[in] elt_size The size of a vector element + * @param[in] elt The element to remove + * @return int Number of elemets (equal to 'elt') removed from the vector + */ +static inline int _vector_remove_unordered(void *vector, size_t elt_size, + void *elt) { + size_t num_removed = 0; + vector_hdr_t *vh = vector_hdr(vector); + for (size_t i = 0; i < vector_hdr(vector)->cur_size; i++) { + if (memcmp((uint8_t *)vector + i * elt_size, elt, elt_size) == 0) { + vh->cur_size--; + memcpy((uint8_t *)vector + i * elt_size, + (uint8_t *)vector + vh->cur_size * elt_size, elt_size); + num_removed++; + } + } + return num_removed; +} + +/******************************************************************************/ +/* Public API */ + +/** + * @brief Allocate and initialize a vector data structure. + * + * @param[in,out] vector Vector to allocate and initialize. + * @param[in] init_size Initial vector size. + * @param[in] max_size Maximum vector size (nonzero). + * + * NOTE: + * - Allocated memory is set to 0 (used by bitmap) + */ + +#define vector_init(vector, init_size, max_size) \ + _vector_init((void **)&vector, sizeof(vector[0]), init_size, max_size) + +/** + * @brief Free a vector data structure. + * + * @param[in] vector The vector data structure to free. + */ +#define vector_free(vector) _vector_free((void **)&vector) + +/** + * @brief Resize a vector data structure. + * + * @param[in] vector The vector data structure to resize. + * @param[in] pos The position at which the vector should be able to hold an + * element. + * + * @return int Flag indicating whether the vector has been correctly resized. + * + * NOTE: + * - The resize operation does not specify the final size of the vector but + * instead ensure that it is large enough to hold an element at the specified + * position. This allows the caller not to care about doing successive calls to + * this API while the vector is growing in size. + * - If the new size is smaller than the current size, the content of the + * vector will be truncated. + * - Newly allocated memory is set to 0 (used by bitmap) + */ +#define vector_resize(vector) \ + _vector_resize((void **)&(vector), sizeof((vector)[0]), 0) + +/** + * @brief Ensures a vector is sufficiently large to hold an element at the + * given position. + * + * @param[in] vector The vector for which to validate the position. + * @param[in] pos The position to validate. + * + * NOTE: + * - This function should always be called before writing to a vector element + * to eventually make room for it (the vector will eventually be resized). + */ +#define vector_ensure_pos(vector, pos) \ + _vector_ensure_pos((void **)&(vector), sizeof((vector)[0]), pos); + +/** + * @brief Push an element at the end of a vector. + * + * @param[in] vector The vector in which to insert the element. + * @param[in] elt The element to insert. + * + * NOTE: + * - This function ensures there is sufficient room for inserting the element, + * and evenutually resizes the vector to make room for it (if allowed by + * maximum size). + */ +#define vector_push(vector, elt) \ + ({ \ + typeof(elt) x = elt; \ + _vector_push((void **)&(vector), sizeof((vector)[0]), (void *)(&x)); \ + }) + +/** + * @brief Remove all the occurrencies of an element from the vector. + * The order of the elements is NOT maintained. + * + * @param[in, out] vector The vector data structure to resize + * @param[in] elt The element to remove + * @return int Number of elemets (equal to 'elt') removed from the vector + */ +#define vector_remove_unordered(vector, elt) \ + ({ \ + typeof(elt) x = elt; \ + _vector_remove_unordered((void *)(vector), sizeof((vector)[0]), \ + (void *)(&x)); \ + }) + +/** + * @brief Returns the length of a vector. + * + * @param[in] vector The vector from which to get the size. + * + * @see vector_ensure_pos + * + * NOTE: + * - The size of the vector corresponds to the highest accessed index (for + * example as specified in the resize operation) and not the currently + * allocated size which will typically be bigger to amortize allocations. + * - A user should always call vector_ensure_pos to ensure the vector is + * sufficiently large to hold an element at the specified position. + */ +#define vector_len(vector) vector_hdr(vector)->cur_size + +/** + * @brief Returns the allocated size of a vector. + */ +#define vector_get_alloc_size(vector) vector_hdr(vector)->alloc_size + +/** + * @brief Iterate over elements in a vector. + * + * @param[in] pool The vector data structure to iterate over + * @param[in, out] eltp A pointer to the element that will be used for + * iteration + * @param[in] BODY Block to execute during iteration + * + * @note Iteration will execute BODY with eltp corresponding successively to all + * elements found in the vector. It is implemented using the more generic + * enumeration function. + */ +#define vector_foreach(vector, eltp, BODY) \ + ({ \ + unsigned _vector_var(i); \ + vector_enumerate((vector), _vector_var(i), (eltp), BODY); \ + }) + +/** + * @brief Helper function used by vector_foreach(). + */ +#define vector_enumerate(vector, i, eltp, BODY) \ + ({ \ + for ((i) = 0; (i) < vector_len(vector); (i)++) { \ + eltp = (vector) + (i); \ + { BODY; } \ + } \ + }) + +#endif /* UTIL_VECTOR_H */ diff --git a/hicn-light/src/hicn/cli/CMakeLists.txt b/hicn-light/src/hicn/cli/CMakeLists.txt new file mode 100644 index 000000000..39581e6ad --- /dev/null +++ b/hicn-light/src/hicn/cli/CMakeLists.txt @@ -0,0 +1,93 @@ +# Copyright (c) 2021-2022 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. + + +if (NOT DISABLE_EXECUTABLES) +############################################################## +# Force libhicn library to whole archive mode +############################################################## + if (APPLE) + set( + LIBHICN_LIGHT_WHOLE_ARCHIVE + "-Wl,-force_load" + "${LIBHICN_LIGHT_STATIC}" + ) + else() + set( + LIBHICN_LIGHT_WHOLE_ARCHIVE + "-Wl,--whole-archive" + "${LIBHICN_LIGHT_STATIC}" + "-Wl,--no-whole-archive" + ) + endif() + +############################################################## +# Sources +############################################################## + list(APPEND CONTROLLER_SRC + color.c + hicnc.c + ) + + +############################################################## +# Build hicn-light-control +############################################################## + build_executable(${HICN_LIGHT_CONTROL} + SOURCES ${CONTROLLER_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_WHOLE_ARCHIVE} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} + ) + + +############################################################## +# Build hicn-light-shell +############################################################## + list(APPEND SHELL_SRC + color.c + hicns.c + ) + + build_executable(${HICN_LIGHT_SHELL} + SOURCES ${SHELL_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_WHOLE_ARCHIVE} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} + ) + + +############################################################## +# Build hicn-light-shell +############################################################## + list(APPEND DAEMON_SRC + color.c + hicnd.c + ) + + # hicn-light-daemon does not compile under Android due to bindSocket + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android") + build_executable(${HICN_LIGHT_DAEMON} + SOURCES ${DAEMON_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_WHOLE_ARCHIVE} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} + ) + endif () +endif () diff --git a/hicn-light/src/hicn/cli/color.c b/hicn-light/src/hicn/cli/color.c new file mode 100644 index 000000000..aed22e302 --- /dev/null +++ b/hicn-light/src/hicn/cli/color.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <stdio.h> +#include "color.h" + +#ifndef _WIN32 + +void vprintfc(color_t color, const char* fmt, va_list ap) { + char* color_s; + switch (color) { +#define _(x, y, z) \ + case COLOR_##x: \ + color_s = y; \ + break; + foreach_color +#undef _ + + case COLOR_UNDEFINED : case COLOR_N : default : // XXX + color_s = ""; + break; + } + printf("%s", color_s); + vprintf(fmt, ap); +} +#else +void vprintfc(color_t color, const char* fmt, va_list ap) { + int color_id; + switch (color) { +#define _(x, y, z) \ + case COLOR_##x: \ + color_id = z; \ + break; + foreach_color +#undef _ + + case COLOR_UNDEFINED : case COLOR_N : color_id = 0; + break; + } + HANDLE hConsole = NULL; + WORD currentConsoleAttr; + CONSOLE_SCREEN_BUFFER_INFO csbi; + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + if (GetConsoleScreenBufferInfo(hConsole, &csbi)) + currentConsoleAttr = csbi.wAttributes; + if (color_id != 0) SetConsoleTextAttribute(hConsole, color_id); + fprintf("%s", color); + vfprintf(fmt, ap); + SetConsoleTextAttribute(hConsole, currentConsoleAttr); +} +#endif + +void printfc(color_t color, const char* fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vprintfc(color, fmt, ap); + va_end(ap); +} diff --git a/hicn-light/src/hicn/core/connectionState.h b/hicn-light/src/hicn/cli/color.h index 9daa15c9c..a9b71c047 100644 --- a/hicn-light/src/hicn/core/connectionState.h +++ b/hicn-light/src/hicn/cli/color.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,25 +13,30 @@ * limitations under the License. */ -/** - * @file connection_state.h - * @brief Represents the state of a connection - * - */ +#ifndef HICNLIGHT_COLOR +#define HICNLIGHT_COLOR -#ifndef connection_state_h -#define connection_state_h +#include <stdarg.h> -#define foreach_connection_state \ - _(UNDEFINED) \ - _(DOWN) \ - _(UP) \ - _(N) +/* + * Format : color_name, escape sequence, windows id + */ +#define foreach_color \ + _(RED, "\033[0;31m", 4) \ + _(WHITE, "\033[0m", 7) typedef enum { -#define _(x) CONNECTION_STATE_ ## x, -foreach_connection_state + COLOR_UNDEFINED, +#define _(x, y, z) COLOR_##x, + foreach_color #undef _ -} connection_state_t; + COLOR_N, +} color_t; + +#define IS_VALID_COLOR(color) ((color != COLOR_UNDEFINED) && (color != COLOR_N)) + +void vprintfc(color_t color, const char* fmt, va_list ap); + +void printfc(color_t color, const char* fmt, ...); -#endif /* connection_state_h */ +#endif /* HICNLIGHT_COLOR */ diff --git a/hicn-light/src/hicn/cli/hicnc.c b/hicn-light/src/hicn/cli/hicnc.c new file mode 100644 index 000000000..d14093b6b --- /dev/null +++ b/hicn-light/src/hicn/cli/hicnc.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <limits.h> // LONG_MAX, LONG_MIN +#include <signal.h> +#include <hicn/ctrl.h> + +#ifndef _WIN32 +#include <getopt.h> +#endif + +#include "color.h" +#include "../config/parse.h" +#include <hicn/util/log.h> +#include <hicn/util/sstrncpy.h> + +#define PORT 9695 + +static struct option longFormOptions[] = {{"help", no_argument, 0, 'h'}, + {"server", required_argument, 0, 'S'}, + {"port", required_argument, 0, 'P'}, + {0, 0, 0, 0}}; + +static void usage(char *prog) { + printf("%s: portable hICN forwarder\n", prog); + printf("\n"); + printf("Usage: %s COMMAND [PARAMETERS]\n", prog); + printf("\n"); + printf(" %s -h This help screen.\n", prog); + printf(" %s help Obtain a list of available commands.\n", prog); + printf("\n"); +} + +static bool stop = false; +void signal_handler(int sig) { + fprintf(stderr, "Received ^C... quitting !\n"); + stop = true; +} + +int main(int argc, char *const *argv) { + log_conf.log_level = LOG_INFO; + + // Handle termination signal + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigaction(SIGINT, &sa, NULL); + + /* Parse commandline */ + char *server_ip = NULL; + uint16_t server_port = 0; + + for (;;) { + // getopt_long stores the option index here. + int optind = 0; + + int c = getopt_long(argc, argv, "hS:P:", longFormOptions, &optind); + if (c == -1) break; + + switch (c) { + case 'S': + server_ip = optarg; + break; + + case 'P': { + char *endptr; + long val = strtol(optarg, &endptr, 10); + + errno = 0; /* To distinguish success/failure after call */ + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || + (errno != 0 && val == 0)) { + perror("strtol"); + exit(EXIT_FAILURE); + } + + if (endptr == optarg) { + fprintf(stderr, "No digits were found.\n"); + exit(EXIT_FAILURE); + } + + if (*endptr != '\0') { + fprintf(stderr, "Spurious characters after number: %s.\n", endptr); + exit(EXIT_FAILURE); + } + + if ((val < 1) || (val > 65535)) { + fprintf(stderr, "Invalid port number: %ld.\n", val); + exit(EXIT_FAILURE); + } + + server_port = val; + break; + } + + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + + default: + fprintf(stderr, "Invalid argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + /* Parse */ + char *param = argv[optind]; + for (; optind < argc - 1; optind++) { + char *arg = argv[optind]; + arg[strlen(arg)] = ' '; + } + + if (!param) { + usage(argv[0]); + goto ERR_PARAM; + } + + if (strncmp(param, "help", 4) == 0) { + if (help(param) < 0) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + + hc_command_t command = {}; + if (parse(param, &command) < 0) { + fprintf(stderr, "Error parsing command : '%s'\n", param); + goto ERR_PARSE; + } + + hc_sock_t *s; + if (server_ip) { + if (server_port == 0) server_port = PORT; +#define BUFSIZE 255 + char url[BUFSIZE]; + snprintf(url, BUFSIZE, "tcp://%s:%d/", server_ip, server_port); + s = hc_sock_create_forwarder_url(HICNLIGHT_NG, url); + } else { + s = hc_sock_create_forwarder(HICNLIGHT_NG); + } + if (!s) { + fprintf(stderr, "Could not create socket.\n"); + goto ERR_SOCK; + } + + if (hc_sock_connect(s) < 0) { + fprintf(stderr, "Could not establish connection to forwarder.\n"); + goto ERR_CONNECT; + } + + if (!IS_VALID_OBJECT_TYPE(command.object.type) || + !IS_VALID_ACTION(command.action)) { + fprintf(stderr, "Unsupported command"); + goto ERR_PARAM; + } + + int rc = UNSUPPORTED_CMD_ERROR; + hc_data_t *data = NULL; + char buf_listener[MAXSZ_HC_LISTENER]; + char buf_connection[MAXSZ_HC_CONNECTION]; + char buf_route[MAXSZ_HC_ROUTE]; + char buf[MAX_LEN]; + switch (command.object.type) { + case OBJECT_ROUTE: + switch (command.action) { + case ACTION_CREATE: + rc = hc_route_create(s, &command.object.route); + break; + + case ACTION_DELETE: + rc = hc_route_delete(s, &command.object.route); + break; + + case ACTION_LIST: + rc = hc_route_list(s, &data); + if (rc < 0) break; + + INFO("Routes:"); + foreach_route(r, data) { + if (hc_route_snprintf(buf_route, MAXSZ_HC_ROUTE, r) >= + MAXSZ_HC_ROUTE) + ERROR("Display error"); + INFO("%s", buf_route); + } + break; + + default: + break; + } + break; + + case OBJECT_LISTENER: + switch (command.action) { + case ACTION_CREATE: + rc = hc_listener_create(s, &command.object.listener); + break; + + case ACTION_DELETE: + rc = hc_listener_delete(s, &command.object.listener); + break; + + case ACTION_LIST: + rc = hc_listener_list(s, &data); + if (rc < 0) break; + + INFO("Listeners:"); + foreach_listener(l, data) { + if (hc_listener_snprintf(buf_listener, MAXSZ_HC_LISTENER + 17, l) >= + MAXSZ_HC_LISTENER) + ERROR("Display error"); + INFO("[%d] %s", l->id, buf_listener); + } + break; + + default: + break; + } + break; + + case OBJECT_CONNECTION: + switch (command.action) { + case ACTION_CREATE: + rc = hc_connection_create(s, &command.object.connection); + break; + + case ACTION_DELETE: + rc = hc_connection_delete(s, &command.object.connection); + break; + + case ACTION_LIST: + rc = hc_connection_list(s, &data); + if (rc < 0) break; + + INFO("Connections:"); + foreach_connection(c, data) { + if (hc_connection_snprintf(buf_connection, MAXSZ_HC_CONNECTION, + c) >= MAXSZ_HC_CONNECTION) + ERROR("Display error"); + INFO("[%d] %s", c->id, buf_connection); + } + break; + + default: + break; + } + break; + + case OBJECT_CACHE: + switch (command.action) { + case ACTION_SERVE: + rc = hc_cache_set_serve(s, &command.object.cache); + break; + + case ACTION_STORE: + rc = hc_cache_set_store(s, &command.object.cache); + break; + + case ACTION_CLEAR: + rc = hc_cache_clear(s, &command.object.cache); + break; + + case ACTION_LIST: + rc = hc_cache_list(s, &data); + if (rc < 0) break; + + hc_cache_snprintf(buf, MAX_LEN, (hc_cache_info_t *)data->buffer); + printf("%s\n", buf); + break; + + default: + break; + } + break; + + case OBJECT_STRATEGY: + switch (command.action) { + case ACTION_SET: + rc = hc_strategy_set(s, &command.object.strategy); + break; + + default: + break; + } + break; + + case OBJECT_MAPME: + switch (command.action) { + case ACTION_UPDATE: + rc = hc_mapme_send_update(s, &command.object.mapme); + break; + case ACTION_SET: + if (command.object.mapme.target == MAPME_TARGET_ENABLE) { + rc = hc_mapme_set(s, &command.object.mapme); + } else if (command.object.mapme.target == MAPME_TARGET_DISCOVERY) { + rc = hc_mapme_set_discovery(s, &command.object.mapme); + } else if (command.object.mapme.target == MAPME_TARGET_TIMESCALE) { + rc = hc_mapme_set_timescale(s, &command.object.mapme); + } else if (command.object.mapme.target == MAPME_TARGET_RETX) { + rc = hc_mapme_set_retx(s, &command.object.mapme); + } + break; + + default: + break; + } + break; + + case OBJECT_LOCAL_PREFIX: + switch (command.action) { + case ACTION_CREATE: + rc = hc_strategy_add_local_prefix(s, &command.object.strategy); + break; + + default: + break; + } + break; + + case OBJECT_SUBSCRIPTION: + // Disable socket recv timeout + hc_sock_set_recv_timeout_ms(s, 0); + + rc = hc_subscription_create(s, &command.object.subscription); + if (rc < 0) break; + INFO("Subscription sent"); + + while (!stop) { + int rc = hc_sock_callback(s, &data); + if (rc < 0 && !stop) ERROR("Notification error"); + + if (!stop) { + event_type_t event_type = rc; + INFO("Notification recevied %s [%d]", event_str(event_type), + event_type); + + if (event_type == EVENT_INTERFACE_UPDATE) { + hc_event_interface_update_t *event = + (hc_event_interface_update_t *)(data->buffer); + INFO("Interface update event received: %u", event->interface_type); + } + } + } + + INFO("Unsubscribing..."); + rc = hc_subscription_delete(s, &command.object.subscription); + break; + + default: + break; + } + hc_data_free(data); + + if (rc < -1) { + if (rc == INPUT_ERROR) ERROR("Wrong input parameters"); + if (rc == UNSUPPORTED_CMD_ERROR) ERROR("Unsupported command"); + goto ERR_CMD; + } + if (rc < 0) ERROR("Error executing command"); + + // Remove the connection created to send the command + command.object.connection.id = 0; + rc = strcpy_s(command.object.connection.name, + sizeof(command.object.connection.name), "SELF"); + if (rc != EOK || hc_connection_delete(s, &command.object.connection) < 0) + fprintf(stderr, "Error removing local connection to forwarder\n"); + + exit(EXIT_SUCCESS); + +ERR_CMD: +ERR_CONNECT: + hc_sock_free(s); +ERR_SOCK: +ERR_PARSE: +ERR_PARAM: + exit(EXIT_FAILURE); +} diff --git a/hicn-light/src/hicn/cli/hicnd.c b/hicn-light/src/hicn/cli/hicnd.c new file mode 100644 index 000000000..e73517e4c --- /dev/null +++ b/hicn-light/src/hicn/cli/hicnd.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2021 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 _WIN32 +#include <unistd.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include <hicn/util/log.h> + +#include "logo.h" +#include "../base/loop.h" +#include "../core/forwarder.h" +#include "../config/configuration.h" // XXX needed ? +#include "../config/configuration_file.h" + +static void usage(const char *prog) { + printf( + "Usage: %s [--port port]" +#ifndef _WIN32 + " [--daemon]" +#endif + " [--capacity objectStoreSize] [--log level]" + "[--log-file filename] [--config file]\n", + prog); + printf("\n"); + printf( + "hicn-light run as a daemon is the program to launch the forwarder, " + "either as a console program\n"); + printf( + "or a background daemon (detatched from console). Once running, use the " + "program controller to\n"); + printf("configure hicn-light.\n"); + printf("\n"); + printf( + "The configuration file contains configuration lines as per " + "controller\n"); + printf( + "If logging level or content store capacity is set in the configuraiton " + "file, it overrides the command_line\n"); + printf( + "When a configuration file is specified, no default listeners on 'port' " + "are setup. Only 'add listener' lines\n"); + printf("in the configuration file matter.\n"); + printf("\n"); + printf( + "If no configuration file is specified, daemon will listen on TCP and " + "UDP ports specified by\n"); + printf( + "the --port flag (or default port). It will listen on both IPv4 and " + "IPv6 if available.\n"); + printf("\n"); + printf("Options:\n"); + printf("%-30s = tcp port for in-bound connections\n", "--port <tcp_port>"); +#ifndef _WIN32 + printf("%-30s = start as daemon process\n", "--daemon"); +#endif + printf( + "%-30s = maximum number of content objects to cache. To disable the " + "cache objectStoreSize must be 0.\n", + "--capacity <objectStoreSize>"); + printf("%-30s Default vaule for objectStoreSize is 100000\n", ""); + printf( + "%-30s = sets the log level. Available levels: trace, debug, info, warn, " + "error, fatal\n", + "--log <level>"); + printf("%-30s = file to write log messages to (required in daemon mode)\n", + "--log-file <output_logfile>"); + printf("%-30s = configuration filename\n", "--config <config_path>"); + printf("\n"); +} + +#ifndef _WIN32 +static int daemonize(int logfile_fd) { + /* Check whether we already are a daemon */ + if (getppid() == 1) return 0; + + int rc = fork(); + if (rc < 0) { + ERROR("Fork error"); + goto ERR_FORK; + } else if (rc > 0) { + /* Parent exits successfully */ + exit(EXIT_SUCCESS); + } + + /* Child daemon detaches */ + DEBUG("child continuing, pid = %u\n", getpid()); + + /* get a new process group independent from old parent */ + setsid(); + + /* close all descriptors (apart from the logfile) */ +#ifdef __ANDROID__ + for (int i = sysconf(_SC_OPEN_MAX); i >= 0; --i) close(i); +#else + for (int i = getdtablesize(); i >= 0; --i) { + if (i != logfile_fd) close(i); + } +#endif + + /* + * Reset errno because it might be seg to EBADF from the close calls above + */ + errno = 0; + /* Redirect stdin and stdout and stderr to /dev/null */ + const char *devnull = "/dev/null"; + int nullfile = open(devnull, O_RDWR); + if (nullfile < 0) { + ERROR("Error opening file '%s': (%d) %s", devnull, errno, strerror(errno)); + goto ERR_DEVNULL; + } + + /* Redirect stdout and stderr to the logfile */ + rc = dup2(logfile_fd, STDOUT_FILENO); + if (rc != STDOUT_FILENO) { + ERROR("Error duping fd 1 got %d file: (%d) %s", rc, errno, strerror(errno)); + goto ERR_DUP1; + } + rc = dup2(logfile_fd, STDERR_FILENO); + if (rc != STDERR_FILENO) { + ERROR("Error duping fd 2 got %d file: (%d) %s", rc, errno, strerror(errno)); + goto ERR_DUP2; + } + + /* Forwarder will capture signals */ + return 0; + +ERR_DUP2: +ERR_DUP1: +ERR_DEVNULL: +ERR_FORK: + return -1; +} +#endif + +static void signal_cb(int sig) { + switch (sig) { + case SIGTERM: + case SIGINT: + INFO("caught an interrupt signal, exiting cleanly"); + break; +#ifndef _WIN32 + case SIGUSR1: + // dump stats + break; +#endif + default: + break; + } + + if (loop_break(MAIN_LOOP) < 0) { + ERROR("Failed to terminate main loop"); + _exit(1); + } +} + +static void signal_setup() { +#ifndef _WIN32 + signal(SIGUSR1, signal_cb); + + /* ignore child */ + signal(SIGCHLD, SIG_IGN); + + /* ignore tty signals */ + signal(SIGTSTP, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); +#endif + signal(SIGINT, signal_cb); + signal(SIGTERM, signal_cb); +} + +configuration_t *parse_commandline(int argc, const char *argv[]) { + if (argc == 2 && strcasecmp(argv[1], "-h") == 0) { + usage(argv[0]); + exit(EXIT_SUCCESS); // XXX redundant + } + + configuration_t *configuration = configuration_create(); + + // XXX use getoptlong ???? + for (int i = 0; i < argc; i++) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--config") == 0) { + const char *fn_config = argv[i + 1]; + configuration_set_fn_config(configuration, fn_config); + i++; + } else if (strcmp(argv[i], "--port") == 0) { + uint16_t port = atoi(argv[i + 1]); + configuration_set_port(configuration, port); + i++; +#ifndef _WIN32 + } else if (strcmp(argv[i], "--daemon") == 0) { + configuration_set_daemon(configuration, true); +#endif + } else if (strcmp(argv[i], "--capacity") == 0 || + strcmp(argv[i], "-c") == 0) { + int capacity = atoi(argv[i + 1]); + configuration_set_cs_size(configuration, capacity); + i++; + } else if (strcmp(argv[i], "--log") == 0) { + int loglevel = loglevel_from_str(argv[i + 1]); + configuration_set_loglevel(configuration, loglevel); + i++; + } else if (strcmp(argv[i], "--log-file") == 0) { + if (configuration_get_logfile(configuration)) { + fprintf(stderr, "Cannot specify --log-file more than once\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + const char *logfile = argv[i + 1]; + configuration_set_logfile(configuration, logfile); + i++; + } else { + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + } + + return configuration; +} + +int main(int argc, const char *argv[]) { + signal_setup(); + logo(); + + configuration_t *configuration = parse_commandline(argc, argv); + const char *logfile = configuration_get_logfile(configuration); + bool daemon = configuration_get_daemon(configuration); + + // set restrictive umask, in case we create any files + umask(027); + +#ifndef _WIN32 + if (daemon && (logfile == NULL)) { + fprintf(stderr, "Must specify a logfile when running in daemon mode\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* In daemon mode, parent will exit and child will continue */ + if (daemon && daemonize(configuration_get_logfile_fd(configuration)) < 0) { + ERROR("Could not daemonize process"); + exit(EXIT_FAILURE); + } +#endif + + /* + * The loop should be created before the forwarder instance as it is needed + * for timers + */ + MAIN_LOOP = loop_create(); + + forwarder_t *forwarder = forwarder_create(configuration); + if (!forwarder) { + ERROR( + "Forwarder initialization failed. Are you running it with sudo " + "privileges?"); + return -1; + } + + forwarder_setup_local_listeners(forwarder, + configuration_get_port(configuration)); + + /* If specified, process the configuration file */ + const char *fn_config = configuration_get_fn_config(configuration); + if (fn_config) configuration_file_process(forwarder, fn_config); + INFO("%s running port %d configuration-port %d", argv[0], + configuration_get_port(configuration), + configuration_get_configuration_port(configuration)); + + /* Main loop */ + if (loop_dispatch(MAIN_LOOP) < 0) { + ERROR("Failed to run main loop"); + return EXIT_FAILURE; + } + + INFO("loop stopped"); + forwarder_free(forwarder); + loop_free(MAIN_LOOP); + MAIN_LOOP = NULL; + +#ifdef _WIN32 + WSACleanup(); // XXX why is this needed here ? +#endif + + configuration_flush_log(); + return 0; +} diff --git a/hicn-light/src/hicn/cli/hicns.c b/hicn-light/src/hicn/cli/hicns.c new file mode 100644 index 000000000..2f7a360f8 --- /dev/null +++ b/hicn-light/src/hicn/cli/hicns.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <limits.h> // LONG_MAX, LONG_MIN +#include <hicn/ctrl.h> + +#ifndef _WIN32 +#include <getopt.h> +#endif + +#include "logo.h" +#include "../config/parse.h" +#include <hicn/util/sstrncpy.h> + +#define PORT 9695 + +static struct option longFormOptions[] = {{"help", no_argument, 0, 'h'}, + {"server", required_argument, 0, 'S'}, + {"port", required_argument, 0, 'P'}, + {0, 0, 0, 0}}; + +static void usage(char *prog) { + printf("%s: interactive shell for hicn-light\n", prog); + printf("\n"); + printf("Usage: %s", prog); + printf("\n"); + printf(" %s -h This help screen.\n", prog); + printf("\n"); +} + +void prompt(void) { + fputs("hicn> ", stdout); + fflush(stdout); +} + +int shell(hc_sock_t *s) { + char *line = NULL; + size_t len = 0; + hc_data_t *data = NULL; + ssize_t nread; + + hc_data_t *connections; + + prompt(); + while ((nread = getline(&line, &len, stdin)) != -1) { + hc_command_t command = {0}; + + char *pos; + if ((pos = strchr(line, '\n')) != NULL) { + *pos = '\0'; + } else { + fprintf(stderr, "Error while reading command.\n"); + goto CONTINUE; + } + + if (strlen(line) == 0) goto CONTINUE; + + if (strncmp(line, "exit", 4) == 0) break; + if (strncmp(line, "quit", 4) == 0) break; + + if (parse(line, &command) < 0) { + fprintf(stderr, "Unknown command '%s'\n", line); + goto CONTINUE; + } + + /* XXX connection list */ + if (hc_connection_list(s, &connections) < 0) { + fprintf(stderr, "Error running command.\n"); + goto CONTINUE; + } + // data = command.object.data; + + char buf[MAXSZ_HC_CONNECTION]; // XXX + foreach_connection(c, data) { + /* XXX connection print */ + int rc = hc_connection_snprintf(buf, MAXSZ_HC_CONNECTION, c); + if (rc < 0) { + strcpy_s(buf, sizeof(buf), "(Error)"); + } else if (rc >= MAXSZ_HC_CONNECTION) { + buf[MAXSZ_HC_CONNECTION - 1] = '\0'; + buf[MAXSZ_HC_CONNECTION - 2] = '.'; + buf[MAXSZ_HC_CONNECTION - 3] = '.'; + buf[MAXSZ_HC_CONNECTION - 4] = '.'; + } + printf("%s\n", buf); + } + + hc_data_free(data); + CONTINUE: + prompt(); + } + + return 0; +} + +int main(int argc, char *const *argv) { + logo(); + printf("Type 'help' for a list of available commands\n"); + printf("\n"); + printf("\n"); + + /* Parse commandline */ + char *server_ip = NULL; + uint16_t server_port = 0; + + for (;;) { + // getopt_long stores the option index here. + int optind = 0; + + int c = getopt_long(argc, argv, "hS:P:", longFormOptions, &optind); + if (c == -1) break; + + switch (c) { + case 'S': + server_ip = optarg; + break; + + case 'P': { + char *endptr; + long val = strtol(optarg, &endptr, 10); + + errno = 0; /* To distinguish success/failure after call */ + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || + (errno != 0 && val == 0)) { + perror("strtol"); + exit(EXIT_FAILURE); + } + + if (endptr == optarg) { + fprintf(stderr, "No digits were found.\n"); + exit(EXIT_FAILURE); + } + + if (*endptr != '\0') { + fprintf(stderr, "Spurious characters after number: %s.\n", endptr); + exit(EXIT_FAILURE); + } + + if ((val < 1) || (val > 65535)) { + fprintf(stderr, "Invalid port number: %ld.\n", val); + exit(EXIT_FAILURE); + } + + server_port = (uint16_t)val; + break; + } + + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + + default: + fprintf(stderr, "Invalid argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + if (optind != argc) { + fprintf(stderr, "Invalid parameters.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + hc_sock_t *s; + if (server_ip) { + if (server_port == 0) server_port = PORT; +#define BUFSIZE 255 + char url[BUFSIZE]; + snprintf(url, BUFSIZE, "tcp://%s:%d/", server_ip, server_port); + s = hc_sock_create_forwarder_url(HICNLIGHT_NG, url); + } else { + s = hc_sock_create_forwarder(HICNLIGHT_NG); + } + if (!s) { + fprintf(stderr, "Could not create socket.\n"); + goto ERR_SOCK; + } + + if (hc_sock_connect(s) < 0) { + fprintf(stderr, "Could not establish connection to forwarder.\n"); + goto ERR_CONNECT; + } + + int rc = shell(s); + + exit((rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS); + +ERR_CONNECT: + hc_sock_free(s); +ERR_SOCK: + exit(EXIT_FAILURE); +} diff --git a/hicn-light/src/hicn/cli/logo.h b/hicn-light/src/hicn/cli/logo.h new file mode 100644 index 000000000..a69097f91 --- /dev/null +++ b/hicn-light/src/hicn/cli/logo.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 HICNLIGHT_LOGO +#define HICNLIGHT_LOGO + +#include "color.h" + +static void logo(void) { + printfc(COLOR_RED, " ____ ___ _ "); + printfc(COLOR_WHITE, " __ _ __ _ __ __\n"); + printfc(COLOR_RED, " / __// _ \\ (_)___ "); + printfc(COLOR_WHITE, " / / (_)____ ___ ____/ /(_)___ _ / / / /_\n"); + printfc(COLOR_RED, " / _/ / // /_ / // _ \\ "); + printfc(COLOR_WHITE, " / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"); + printfc(COLOR_RED, "/_/ /____/(_)/_/ \\___/ "); + printfc(COLOR_WHITE, "/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n"); + printfc( + COLOR_WHITE, + " /___/ " + "\n"); + printf("\n"); +} + +#endif /* HICNLIGHT_LOGO */ diff --git a/hicn-light/src/hicn/command_line/CMakeLists.txt b/hicn-light/src/hicn/command_line/CMakeLists.txt deleted file mode 100644 index 16c23dc5c..000000000 --- a/hicn-light/src/hicn/command_line/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(controller) -add_subdirectory(daemon) diff --git a/hicn-light/src/hicn/command_line/controller/CMakeLists.txt b/hicn-light/src/hicn/command_line/controller/CMakeLists.txt deleted file mode 100644 index 4cbd49220..000000000 --- a/hicn-light/src/hicn/command_line/controller/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2017-2019 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. - -list(APPEND CONTROLLER_SRC - hicnLightControl_main.c -) - -if (WIN32) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:\"LIBCMT\"" ) -endif() - -if (NOT DISABLE_EXECUTABLES) - if (${CMAKE_SYSTEM_NAME} MATCHES Android) - set(LINK_FLAGS "-Wl,--unresolved-symbols=ignore-in-object-files") - endif() - - build_executable(${HICN_LIGHT_CONTROL} - SOURCES ${CONTROLLER_SRC} - LINK_LIBRARIES ${LIBHICN_LIGHT_STATIC} - DEPENDS ${LIBHICN_LIGHT_STATIC} - COMPONENT ${HICN_LIGHT} - DEFINITIONS ${COMPILER_DEFINITIONS} - LINK_FLAGS ${LINK_FLAGS} - ) -endif () diff --git a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c b/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c deleted file mode 100644 index e6a97c4e2..000000000 --- a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <hicn/utils/utils.h> - - -#ifndef _WIN32 -#include <arpa/inet.h> -#include <getopt.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/uio.h> -#include <unistd.h> -#include <arpa/inet.h> -#endif -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> -#include <string.h> - -#include <parc/security/parc_IdentityFile.h> -#include <parc/security/parc_Security.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_List.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_SafeMemory.h> - -#include <hicn/core/dispatcher.h> -#include <hicn/core/forwarder.h> - -#include <errno.h> -#include <hicn/config/controlRoot.h> -#include <hicn/config/controlState.h> - -#include <hicn/utils/commands.h> - - - -size_t commandOutputLen = 0; // preserve the number of structs composing - // payload in case on not interactive call. - -// REMINDER: when a new_command is added, the following array has to be updated -// with the sizeof(new_command). It allows to allocate the buffer for receiving -// the payload of the DAEMON RESPONSE after the header has beed read. Each -// command identifier (typedef enum command_id) corresponds to a position in the -// following array. -static int payloadLengthController[LAST_COMMAND_VALUE] = { - sizeof(add_listener_command), - sizeof(add_connection_command), - sizeof(list_connections_command), // needed when get response from FWD - sizeof(add_route_command), - sizeof(list_routes_command), // needed when get response from FWD - sizeof(remove_connection_command), - sizeof(remove_listener_command), - sizeof(remove_route_command), - sizeof(cache_store_command), - sizeof(cache_serve_command), - 0, // cache clear - sizeof(set_strategy_command), - sizeof(set_wldr_command), - sizeof(add_punting_command), - sizeof(list_listeners_command), // needed when get response from FWD - sizeof(mapme_activator_command), - sizeof(mapme_activator_command), - sizeof(mapme_timing_command), - sizeof(mapme_timing_command), - sizeof(mapme_send_update_command), - sizeof(connection_set_admin_state_command), -#ifdef WITH_POLICY - sizeof(add_policy_command), - sizeof(list_policies_command), - sizeof(remove_policy_command), - sizeof(update_connection_command), - sizeof(connection_set_priority_command), - sizeof(connection_set_tags_command), -#endif -}; - -typedef struct controller_main_state { - ControlState *controlState; -} ControlMainState; - -static void _printRed(const char *output) { -#ifndef _WIN32 - printf("\033[0;31m%s", output); -#else - HANDLE hConsole = NULL; - WORD currentConsoleAttr; - CONSOLE_SCREEN_BUFFER_INFO csbi; - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) - currentConsoleAttr = csbi.wAttributes; - SetConsoleTextAttribute(hConsole, 4); - printf("%s", output); - SetConsoleTextAttribute(hConsole, currentConsoleAttr); -#endif -} - -static void _printWhite(const char *output) { -#ifndef _WIN32 - printf("\033[0m%s", output); -#else - HANDLE hConsole = NULL; - WORD currentConsoleAttr; - CONSOLE_SCREEN_BUFFER_INFO csbi; - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) - currentConsoleAttr = csbi.wAttributes; - SetConsoleTextAttribute(hConsole, 7); - printf("%s", output); - SetConsoleTextAttribute(hConsole, currentConsoleAttr); -#endif -} - -static void _displayForwarderLogo(void) { - _printRed(" ____ ___ _ "); - _printWhite(" __ _ __ _ __ __\n"); - _printRed(" / __// _ \\ (_)___ "); - _printWhite(" / / (_)____ ___ ____/ /(_)___ _ / / / /_\n"); - _printRed(" / _/ / // /_ / // _ \\ "); - _printWhite(" / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"); - _printRed("/_/ /____/(_)/_/ \\___/ "); - _printWhite("/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n"); - _printWhite( - " /___/ " - "\n"); - printf("\n"); -} - -static void _displayUsage(char *programName) { - printf("Usage: %s -h\n", programName); - printf( - "hicn-light is the 1.0 source, which runs on each end system and as a " - "software source\n"); - printf( - "on intermediate systems. controller is the program to configure the " - "source, daemon.\n"); - printf("\n"); - printf("Options:\n"); - printf("-h = This help screen\n"); - printf( - "commands = configuration line to send to hicn-light (use 'help' " - "for list)\n"); - printf("\n"); -} - -static int _parseArgs(int argc, char *argv[], char **server_ip, - uint16_t *server_port, PARCList *commandList){ - static struct option longFormOptions[] = { - {"help", no_argument, 0, 'h'}, - {"server", required_argument, 0, 'S'}, - {"port", required_argument, 0, 'P'}, - {0, 0, 0, 0}}; - - int c; - - while (1) { - // getopt_long stores the option index here. - int optionIndex = 0; - - c = getopt_long(argc, argv, "hS:P:", longFormOptions, &optionIndex); - - // Detect the end of the options. - if (c == -1) { - break; - } - - switch (c) { - case 'S': - { - *server_ip = optarg; - struct sockaddr_in sa; - int result = inet_pton(AF_INET, *server_ip, &(sa.sin_addr)); - //inet_pton() returns 1 on success - if(result != 1){ - return 0; - } - break; - } - case 'P': - { - char * port_str = optarg; - if(utils_IsNumber(port_str)){ - *server_port = (uint16_t) strtol(port_str, NULL, 10); - } else { - return 0; - } - break; - } - case 'h': - default: - return 0; - } - } - - if (optind < argc) { - while (optind < argc) { - parcList_Add(commandList, argv[optind]); - optind++; - } - } - - return 1; -} - -struct iovec *_writeAndReadMessage(ControlState *state, struct iovec *msg) { - parcAssertNotNull(msg, "Parameter msg must be non-null"); - int sockfd = controlState_GetSockfd(state); - - // check if request has a payload - if (((header_control_message *)msg[0].iov_base)->length > - 0) { // command with payload - // write header + payload (compatibility issue: two write needed instead of - // the writev) -#ifndef _WIN32 - if (write(sockfd, msg[0].iov_base, (unsigned int)msg[0].iov_len) < 0 || - write(sockfd, msg[1].iov_base, (unsigned int)msg[1].iov_len) < 0) { -#else - if (send(sockfd, msg[0].iov_base, (int)msg[0].iov_len, 0) == SOCKET_ERROR || - send(sockfd, msg[1].iov_base, (int)msg[1].iov_len, 0) == SOCKET_ERROR) { -#endif - printf("\nError while sending the Message: cannot write on socket \n"); - exit(EXIT_FAILURE); - } - parcMemory_Deallocate(&msg[1].iov_base); - } else { // command without payload, e.g. 'list' - // write header only -#ifndef _WIN32 - if (write(sockfd, msg[0].iov_base, msg[0].iov_len) < 0) { -#else - int result = send(sockfd, msg[0].iov_base, (int)msg[0].iov_len, 0); - if (result == SOCKET_ERROR) { -#endif - printf("\nError while sending the Message: cannot write on socket \n"); - exit(EXIT_FAILURE); - } - } - parcMemory_Deallocate(&msg[0].iov_base); - - // ======= RECEIVE ======= - - header_control_message *headerResponse = - (header_control_message *)parcMemory_AllocateAndClear( - sizeof(header_control_message)); - if (recv(sockfd, (char *)headerResponse, sizeof(header_control_message), 0) < - 0) { - printf("\nError in Receiving the Message \n"); - exit(EXIT_FAILURE); - } - - if (headerResponse->messageType < RESPONSE_LIGHT || - headerResponse->messageType >= LAST_MSG_TYPE_VALUE) { - char *checkFinMsg = parcMemory_Reallocate(headerResponse, 32); -#ifndef _WIN32 - if (recv(sockfd, checkFinMsg, sizeof(checkFinMsg), - MSG_PEEK | MSG_DONTWAIT) == 0) { -#else - if (recv(sockfd, checkFinMsg, sizeof(checkFinMsg), MSG_PEEK) == 0) { -#endif - // if recv returns zero, that means the connection has been closed: - close(sockfd); - printf("\nConnection terminated by the Daemon. Exiting... \n"); - exit(EXIT_SUCCESS); - } else { - printf("\nError: Unrecognized message type received \n"); - exit(EXIT_FAILURE); - } - } - - void *payloadResponse = NULL; - - if ((commandOutputLen = headerResponse->length) > 0) { - payloadResponse = parcMemory_AllocateAndClear( - payloadLengthController[headerResponse->commandID] * - headerResponse->length); - - if (recv(sockfd, payloadResponse, - payloadLengthController[headerResponse->commandID] * - headerResponse->length, - 0) < 0) { - printf("\nError in Receiving the Message \n"); - exit(EXIT_FAILURE); - } - } - - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); - - response[0].iov_base = headerResponse; - response[0].iov_len = sizeof(header_control_message); - response[1].iov_base = payloadResponse; - response[1].iov_len = payloadLengthController[headerResponse->commandID] * - headerResponse->length; - - return response; -} - -int main(int argc, char *argv[]) { - _displayForwarderLogo(); - -#ifdef _WIN32 - WSADATA wsaData; - WSAStartup(MAKEWORD(2, 2), &wsaData); -#endif - - if (argc == 2 && strcmp("-h", argv[1]) == 0) { - _displayUsage(argv[0]); - exit(EXIT_SUCCESS); - } - - PARCList *commands = - parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); - - char *server_ip = SRV_CTRL_IP; - uint16_t server_port = SRV_CTRL_PORT; - if (!_parseArgs(argc, argv, &server_ip, - &server_port, commands)) { - _displayUsage(argv[0]); - parcList_Release(&commands); - exit(EXIT_FAILURE); - } - - ControlMainState mainState; - mainState.controlState = - controlState_Create(&mainState, _writeAndReadMessage, true, - server_ip, server_port); - if (mainState.controlState == NULL) { - exit(EXIT_FAILURE); - } - - controlState_RegisterCommand(mainState.controlState, - controlRoot_HelpCreate(mainState.controlState)); - controlState_RegisterCommand(mainState.controlState, - controlRoot_Create(mainState.controlState)); - - if (parcList_Size(commands) > 0) { - controlState_SetInteractiveFlag(mainState.controlState, false); - char output[8192]; - controlState_DispatchCommand(mainState.controlState, commands, output, sizeof(output)); - printf("%s", output); - char **commandOutputMain = - controlState_GetCommandOutput(mainState.controlState); - if (commandOutputMain != NULL && commandOutputLen > 0) { -#if 0 - for (size_t j = 0; j < commandOutputLen; j++) { - printf("Output %zu: %s \n", j, commandOutputMain[j]); - } -#endif - controlState_ReleaseCommandOutput(mainState.controlState, - commandOutputMain, commandOutputLen); - } - // release - - } else { - controlState_Interactive(mainState.controlState); - } - - parcList_Release(&commands); - - controlState_Destroy(&mainState.controlState); -#ifdef _WIN32 - WSACleanup(); -#endif - return EXIT_SUCCESS; -} diff --git a/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c b/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c deleted file mode 100644 index ab7039f5e..000000000 --- a/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 _WIN32 -#include <unistd.h> -#endif -#include <errno.h> -#include <fcntl.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> - -#include <hicn/hicn-light/config.h> -#include <parc/algol/parc_FileOutputStream.h> -#include <parc/logging/parc_LogLevel.h> -#include <parc/logging/parc_LogReporterFile.h> -#include <parc/logging/parc_LogReporterTextStdout.h> - -#include <parc/assert/parc_Assert.h> - -#include <hicn/core/dispatcher.h> -#include <hicn/core/forwarder.h> - -static void _printRed(const char *output) { -#ifndef _WIN32 - printf("\033[0;31m%s", output); -#else - HANDLE hConsole = NULL; - WORD currentConsoleAttr; - CONSOLE_SCREEN_BUFFER_INFO csbi; - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) - currentConsoleAttr = csbi.wAttributes; - SetConsoleTextAttribute(hConsole, 4); - printf("%s", output); - SetConsoleTextAttribute(hConsole, currentConsoleAttr); -#endif -} - -static void _printWhite(const char *output) { -#ifndef _WIN32 - printf("\033[0m%s", output); -#else - HANDLE hConsole = NULL; - WORD currentConsoleAttr; - CONSOLE_SCREEN_BUFFER_INFO csbi; - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) - currentConsoleAttr = csbi.wAttributes; - SetConsoleTextAttribute(hConsole, 7); - printf("%s", output); - SetConsoleTextAttribute(hConsole, currentConsoleAttr); -#endif -} - -static void _displayForwarderLogo(void) { - _printRed(" ____ ___ _ "); - _printWhite(" __ _ __ _ __ __\n"); - _printRed(" / __// _ \\ (_)___ "); - _printWhite(" / / (_)____ ___ ____/ /(_)___ _ / / / /_\n"); - _printRed(" / _/ / // /_ / // _ \\ "); - _printWhite(" / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"); - _printRed("/_/ /____/(_)/_/ \\___/ "); - _printWhite("/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n"); - _printWhite( - " /___/ " - "\n"); - printf("\n"); -} - -static void _usage(int exitCode) { -#ifndef _WIN32 - printf( - "Usage: hicn-light-daemon [--port port] [--capacity objectStoreSize] " - "[--log facility=level] [--log-file filename] [--config file]\n"); -#else - printf( - "Usage: hicn-light-daemon.exe [--port port] [--daemon] [--capacity objectStoreSize] " - "[--log facility=level] [--log-file filename] [--config file]\n"); -#endif - printf("\n"); - printf( - "hicn-light run as a daemon is the program to launch the forwarder, " - "either as a console program\n"); - printf( - "or a background daemon (detatched from console). Once running, use the " - "program controller to\n"); - printf("configure hicn-light.\n"); - printf("\n"); - printf( - "The configuration file contains configuration lines as per " - "controller\n"); - printf( - "If logging level or content store capacity is set in the configuraiton " - "file, it overrides the command_line\n"); - printf( - "When a configuration file is specified, no default listeners on 'port' " - "are setup. Only 'add listener' lines\n"); - printf("in the configuration file matter.\n"); - printf("\n"); - printf( - "If no configuration file is specified, daemon will listen on TCP and " - "UDP ports specified by\n"); - printf( - "the --port flag (or default port). It will listen on both IPv4 and " - "IPv6 if available.\n"); - printf("\n"); - printf("Options:\n"); - printf("--port = tcp port for in-bound connections\n"); -#ifndef _WIN32 - printf("--daemon = start as daemon process\n"); -#endif - printf("--objectStoreSize = maximum number of content objects to cache\n"); - printf( - "--log = sets a facility to a given log level. You can have " - "multiple of these.\n"); - printf( - " facilities: all, config, core, io, message, " - "processor\n"); - printf( - " levels: debug, info, notice, warning, error, " - "critical, alert, off\n"); - printf(" example: daemon --log io=debug --log core=off\n"); - printf( - "--log-file = file to write log messages to (required in daemon " - "mode)\n"); - printf("--config = configuration filename\n"); - printf("\n"); - exit(exitCode); -} - -static void _setLogLevelToLevel(int logLevelArray[LoggerFacility_END], - LoggerFacility facility, - const char *levelString) { - PARCLogLevel level = parcLogLevel_FromString(levelString); - - if (level < PARCLogLevel_All) { - // we have a good facility and level - logLevelArray[facility] = level; - } else { - printf("Invalid log level string %s\n", levelString); - _usage(EXIT_FAILURE); - } -} - -/** - * string: "facility=level" - * Set the right thing in the logger - */ -static void _setLogLevel(int logLevelArray[LoggerFacility_END], - const char *string) { - char *tofree = parcMemory_StringDuplicate(string, strlen(string)); - char *p = tofree; - - char *facilityString = strtok(p, "="); - if (facilityString) { - char *levelString = strtok(NULL, "="); - - if (strcasecmp(facilityString, "all") == 0) { - for (LoggerFacility facility = 0; facility < LoggerFacility_END; - facility++) { - _setLogLevelToLevel(logLevelArray, facility, levelString); - } - } else { - LoggerFacility facility; - for (facility = 0; facility < LoggerFacility_END; facility++) { - if (strcasecmp(facilityString, logger_FacilityString(facility)) == 0) { - break; - } - } - - if (facility < LoggerFacility_END) { - _setLogLevelToLevel(logLevelArray, facility, levelString); - } else { - printf("Invalid facility string %s\n", facilityString); - _usage(EXIT_FAILURE); - } - } - } - - parcMemory_Deallocate((void **)&tofree); -} - -#ifndef _WIN32 -static void _daemonize(void) { - if (getppid() == 1) { - // already a daemon - return; - } - - int forkReturn = fork(); - parcTrapUnexpectedStateIf(forkReturn < 0, "Fork error") - - if (forkReturn > 0) { - // parent exits - exit(EXIT_SUCCESS); - } - - // Child daemon detaches - printf("child continuing, pid = %u\n", getpid()); - - // get a new process group independent from old parent - setsid(); - - /* close all descriptors */ -#ifdef __ANDROID__ - for (int i = sysconf(_SC_OPEN_MAX); i >= 0; --i) { - close(i); - } -#else - for (int i = getdtablesize(); i >= 0; --i) { - close(i); - } -#endif - // reset errno because it might be seg to EBADF from the close calls above - errno = 0; - - // Redirect stdin and stdout and stderr to /dev/null - const char *devnull = "/dev/null"; - int nullfile = open(devnull, O_RDWR); - parcAssertTrue(nullfile >= 0, "Error opening file '%s': (%d) %s", devnull, - errno, strerror(errno)); - - int ret; - ret = dup(nullfile); - parcAssertTrue(ret == 1, "Error duping fd 1 got %d file: (%d) %s", ret, errno, - strerror(errno)); - ret = dup(nullfile); - parcAssertTrue(ret == 2, "Error duping fd 2, got %d file: (%d) %s", ret, - errno, strerror(errno)); - - // forwarder will capture signals -} -#endif - -static Logger *_createLogfile(const char *logfile) { -#ifndef _WIN32 - int logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR); -#else - int logfd = - _open(logfile, _O_WRONLY | _O_APPEND | _O_CREAT, _S_IWRITE | _S_IREAD); -#endif - if (logfd < 0) { - fprintf(stderr, "Error opening %s for writing: (%d) %s\n", logfile, errno, - strerror(errno)); - exit(EXIT_FAILURE); - } - -#ifndef _WIN32 - chmod(logfile, S_IRWXU); -#endif - - PARCFileOutputStream *fos = parcFileOutputStream_Create(logfd); - PARCOutputStream *pos = parcFileOutputStream_AsOutputStream(fos); - PARCLogReporter *reporter = parcLogReporterFile_Create(pos); - - Logger *logger = logger_Create(reporter, parcClock_Wallclock()); - - parcOutputStream_Release(&pos); - parcLogReporter_Release(&reporter); - - return logger; -} - -int main(int argc, const char *argv[]) { - _displayForwarderLogo(); -#ifndef _WIN32 - bool daemon = false; -#else - WSADATA wsaData = {0}; - WSAStartup(MAKEWORD(2, 2), &wsaData); -#endif - - uint16_t port = PORT_NUMBER; - uint16_t configurationPort = 2001; - int capacity = -1; - const char *configFileName = NULL; - - char *logfile = NULL; - - if (argc == 2 && strcasecmp(argv[1], "-h") == 0) { - _usage(EXIT_SUCCESS); - } - - int logLevelArray[LoggerFacility_END]; - for (int i = 0; i < LoggerFacility_END; i++) { - logLevelArray[i] = -1; - } - - for (int i = 0; i < argc; i++) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "--config") == 0) { - configFileName = argv[i + 1]; - i++; - } else if (strcmp(argv[i], "--port") == 0) { - port = atoi(argv[i + 1]); - i++; -#ifndef _WIN32 - } else if (strcmp(argv[i], "--daemon") == 0) { - daemon = true; -#endif - } else if (strcmp(argv[i], "--capacity") == 0 || - strcmp(argv[i], "-c") == 0) { - capacity = atoi(argv[i + 1]); - i++; - } else if (strcmp(argv[i], "--log") == 0) { - _setLogLevel(logLevelArray, argv[i + 1]); - i++; - } else if (strcmp(argv[i], "--log-file") == 0) { - if (logfile) { - // error cannot repeat - fprintf(stderr, "Cannot specify --log-file more than once\n"); - _usage(EXIT_FAILURE); - } - - logfile = parcMemory_StringDuplicate(argv[i + 1], strlen(argv[i + 1])); - i++; - } else { - _usage(EXIT_FAILURE); - } - } - } - - // set restrictive umask, in case we create any files - umask(027); - -#ifndef _WIN32 - if (daemon && (logfile == NULL)) { - fprintf(stderr, "Must specify a logfile when running in daemon mode\n"); - _usage(EXIT_FAILURE); - } - - if (daemon) { - // inside this call, parent will EXIT_SUCCESS and child will continue - _daemonize(); - } -#endif - - Logger *logger = NULL; - if (logfile) { - logger = _createLogfile(logfile); - parcMemory_Deallocate((void **)&logfile); - } else { - PARCLogReporter *stdoutReporter = parcLogReporterTextStdout_Create(); - logger = logger_Create(stdoutReporter, parcClock_Wallclock()); - parcLogReporter_Release(&stdoutReporter); - } - - for (int i = 0; i < LoggerFacility_END; i++) { - if (logLevelArray[i] > -1) { - logger_SetLogLevel(logger, i, logLevelArray[i]); - } - } - - // this will update the clock to the tick clock - Forwarder *forwarder = forwarder_Create(logger); - - if (forwarder == NULL) { - logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Error, "daemon", - "Forwarder initialization failed. Are you running it with sudo " - "privileges?"); - logger_Release(&logger); - return -1; - } - - Configuration *configuration = forwarder_GetConfiguration(forwarder); - - if (capacity > -1) { - configuration_SetObjectStoreSize(configuration, capacity); - } - - forwarder_SetupLocalListeners(forwarder, port); - if (configFileName) { - forwarder_SetupFromConfigFile(forwarder, configFileName); - } - - Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder); - - logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Alert, "daemon", - "hicn-light running port %d configuration-port %d", port, - configurationPort); - - dispatcher_Run(dispatcher); - - logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Alert, "daemon", - "hicn-light exiting port %d", port); - - forwarder_Destroy(&forwarder); - -#ifndef _WIN32 - //sleep(2); -#else - //Sleep(2000); - WSACleanup(); -#endif - - logger_Release(&logger); - return 0; -} diff --git a/hicn-light/src/hicn/config.h.in b/hicn-light/src/hicn/config.h.in index 90ab8e83f..6c2915b7e 100644 --- a/hicn-light/src/hicn/config.h.in +++ b/hicn-light/src/hicn/config.h.in @@ -2,7 +2,8 @@ #define LEVEL1_DCACHE_LINESIZE @LEVEL1_DCACHE_LINESIZE@ #ifndef _WIN32 -#define _GNU_SOURCE +// This is now in CMakeLists.txt +//#define _GNU_SOURCE #else #include <hicn/platforms/windows/win_portability.h> #endif diff --git a/hicn-light/src/hicn/config/CMakeLists.txt b/hicn-light/src/hicn/config/CMakeLists.txt index 104026355..00ee24077 100644 --- a/hicn-light/src/hicn/config/CMakeLists.txt +++ b/hicn-light/src/hicn/config/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -12,95 +12,28 @@ # limitations under the License. list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.h - ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.h - ${CMAKE_CURRENT_SOURCE_DIR}/configuration.h - ${CMAKE_CURRENT_SOURCE_DIR}/commandReturn.h - ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlState.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.h - ${CMAKE_CURRENT_SOURCE_DIR}/configurationFile.h - ${CMAKE_CURRENT_SOURCE_DIR}/configurationListeners.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPolicy.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlList.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlListPolicies.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePolicy.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdate.h - ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdateConnection.h + ${CMAKE_CURRENT_SOURCE_DIR}/configuration.h + ${CMAKE_CURRENT_SOURCE_DIR}/command.h + ${CMAKE_CURRENT_SOURCE_DIR}/commands.h + ${CMAKE_CURRENT_SOURCE_DIR}/parse.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.c - ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.c - ${CMAKE_CURRENT_SOURCE_DIR}/configuration.c - ${CMAKE_CURRENT_SOURCE_DIR}/configurationFile.c - ${CMAKE_CURRENT_SOURCE_DIR}/configurationListeners.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlState.c - ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPolicy.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlList.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlListPolicies.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveListener.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePolicy.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeRetx.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdate.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdateConnection.c + ${CMAKE_CURRENT_SOURCE_DIR}/configuration.c + ${CMAKE_CURRENT_SOURCE_DIR}/configuration_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_cache.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_connection.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_face.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_listener.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_mapme.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_policy.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_punting.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_route.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_strategy.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_subscription.c + ${CMAKE_CURRENT_SOURCE_DIR}/command.c + ${CMAKE_CURRENT_SOURCE_DIR}/commands.c + ${CMAKE_CURRENT_SOURCE_DIR}/parse.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/config/command.c b/hicn-light/src/hicn/config/command.c new file mode 100644 index 000000000..bee0d2663 --- /dev/null +++ b/hicn-light/src/hicn/config/command.c @@ -0,0 +1,119 @@ + +/** + * @file command.c + * @brief Implementation of commands. + */ + +#include <search.h> /* tfind, tdestroy, twalk */ +#include <stdio.h> +#include <ctype.h> +#include "command.h" +#include "parse.h" + +/* Commands are registered in the following tree. */ +static void *commands_root = NULL; /**< Tree ordered by name */ + +#ifdef __linux__ +static void nothing_to_free() {} + +__attribute__((destructor)) static void command_clear() { + tdestroy(commands_root, nothing_to_free); +} +#endif /* __linux__ */ + +static int _command_compare(const command_parser_t *c1, + const command_parser_t *c2) { + if (c1->object != c2->object) return c2->object - c1->object; + if (c1->action != c2->action) return c2->action - c1->action; + if (c1->nparams != c2->nparams) return c2->nparams - c1->nparams; + return 0; +} + +#define command_compare (int (*)(const void *, const void *))(_command_compare) + +void command_register(const command_parser_t *command) { + // Insert the command in the tree if the keys does not exist yet + tsearch(command, &commands_root, command_compare); +} + +const command_parser_t *command_search(const hc_action_t action, + hc_object_type_t object, + unsigned nparams) { + command_parser_t **command, search; + + search.action = action; + search.object = object; + search.nparams = nparams; + command = tfind(&search, &commands_root, command_compare); + + return command ? *command : NULL; +} + +static inline void to_lowercase(char *p) { + for (; *p; ++p) *p = tolower(*p); +} + +typedef struct { + hc_object_type_t object; + hc_action_t action; +} cmd_search_params_t; + +static hc_object_type_t prev_obj = OBJECT_UNDEFINED; +static hc_action_t prev_action = ACTION_UNDEFINED; +static void traversal_action(const void *nodep, VISIT which, + void *cmd_params0) { + cmd_search_params_t *cmd_params = cmd_params0; + + // Execute this function during inorder traversal + if (which != postorder && which != leaf) return; + + command_parser_t *datap; + datap = *(command_parser_t **)nodep; + char *obj_str = strdup(object_str(datap->object)); + to_lowercase(obj_str); + + // List all objects + if (cmd_params->object == OBJECT_UNDEFINED && + cmd_params->action == ACTION_UNDEFINED) { + if (datap->object == prev_obj) goto FREE_STR; + prev_obj = datap->object; + + printf("\thelp %s\n", obj_str); + goto FREE_STR; + } + + // List actions for specific object + if (datap->object != cmd_params->object) goto FREE_STR; + if (cmd_params->action == ACTION_UNDEFINED) { + if (datap->action == prev_action) goto FREE_STR; + prev_action = datap->action; + + printf("\thelp %s %s\n", obj_str, action_to_cmd_action(datap->action)); + goto FREE_STR; + } + + // List commands for specific object and action + if (datap->action != cmd_params->action) goto FREE_STR; + printf(" %s %s ", action_to_cmd_action(datap->action), obj_str); + for (int i = 0; i < datap->nparams; i++) + printf("<%s> ", datap->parameters[i].name); + printf("\n\n"); + // List options' details + if (datap->nparams == 0) goto FREE_STR; + for (int i = 0; i < datap->nparams; i++) + printf("%16s: %s\n", datap->parameters[i].name, datap->parameters[i].help); + printf("\n"); + +FREE_STR: + free(obj_str); +} + +void command_list(hc_object_type_t object, hc_action_t action) { +#if defined(__linux__) && !defined(__ANDROID__) + cmd_search_params_t cmd_params = {.object = object, .action = action}; + twalk_r(commands_root, traversal_action, &cmd_params); +#else + fprintf(stderr, "twalk_r() function only available on linux"); + (void)traversal_action; +#endif +} diff --git a/hicn-light/src/hicn/config/command.h b/hicn-light/src/hicn/config/command.h new file mode 100644 index 000000000..73d8edb1f --- /dev/null +++ b/hicn-light/src/hicn/config/command.h @@ -0,0 +1,179 @@ +#ifndef HICNLIGHT_CONFIG_COMMAND +#define HICNLIGHT_CONFIG_COMMAND + +/** + * @file command.h + * @brief Commands. + */ + +#include <stddef.h> // offsetof +#include <hicn/util/ip_address.h> + +#include <hicn/ctrl/api.h> + +/* Update sscanf accordingly in parse_cmd.c */ +#define MAX_PARAMETERS 10 +#define MAX_SCANF_PARAM_LEN 100 + +typedef int (*parser_hook_t)(void *arg); + +typedef enum { + TYPENAME_UNDEFINED, + TYPENAME_INT, + TYPENAME_UINT, + TYPENAME_STR, + TYPENAME_SYMBOLIC_OR_ID, + TYPENAME_INTERFACE_NAME, + TYPENAME_IP_ADDRESS, + TYPENAME_IP_PREFIX, + TYPENAME_ON_OFF, + TYPENAME_ENUM, + TYPENAME_POLICY_STATE, +} parser_typename_t; + +typedef struct { + parser_typename_t name; + union { + struct { + size_t max_size; + } str; + struct { + int min; + int max; + } sint; + struct { + int min; + int max; + } uint; + struct { + int (*from_str)(const char *str); + } enum_; + struct { + policy_tag_t tag; + } policy_state; + }; +} parser_type_t; + +typedef struct { + const char *name; + const char *help; + parser_type_t type; + size_t offset; + /* + * quick hack to let the functions update two or more parameters, like for + * IP_ADDRESS or IP_PREFIX types + */ + size_t offset2; + size_t offset3; +} command_parameter_t; + +typedef struct { + hc_action_t action; + hc_object_type_t object; + unsigned nparams; + command_parameter_t parameters[MAX_PARAMETERS]; + parser_hook_t post_hook; +} command_parser_t; + +#define TYPE_STRN(N) \ + (parser_type_t) { \ + .name = TYPENAME_STR, \ + .str = { \ + .max_size = N, \ + }, \ + } +#define TYPE_FMT_STRN(N) "%s" + +#define TYPE_INT(MIN, MAX) \ + (parser_type_t) { \ + .name = TYPENAME_INT, \ + .sint = { \ + .min = (MIN), \ + .max = (MAX), \ + }, \ + } +#define TYPE_FMT_INT "%d" + +#define TYPE_UINT(min, max) \ + (parser_type_t) { \ + .name = TYPENAME_UINT, \ + .uint = { \ + .min = min, \ + .max = max, \ + }, \ + } +#define TYPE_FMT_UINT "%u" + +#define TYPE_SYMBOLIC_OR_ID TYPE_STRN(SYMBOLIC_NAME_LEN) +#define TYPE_FMT_SYMBOLIC_OR_ID "%s" + +#define TYPE_INTERFACE_NAME TYPE_STRN(INTERFACE_LEN) +#define TYPE_FMT_INTERFACE_NAME "%s" + +#define TYPE_IP_ADDRESS \ + (parser_type_t) { .name = TYPENAME_IP_ADDRESS, } +#define TYPE_FMT_IP_ADDRESS "%s" + +#define TYPE_IP_PREFIX \ + (parser_type_t) { .name = TYPENAME_IP_PREFIX, } +#define TYPE_FMT_IP_PREFIX "%s" + +#define TYPE_ON_OFF \ + (parser_type_t) { .name = TYPENAME_ON_OFF, } +#define TYPE_FMT_ON_OFF "%s" + +#define TYPE_ENUM(x) \ + (parser_type_t) { \ + .name = TYPENAME_ENUM, \ + .enum_ = { \ + .from_str = (int (*)(const char *))x##_from_str, \ + }, \ + } +/* We need to allocate room for the intermediate string */ +#define TYPE_FMT_ENUM "%s" + +#define TYPE_POLICY_STATE(TAG) \ + (parser_type_t) { \ + .name = TYPENAME_POLICY_STATE, \ + .policy_state = { \ + .tag = TAG, \ + }, \ + } +/* We need to allocate room for the intermediate string */ +#define TYPE_FMT_POLICY_STATE "%s" + +/** + * \brief Register a protocol + * \param protocol Pointer to a protocol_t structure describing the protocol to + * register \return None + */ + +void command_register(const command_parser_t *command); + +/** + * \brief Search a registered protocol in the library according to its name + * \param[in] action The action of the command. + * \param[in] object The object of the command. + * \param[in] nparams The number of parameters expected in the command. + * \return A pointer to the corresponding command if any, NULL othewise + */ +const command_parser_t *command_search(hc_action_t action, + hc_object_type_t object, + unsigned nparams); + +/** + * @brief List the commands associated with the specified object and/or action. + * Use OBJECT_UNDEFINED and ACTION_UNDEFINED to list all the available objects. + * Use ACTION_UNDEFINED to list all the actions associated to the specified + * object. + * + * @param object The action of the command + * @param action The object of the command + */ +void command_list(hc_object_type_t object, hc_action_t action); + +#define COMMAND_REGISTER(MOD) \ + static void __init_##MOD(void) __attribute__((constructor)); \ + static void __init_##MOD(void) { command_register(&MOD); } + +#endif /* HICNLIGHT_CONFIG_COMMAND */ diff --git a/hicn-light/src/hicn/config/commandOps.c b/hicn-light/src/hicn/config/commandOps.c deleted file mode 100644 index dd8e148d0..000000000 --- a/hicn-light/src/hicn/config/commandOps.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifndef __ANDROID__ -#ifdef HAVE_ERRNO_H -#include <errno.h> -#else -#ifndef _WIN32 -extern int errno; -#endif -#endif -#endif - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/config/commandOps.h> -#include <hicn/config/commandParser.h> - -CommandOps *commandOps_Create(void *closure, const char *command, - void (*init)(CommandParser *parser, - CommandOps *ops), - CommandReturn (*execute)(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size), - void (*destroyer)(CommandOps **opsPtr)) { - parcAssertNotNull(command, "Parameter command must be non-null"); - parcAssertNotNull(execute, "Parameter execute must be non-null"); - CommandOps *ops = parcMemory_AllocateAndClear(sizeof(CommandOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(CommandOps)); - - ops->closure = closure; - ops->command = parcMemory_StringDuplicate(command, strlen(command) + 1); - ops->init = init; - ops->execute = execute; - ops->destroyer = destroyer; - return ops; -} - -void commandOps_Destroy(CommandOps **opsPtr) { - parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null"); - parcAssertNotNull(*opsPtr, - "Parameter opsPtr must dereference to non-null pointer"); - - CommandOps *ops = *opsPtr; - parcMemory_Deallocate((void **)&(ops->command)); - // DO NOT call ops->destroyer, we are one! - parcMemory_Deallocate((void **)&ops); - - *opsPtr = NULL; -} diff --git a/hicn-light/src/hicn/config/commandOps.h b/hicn-light/src/hicn/config/commandOps.h deleted file mode 100644 index 784b91eb8..000000000 --- a/hicn-light/src/hicn/config/commandOps.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file command_Ops.h - * @brief The function structure defining a CLI command - * - * The function structure that defines a CLI command. Each command will return - * one of these which defines how to run the command. - * - */ - -#ifndef command_Ops_h -#define command_Ops_h - -#include <parc/algol/parc_List.h> - -#include <hicn/config/commandReturn.h> - -// forward reference -struct command_parser; - -struct command_ops; -typedef struct command_ops CommandOps; - -/** - * @typedef CommandOps - * @abstract Each command implements a CommandOps - * @constant closure is a user-specified pointer for any state the user needs - * @constant command The text string of the command, must be the spelled out - * string, e.g. "help list routes" - * @constant init A function to call to initialize the command at program - * startup - * @constant execute A function to call to execute the command - * @constant destroyer A function to call to release the command - * @discussion - * Typically, the root of the thee has an Init function that then initilizes - * the rest of the tree. For example: - * - * @code - * const CommandOps control_Root = { - * .closure = NULL, - * .command = "", // empty string for root - * .init = control_Root_Init, - * .execute = control_Root_Execute - * .destroyer = NULL - * }; - * @endcode - * - * The control_Root_Init function will then begin adding the subtree under root. - * For example: - * - * @code - * const CommandOps control_Add = { - * .closure = NULL, - * .command = "add", - * .init = control_Add_Init, - * .execute = control_Add_Execute, - * .destroyer = NULL - * }; - * - * static void - * control_Root_Init(ControlState *state, CommandOps *ops) - * { - * controlState_RegisterCommand(state, &control_Add); - * } - * @endcode - */ -struct command_ops { - void *closure; - char *command; - void (*init)(struct command_parser *parser, CommandOps *ops); - CommandReturn (*execute)(struct command_parser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - void (*destroyer)(CommandOps **opsPtr); -}; - -/** - * A helper function to create the pubically defined CommandOps. - * - * Retruns allocated memory of the command - * - * @param [in] command The string is copied - * - * @retval <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -CommandOps *commandOps_Create( - void *closure, const char *command, - void (*init)(struct command_parser *parser, CommandOps *ops), - CommandReturn (*execute)(struct command_parser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size), - void (*destroyer)(CommandOps **opsPtr)); - -/** - * De-allocates the memory of the CommandOps and the copied command string - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @retval <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -void commandOps_Destroy(CommandOps **opsPtr); -#endif // command_Ops_h diff --git a/hicn-light/src/hicn/config/commandParser.c b/hicn-light/src/hicn/config/commandParser.c deleted file mode 100644 index f4652fe39..000000000 --- a/hicn-light/src/hicn/config/commandParser.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <parc/assert/parc_Assert.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <parc/security/parc_Security.h> - -#include <parc/algol/parc_List.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Time.h> -#include <parc/algol/parc_TreeRedBlack.h> - -#include <hicn/config/commandParser.h> - -#ifndef __ANDROID__ -#ifdef HAVE_ERRNO_H -#include <errno.h> -#else -#ifndef _WIN32 -extern int errno; -#endif -#endif -#endif - -struct command_parser { - // key = command, value = CommandOps - PARCTreeRedBlack *commandTree; - bool debugFlag; -}; - -static int _stringCompare(const void *key1, const void *key2) { - return strcasecmp((const char *)key1, (const char *)key2); -} - -CommandParser *commandParser_Create(void) { - CommandParser *state = parcMemory_AllocateAndClear(sizeof(CommandParser)); - parcAssertNotNull(state, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(CommandParser)); - - state->commandTree = parcTreeRedBlack_Create(_stringCompare, // key compare - NULL, // key free - NULL, // key copy - NULL, // value equals - NULL, // value free - NULL // value copy - ); - state->debugFlag = false; - return state; -} - -void commandParser_Destroy(CommandParser **parserPtr) { - CommandParser *parser = *parserPtr; - - // destroy every element if it has a destroyer - PARCArrayList *values = parcTreeRedBlack_Values(parser->commandTree); - if (values) { - for (int i = 0; i < parcArrayList_Size(values); i++) { - CommandOps *ops = parcArrayList_Get(values, i); - parcTreeRedBlack_Remove(parser->commandTree, ops->command); - if (ops->destroyer) { - ops->destroyer(&ops); - } - } - parcArrayList_Destroy(&values); - } - - parcTreeRedBlack_Destroy(&parser->commandTree); - - parcMemory_Deallocate((void **)&parser); - *parserPtr = NULL; -} - -void commandParser_SetDebug(CommandParser *state, bool debugFlag) { - state->debugFlag = debugFlag; -} - -bool commandParser_GetDebug(CommandParser *state) { return state->debugFlag; } - -void commandParser_RegisterCommand(CommandParser *state, CommandOps *ops) { - parcAssertNotNull(state, "Parameter state must be non-null"); - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(ops->command, "Operation command string must be non-null"); - - void *exists = parcTreeRedBlack_Get(state->commandTree, ops->command); - parcAssertNull(exists, "Command '%s' already exists in the tree %p\n", - ops->command, (void *)exists); - - parcTreeRedBlack_Insert(state->commandTree, (void *)ops->command, - (void *)ops); - - // if the command being registered asked for an init function to be called, - // call it - if (ops->init != NULL) { - ops->init(state, ops); - } -} - -static PARCList *parseStringIntoTokens(const char *originalString) { - PARCList *list = - parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), - PARCArrayListAsPARCList); - - char *token; - - char *tofree = - parcMemory_StringDuplicate(originalString, strlen(originalString) + 1); - char *string = tofree; - - token = strtok(string, " \t\n"); - while (token != NULL) { - if (strlen(token) > 0) { - parcList_Add(list, strdup(token)); - } - token = strtok(NULL, " \t\n"); - } - - parcMemory_Deallocate((void **)&tofree); - - return list; -} - -/** - * Matches the user arguments to available commands, returning the command or - * NULL if not found - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @return <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -static CommandOps *commandParser_MatchCommand(CommandParser *state, - PARCList *args) { - // Find the longest matching prefix command. - // Pretty wildly inefficient - - size_t longest_token_count = 0; - char *longest_command = NULL; - - PARCArrayList *commands = parcTreeRedBlack_Keys(state->commandTree); - for (int i = 0; i < parcArrayList_Size(commands); i++) { - char *command = parcArrayList_Get(commands, i); - PARCList *command_tokens = parseStringIntoTokens(command); - - // is it a prefix match? - if (parcList_Size(args) >= parcList_Size(command_tokens)) { - bool possible_match = true; - for (int i = 0; i < parcList_Size(command_tokens) && possible_match; - i++) { - const char *a = parcList_GetAtIndex(command_tokens, i); - const char *b = parcList_GetAtIndex(args, i); - if (strncasecmp(a, b, strlen(a) + 1) != 0) { - possible_match = false; - } - } - - if (possible_match && - parcList_Size(command_tokens) > longest_token_count) { - longest_token_count = parcList_Size(command_tokens); - longest_command = command; - } - } - - parcList_Release(&command_tokens); - } - - parcArrayList_Destroy(&commands); - - if (longest_token_count == 0) { - return NULL; - } else { - CommandOps *ops = parcTreeRedBlack_Get(state->commandTree, longest_command); - parcAssertNotNull(ops, "Got null operations for command '%s'\n", - longest_command); - return ops; - } -} - -CommandReturn commandParser_DispatchCommand(CommandParser *state, - PARCList *args, - char *output, - size_t output_size) { - parcAssertNotNull(output, "output buffer is null\n"); - CommandOps *ops = commandParser_MatchCommand(state, args); - - if (ops == NULL) { - snprintf(output, output_size, "Command not found.\n"); - return CommandReturn_Failure; - } else { - return ops->execute(state, ops, args, output, output_size); - } -} - -bool commandParser_ContainsCommand(CommandParser *parser, const char *command) { - CommandOps *ops = parcTreeRedBlack_Get(parser->commandTree, command); - return (ops != NULL); -} diff --git a/hicn-light/src/hicn/config/commandParser.h b/hicn-light/src/hicn/config/commandParser.h deleted file mode 100644 index 882d55d26..000000000 --- a/hicn-light/src/hicn/config/commandParser.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file command_Parser.h - * @brief Creates a dictionary of commands and parses a command_line to match - * against them - * - * A user creates individual CommandParserEntry that map a command_line to a - * function to execute. The CommandParser then does a longest-matching prefix - * match of a command_line to the dictionary of commands and executes the - * appropriate command. - * - */ - -#ifndef command_parser_h -#define command_parser_h - -#include <hicn/config/commandOps.h> -#include <hicn/config/commandReturn.h> - -struct command_parser; -typedef struct command_parser CommandParser; - -/** - * controlState_Create - * - * Creates the global state for the Control program - * - * @return non-null A command parser - * - * Example: - * @code - * <#example#> - * @endcode - */ -CommandParser *commandParser_Create(void); - -/** - * Destroys the control state, closing all network connections - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @return <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -void commandParser_Destroy(CommandParser **statePtr); - -/** - * Registers a CommandOps with the system. - * - * Each command has its complete command prefix in the "command" field. - * RegisterCommand will put these command prefixes in to a tree and then match - * what a user types against the longest-matching prefix in the tree. If - * there's a match, it will call the "execute" function. - * - * When the parser is destroyed, each command's destroyer function will be - * called. - * - * @param [in] state An allocated ControlState - * @param [in] command The command to register with the system - * - * Example: - * @code - * static ControlReturn - * control_Root_Execute(CommandParser *parser, CommandOps *ops, PARCList - * *args) - * { - * printf("Root Command\n"); - * return CommandReturn_Success; - * } - * - * static ControlReturn - * control_FooBar_Execute(CommandParser *parser, CommandOps *ops, PARCList - * *args) - * { - * printf("Foo Bar Command\n"); - * return CommandReturn_Success; - * } - * - * const CommandOps control_Root = { - * .closure = NULL, - * .command = "", // empty string for root - * .init = NULL, - * .execute = control_Root_Execute - * }; - * - * const CommandOps control_FooBar = { - * .closure = NULL, - * .command = "foo bar", // empty string for root - * .init = NULL, - * .execute = control_FooBar_Execute - * }; - * - * void startup(void) - * { - * ControlState *state = controlState_Create("happy", "day"); - * controlState_RegisterCommand(state, control_FooBar); - * controlState_RegisterCommand(state, control_Root); - * - * // this executes "root" - * controlState_DispatchCommand(state, "foo"); - * controlState_Destroy(&state); - * } - * @endcode - */ -void commandParser_RegisterCommand(CommandParser *state, CommandOps *command); - -/** - * Performs a longest-matching prefix of the args to the command tree - * - * The command tree is created with controlState_RegisterCommand. - * - * @param [in] state The allocated ControlState - * @param [in] args Each command_line word parsed to the ordered list - * @param [in] output The allocated output string, if null, the normal printf is executed - * @param [in] output_size the size of output array string. It is ignored if the output string is null - * - * @return CommandReturn_Success the command was successful - * @return CommandReturn_Failure the command failed or was not found - * @return CommandReturn_Exit the command indicates that the interactive mode - * should exit - * - * Example: - * @code - * <#example#> - * @endcode - */ -CommandReturn commandParser_DispatchCommand(CommandParser *state, - PARCList *args, - char *output, - size_t output_size); - -/** - * Sets the Debug mode, which will print out much more information. - * - * Prints out much more diagnostic information about what hicn-light controller - * is doing. yes, you would make a CommandOps to set and unset this :) - * - * @param [in] debugFlag true means to print debug info, false means to turn it - * off - * - * Example: - * @code - * <#example#> - * @endcode - */ -void commandParser_SetDebug(CommandParser *state, bool debugFlag); - -/** - * Returns the debug state of ControlState - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @return <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -bool commandParser_GetDebug(CommandParser *state); - -/** - * Checks if the command is registered - * - * Checks if the exact command given is registered. This is not a prefix match. - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @return true The command is registered - * @return false The command is not registered - * - * Example: - * @code - * <#example#> - * @endcode - */ -bool commandParser_ContainsCommand(CommandParser *parser, const char *command); -#endif // command_parser_h diff --git a/hicn-light/src/hicn/config/commandReturn.h b/hicn-light/src/hicn/config/commandReturn.h deleted file mode 100644 index 16ee93db1..000000000 --- a/hicn-light/src/hicn/config/commandReturn.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file command_Return.h - * @brief The return code used by CLI commands - * - * This return code is used throughout the command parser and command - * implementations to indicate success, failure, or if the program should exit. - * - */ - -#ifndef command_return_h -#define command_return_h - -/** - * @typedef ControlReturn - * @abstract A command returns one of (SUCCESS, FAILURE, EXIT) - * @constant SUCCESS means the command succeeded - * @constant FAILURE indicates failure - * @constant EXIT means the command indicated that hicn-light controller should - * exit. - * @discussion <#Discussion#> - */ -typedef enum command_return { - CommandReturn_Success, // command returned success - CommandReturn_Failure, // command failure - CommandReturn_Exit // command indicates program should exit -} CommandReturn; - -#endif // command_return_h diff --git a/hicn-light/src/hicn/config/command_cache.c b/hicn-light/src/hicn/config/command_cache.c new file mode 100644 index 000000000..073221cf0 --- /dev/null +++ b/hicn-light/src/hicn/config/command_cache.c @@ -0,0 +1,54 @@ +#include <math.h> +#include "command.h" + +/* Parameters */ + +#define serve \ + { \ + .name = "serve", \ + .help = \ + "Enables/disables replies from local content store. Either the " \ + "string 'on' or 'off'", \ + .type = TYPE_ON_OFF, .offset = offsetof(hc_cache_t, serve), \ + } + +#define store \ + { \ + .name = "store", \ + .help = \ + "enables/disables the storage of incoming data packets in the local " \ + "content store. Either the string 'on' or 'off'", \ + .type = TYPE_ON_OFF, .offset = offsetof(hc_cache_t, store), \ + } + +/* Commands */ + +static const command_parser_t command_cache_set_serve = { + .action = ACTION_SERVE, + .object = OBJECT_CACHE, + .nparams = 1, + .parameters = {serve}, +}; +COMMAND_REGISTER(command_cache_set_serve); + +static const command_parser_t command_cache_set_store = { + .action = ACTION_STORE, + .object = OBJECT_CACHE, + .nparams = 1, + .parameters = {store}, +}; +COMMAND_REGISTER(command_cache_set_store); + +static const command_parser_t command_cache_clear = { + .action = ACTION_CLEAR, + .object = OBJECT_CACHE, + .nparams = 0, +}; +COMMAND_REGISTER(command_cache_clear); + +static const command_parser_t command_cache_list = { + .action = ACTION_LIST, + .object = OBJECT_CACHE, + .nparams = 0, +}; +COMMAND_REGISTER(command_cache_list); diff --git a/hicn-light/src/hicn/config/command_connection.c b/hicn-light/src/hicn/config/command_connection.c new file mode 100644 index 000000000..069bf55a6 --- /dev/null +++ b/hicn-light/src/hicn/config/command_connection.c @@ -0,0 +1,128 @@ +#include <math.h> +#include "command.h" + +/* Parameters */ + +#define type_hicn \ + { \ + .name = "type", .help = "connection type (hICN)", \ + .type = TYPE_ENUM(face_type), .offset = offsetof(hc_connection_t, type), \ + } + +#define type_tcp_udp \ + { \ + .name = "type", .help = "connection type [tcp | udp]", \ + .type = TYPE_ENUM(face_type), .offset = offsetof(hc_connection_t, type), \ + } + +#define symbolic \ + { \ + .name = "symbolic", \ + .help = "symbolic name, e.g. 'conn1' (must be unique, start with alpha)", \ + .type = TYPE_SYMBOLIC_OR_ID, .offset = offsetof(hc_connection_t, name), \ + } + +#define local_address \ + { \ + .name = "local_addr", .help = "local IP address on which to bind.", \ + .type = TYPE_IP_ADDRESS, .offset = offsetof(hc_connection_t, local_addr), \ + .offset2 = offsetof(hc_connection_t, family), \ + } + +#define local_port \ + { \ + .name = "local_port", .help = "Local port.", \ + .type = TYPE_INT(1, UINT16_MAX), \ + .offset = offsetof(hc_connection_t, local_port), \ + } + +#define remote_address \ + { \ + .name = "remote_address", \ + .help = "The IPv4 or IPv6 or hostname of the remote system.", \ + .type = TYPE_IP_ADDRESS, .offset = offsetof(hc_connection_t, remote_addr), \ + .offset2 = offsetof(hc_connection_t, family), \ + } + +#define remote_port \ + { \ + .name = "remote_port", .help = "Remote port.", \ + .type = TYPE_INT(1, UINT16_MAX), \ + .offset = offsetof(hc_connection_t, remote_port), \ + } + +#define interface \ + { \ + .name = "interface", .help = "Interface on which to bind", \ + .type = TYPE_INTERFACE_NAME, \ + .offset = offsetof(hc_connection_t, interface_name), \ + } + +#define symbolic_or_id \ + { \ + .name = "symbolic", .help = "The connection symbolic name or id", \ + .type = TYPE_SYMBOLIC_OR_ID, .offset = offsetof(hc_connection_t, name), \ + } + +/* Commands */ + +int on_connection_create(hc_connection_t* connection) { + connection->admin_state = FACE_STATE_UP; + return 0; +} + +#if 0 +static command_parser_t command_connection_create4 = { + .action = ACTION_CREATE, + .object = OBJECT_CONNECTION, + .nparams = 4, + .parameters = {type_hicn, symbolic, local_address, remote_address}, + .post_hook = (parser_hook_t)on_connection_create, +}; +COMMAND_REGISTER(command_connection_create4); + +static const command_parser_t command_connection_create5 = { + .action = ACTION_CREATE, + .object = OBJECT_CONNECTION, + .nparams = 5, + .parameters = {type_hicn, symbolic, local_address, remote_address, + interface}, + .post_hook = (parser_hook_t)on_connection_create, +}; +COMMAND_REGISTER(command_connection_create5); +#endif + +static const command_parser_t command_connection_create6 = { + .action = ACTION_CREATE, + .object = OBJECT_CONNECTION, + .nparams = 6, + .parameters = {type_tcp_udp, symbolic, remote_address, remote_port, + local_address, local_port}, + .post_hook = (parser_hook_t)on_connection_create, +}; +COMMAND_REGISTER(command_connection_create6); + +static const command_parser_t command_connection_create7 = { + .action = ACTION_CREATE, + .object = OBJECT_CONNECTION, + .nparams = 7, + .parameters = {type_tcp_udp, symbolic, remote_address, remote_port, + local_address, local_port, interface}, + .post_hook = (parser_hook_t)on_connection_create, +}; +COMMAND_REGISTER(command_connection_create7); + +static const command_parser_t command_connection_list = { + .action = ACTION_LIST, + .object = OBJECT_CONNECTION, + .nparams = 0, +}; +COMMAND_REGISTER(command_connection_list); + +static const command_parser_t command_connection_remove = { + .action = ACTION_DELETE, + .object = OBJECT_CONNECTION, + .nparams = 1, + .parameters = {symbolic_or_id}, +}; +COMMAND_REGISTER(command_connection_remove); diff --git a/hicn-light/src/hicn/config/command_face.c b/hicn-light/src/hicn/config/command_face.c new file mode 100644 index 000000000..95ec404f0 --- /dev/null +++ b/hicn-light/src/hicn/config/command_face.c @@ -0,0 +1,16 @@ +#if 0 +#include "command.h" + +/* Parameters */ + +/* Commands */ + +// XXX missing add + +static const command_parser_t command_face_list = { + .action = ACTION_LIST, + .object = OBJECT_FACE, + .nparams = 0, +}; +COMMAND_REGISTER(command_face_list); +#endif
\ No newline at end of file diff --git a/hicn-light/src/hicn/config/command_listener.c b/hicn-light/src/hicn/config/command_listener.c new file mode 100644 index 000000000..8ad7c94be --- /dev/null +++ b/hicn-light/src/hicn/config/command_listener.c @@ -0,0 +1,111 @@ +#include <math.h> +#include "command.h" + +/* Parameters */ + +#define protocol_hicn \ + { \ + .name = "protocol", .help = "Protocol [hicn].", \ + .type = TYPE_ENUM(face_type), .offset = offsetof(hc_listener_t, type), \ + } + +#define protocol_tcp_udp \ + { \ + .name = "protocol", .help = "Protocol [tcp | udp]", \ + .type = TYPE_ENUM(face_type), .offset = offsetof(hc_listener_t, type), \ + } + +#define symbolic \ + { \ + .name = "symbolic", \ + .help = \ + "User defined name for listener, must start with alpha and be " \ + "alphanum", \ + .type = TYPE_SYMBOLIC_OR_ID, .offset = offsetof(hc_listener_t, name), \ + } + +#define local_address \ + { \ + .name = "local_addr", \ + .help = \ + "IPv4 or IPv6 address (or prefix protocol = hicn) assigend to the " \ + "local interface", \ + .type = TYPE_IP_ADDRESS, .offset = offsetof(hc_listener_t, local_addr), \ + .offset2 = offsetof(hc_listener_t, family), \ + } + +#define local_port \ + { \ + .name = "local_port", .help = "Local port.", \ + .type = TYPE_INT(1, UINT16_MAX), \ + .offset = offsetof(hc_listener_t, local_port), \ + } + +#define interface \ + { \ + .name = "interface", .help = "Interface on which to bind", \ + .type = TYPE_INTERFACE_NAME, \ + .offset = offsetof(hc_listener_t, interface_name), \ + } + +#define symbolic_or_id \ + { \ + .name = "symbolic", .help = "The listener symbolic name or id", \ + .type = TYPE_SYMBOLIC_OR_ID, .offset = offsetof(hc_listener_t, name), \ + } + +/* Commands */ + +/* The parse sets the wrong face_type_t for listener, we fix that here */ +int on_listener_create(hc_listener_t* listener) { + switch (listener->type) { + case FACE_TYPE_UDP: + listener->type = FACE_TYPE_UDP_LISTENER; + break; + case FACE_TYPE_TCP: + listener->type = FACE_TYPE_TCP_LISTENER; + break; + case FACE_TYPE_HICN: + listener->type = FACE_TYPE_HICN_LISTENER; + break; + default: + break; + } + return 0; +} + +#if 0 +static const command_parser_t command_listener_create4 = { + .action = ACTION_CREATE, + .object = OBJECT_LISTENER, + .nparams = 4, + .parameters = {protocol_hicn, symbolic, local_address, interface}, + .post_hook = (parser_hook_t)on_listener_create, +}; +COMMAND_REGISTER(command_listener_create4); +#endif + +static const command_parser_t command_listener_create6 = { + .action = ACTION_CREATE, + .object = OBJECT_LISTENER, + .nparams = 5, + .parameters = {protocol_tcp_udp, symbolic, local_address, local_port, + interface}, + .post_hook = (parser_hook_t)on_listener_create, +}; +COMMAND_REGISTER(command_listener_create6); + +static const command_parser_t command_listener_list = { + .action = ACTION_LIST, + .object = OBJECT_LISTENER, + .nparams = 0, +}; +COMMAND_REGISTER(command_listener_list); + +static const command_parser_t command_listener_remove = { + .action = ACTION_DELETE, + .object = OBJECT_LISTENER, + .nparams = 1, + .parameters = {symbolic_or_id}, +}; +COMMAND_REGISTER(command_listener_remove); diff --git a/hicn-light/src/hicn/config/command_mapme.c b/hicn-light/src/hicn/config/command_mapme.c new file mode 100644 index 000000000..a22e8b340 --- /dev/null +++ b/hicn-light/src/hicn/config/command_mapme.c @@ -0,0 +1,59 @@ +#include <math.h> +#include "command.h" + +/* Parameters */ + +#define target \ + { \ + .name = "target", \ + .help = \ + "Target for the set action, e.g. enable, discovery, timescale, retx", \ + .type = TYPE_ENUM(mapme_target), .offset = offsetof(hc_mapme_t, target), \ + } + +#define value \ + { \ + .name = "value", \ + .help = "Value to set for the target, e.g. 'on', 'off', milliseconds", \ + .type = TYPE_STRN(4), .offset = offsetof(hc_mapme_t, unparsed_arg), \ + } + +#define prefix \ + { \ + .name = "prefix", \ + .help = "The hicn name as IPv4 or IPv6 address (e.g 1234::0/64).", \ + .type = TYPE_IP_PREFIX, .offset = offsetof(hc_mapme_t, address), \ + .offset2 = offsetof(hc_mapme_t, len), \ + .offset3 = offsetof(hc_mapme_t, family), \ + } + +/* Commands */ + +// Parse the raw string argument into 'timescale' or 'enabled', +// necessary since the command dispatch is based on the number +// of arguments and not their type +int parse_args(hc_mapme_t* mapme) { + mapme->timescale = atoi(mapme->unparsed_arg); + + if (strcasecmp(mapme->unparsed_arg, "off") == 0) mapme->enabled = 0; + if (strcasecmp(mapme->unparsed_arg, "on") == 0) mapme->enabled = 1; + + return 0; +} + +static const command_parser_t command_mapme_set = { + .action = ACTION_SET, + .object = OBJECT_MAPME, + .nparams = 2, + .parameters = {target, value}, + .post_hook = (parser_hook_t)parse_args, +}; +COMMAND_REGISTER(command_mapme_set); + +static const command_parser_t command_mapme_update = { + .action = ACTION_UPDATE, + .object = OBJECT_MAPME, + .nparams = 1, + .parameters = {prefix}, +}; +COMMAND_REGISTER(command_mapme_update);
\ No newline at end of file diff --git a/hicn-light/src/hicn/config/command_policy.c b/hicn-light/src/hicn/config/command_policy.c new file mode 100644 index 000000000..1e802c3f5 --- /dev/null +++ b/hicn-light/src/hicn/config/command_policy.c @@ -0,0 +1,52 @@ +#if 0 +#include <hicn/policy.h> + +#include "command.h" + +/* Parameters */ + +#define prefix \ + { \ + .name = "prefix", \ + .help = "The hicn name as IPv4 or IPv6 address (e.g 1234::0/64).", \ + .type = TYPE_IP_PREFIX, .offset = offsetof(hc_policy_t, remote_addr), \ + .offset2 = offsetof(hc_policy_t, len), \ + .offset3 = offsetof(hc_policy_t, family), \ + } + +#define app_name \ + { \ + .name = "app_name", \ + .help = "The application name associated to this policy", \ + .type = TYPE_STR, .offset = offsetof(hc_policy_t, policy.app_name), \ + } + +/* Commands */ + +static const command_parser_t command_policy_create = { + .action = ACTION_CREATE, + .object = OBJECT_POLICY, + .nparams = 2 + POLICY_TAG_N, + .parameters = {prefix, app_name, +#define _(x, y) \ + { \ + .name = "flag:" #x, \ + .help = \ + "A value among [neutral|require|prefer|avoid|prohibit] with an " \ + "optional '!' character prefix for disabling changes", \ + .type = TYPE_POLICY_STATE(POLICY_TAG_##x), \ + .offset = offsetof(hc_policy_t, policy.tags), \ + }, + foreach_policy_tag +#undef _ + }, +}; +COMMAND_REGISTER(command_policy_create); + +static const command_parser_t command_policy_list = { + .action = ACTION_LIST, + .object = OBJECT_POLICY, + .nparams = 0, +}; +COMMAND_REGISTER(command_policy_list); +#endif
\ No newline at end of file diff --git a/hicn-light/src/hicn/config/command_punting.c b/hicn-light/src/hicn/config/command_punting.c new file mode 100644 index 000000000..8c7a6dec3 --- /dev/null +++ b/hicn-light/src/hicn/config/command_punting.c @@ -0,0 +1,40 @@ +#if 0 +#include "command.h" + +/* Parameters */ + +#define symbolic_or_id \ + { \ + .name = "symbolic_or_id", \ + .help = \ + "The symbolic name for an egress, or the egress punting id (see " \ + "'help list puntings')", \ + .type = TYPE_SYMBOLIC_OR_ID, .offset = offsetof(hc_punting_t, face_id), \ + } + +#define prefix \ + { \ + .name = "prefix", \ + .help = "Prefix to add as a punting rule. (example 1234::0/64)", \ + .type = TYPE_IP_PREFIX, .offset = offsetof(hc_punting_t, prefix), \ + .offset2 = offsetof(hc_punting_t, prefix_len), \ + .offset3 = offsetof(hc_punting_t, family), \ + } + +/* Commands */ + +static const command_parser_t command_punting_create = { + .action = ACTION_CREATE, + .object = OBJECT_PUNTING, + .nparams = 2, + .parameters = {symbolic_or_id, prefix}, +}; +COMMAND_REGISTER(command_punting_create); + +static const command_parser_t command_punting_list = { + .action = ACTION_LIST, + .object = OBJECT_PUNTING, + .nparams = 0, +}; +COMMAND_REGISTER(command_punting_list); +#endif
\ No newline at end of file diff --git a/hicn-light/src/hicn/config/command_route.c b/hicn-light/src/hicn/config/command_route.c new file mode 100644 index 000000000..dfbea101f --- /dev/null +++ b/hicn-light/src/hicn/config/command_route.c @@ -0,0 +1,53 @@ +#include <math.h> +#include "command.h" + +/* Parameters */ + +#define symbolic_or_id \ + { \ + .name = "symbolic_or_id", \ + .help = \ + "The symbolic name for an egress, or the egress route id (see 'help " \ + "list routes')", \ + .type = TYPE_SYMBOLIC_OR_ID, .offset = offsetof(hc_route_t, name), \ + } + +#define prefix \ + { \ + .name = "prefix", \ + .help = "The hicn name as IPv4 or IPv6 address (e.g 1234::0/64).", \ + .type = TYPE_IP_PREFIX, .offset = offsetof(hc_route_t, remote_addr), \ + .offset2 = offsetof(hc_route_t, len), \ + .offset3 = offsetof(hc_route_t, family), \ + } + +#define cost \ + { \ + .name = "cost", .help = "Positive integer representing cost.", \ + .type = TYPE_INT(1, 255), .offset = offsetof(hc_route_t, cost), \ + } + +/* Commands */ + +static const command_parser_t command_route_create = { + .action = ACTION_CREATE, + .object = OBJECT_ROUTE, + .nparams = 3, + .parameters = {symbolic_or_id, prefix, cost}, +}; +COMMAND_REGISTER(command_route_create); + +static const command_parser_t command_route_list = { + .action = ACTION_LIST, + .object = OBJECT_ROUTE, + .nparams = 0, +}; +COMMAND_REGISTER(command_route_list); + +static const command_parser_t command_route_remove = { + .action = ACTION_DELETE, + .object = OBJECT_ROUTE, + .nparams = 2, + .parameters = {symbolic_or_id, prefix}, +}; +COMMAND_REGISTER(command_route_remove); diff --git a/hicn-light/src/hicn/config/command_strategy.c b/hicn-light/src/hicn/config/command_strategy.c new file mode 100644 index 000000000..2341ac830 --- /dev/null +++ b/hicn-light/src/hicn/config/command_strategy.c @@ -0,0 +1,47 @@ +#include "command.h" + +/* Parameters */ +#define prefix \ + { \ + .name = "prefix", \ + .help = "The hicn name as IPv4 or IPv6 address (e.g 1234::0/64).", \ + .type = TYPE_IP_PREFIX, .offset = offsetof(hc_strategy_t, address), \ + .offset2 = offsetof(hc_strategy_t, len), \ + .offset3 = offsetof(hc_strategy_t, family), \ + } + +#define strategy \ + { \ + .name = "strategy", \ + .help = \ + "Strategy type (e.g. 'random', 'loadbalancer', 'low_latency', " \ + "'replication', 'bestpath').", \ + .type = TYPE_ENUM(strategy_type), .offset = offsetof(hc_strategy_t, type), \ + } + +#define local_prefix \ + { \ + .name = "local_prefix", \ + .help = "The hicn name as IPv4 or IPv6 address (e.g 1234::0/64).", \ + .type = TYPE_IP_PREFIX, .offset = offsetof(hc_strategy_t, local_address), \ + .offset2 = offsetof(hc_strategy_t, local_len), \ + .offset3 = offsetof(hc_strategy_t, local_family), \ + } + +/* Commands */ + +static const command_parser_t command_strategy_list = { + .action = ACTION_SET, + .object = OBJECT_STRATEGY, + .nparams = 2, + .parameters = {prefix, strategy}, +}; +COMMAND_REGISTER(command_strategy_list); + +static const command_parser_t local_prefix_add = { + .action = ACTION_CREATE, + .object = OBJECT_LOCAL_PREFIX, + .nparams = 3, + .parameters = {prefix, strategy, local_prefix}, +}; +COMMAND_REGISTER(local_prefix_add); diff --git a/hicn-light/src/hicn/config/command_subscription.c b/hicn-light/src/hicn/config/command_subscription.c new file mode 100644 index 000000000..89e3dcd98 --- /dev/null +++ b/hicn-light/src/hicn/config/command_subscription.c @@ -0,0 +1,23 @@ +#include "command.h" + +/* Parameters */ + +#define topics \ + { \ + .name = "topics", \ + .help = \ + "Topics to subscribe to, e.g. 6 (110 in binary) means topic 2 (10 in " \ + "binary, TOPIC_CONNECTION) and topic 4 (100 in binary, " \ + "TOPIC_LISTENER).", \ + .type = TYPE_INT(1, 255), .offset = offsetof(hc_subscription_t, topics), \ + } + +/* Commands */ + +static const command_parser_t command_subscription_create = { + .action = ACTION_CREATE, + .object = OBJECT_SUBSCRIPTION, + .nparams = 1, + .parameters = {topics}, +}; +COMMAND_REGISTER(command_subscription_create);
\ No newline at end of file diff --git a/hicn-light/src/hicn/config/commands.c b/hicn-light/src/hicn/config/commands.c new file mode 100644 index 000000000..e99e0b8f5 --- /dev/null +++ b/hicn-light/src/hicn/config/commands.c @@ -0,0 +1,1530 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * + * Example: + * @code + * <#example#> + * @endcode + */ + +#ifndef _WIN32 +#include <arpa/inet.h> +#include <unistd.h> +#endif +#include <ctype.h> +#include <hicn/hicn-light/config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <hicn/core/connection.h> +#include <hicn/core/connection_table.h> +#include <hicn/core/forwarder.h> +//#include <hicn/core/system.h> +#ifdef WITH_MAPME +#include <hicn/core/mapme.h> +#endif /* WITH_MAPME */ + +#include <hicn/core/listener.h> //the listener list +#include <hicn/core/listener_table.h> +#include <hicn/core/subscription.h> +#include <hicn/ctrl/hicn-light-ng.h> +#include <hicn/utils/punting.h> +#include <hicn/util/log.h> +#include <hicn/validation.h> +#include <hicn/face.h> + +#include "commands.h" +#include "configuration.h" + +#define ETHERTYPE 0x0801 +#define DEFAULT_COST 1 +#define DEFAULT_PORT 1234 + +#define make_ack(msg) ((msg_header_t *)msg)->header.message_type = ACK_LIGHT +#define make_nack(msg) ((msg_header_t *)msg)->header.message_type = NACK_LIGHT + +#define msg_malloc_list(msg, COMMAND_ID, N, seq_number) \ + do { \ + msg = calloc(1, sizeof((msg)->header) + N * sizeof((msg)->payload)); \ + (msg)->header.message_type = RESPONSE_LIGHT; \ + (msg)->header.command_id = (COMMAND_ID); \ + (msg)->header.length = (uint16_t)(N); \ + (msg)->header.seq_num = (seq_number); \ + } while (0); + +// conn_id = UINT_MAX when symbolic_name is not found +static inline unsigned _symbolic_to_conn_id(forwarder_t *forwarder, + const char *symbolic_or_connid, + bool allow_self, + unsigned ingress_id) { + unsigned conn_id; + const connection_table_t *table = forwarder_get_connection_table(forwarder); + + if (allow_self && strcmp(symbolic_or_connid, "SELF") == 0) { + conn_id = ingress_id; + } else if (is_number(symbolic_or_connid, SYMBOLIC_NAME_LEN)) { + // case for conn_id as input + // XXX type issue ! XXX No check, see man + unsigned id = atoi(symbolic_or_connid); + if (id < 0) return CONNECTION_ID_UNDEFINED; + conn_id = id; + + if (!connection_table_validate_id(table, conn_id)) { + ERROR("ConnID not found, check list connections"); + conn_id = CONNECTION_ID_UNDEFINED; + } + } else { + // case for symbolic as input: check if symbolic name can be resolved + conn_id = connection_table_get_id_by_name(table, symbolic_or_connid); + if (connection_id_is_valid(conn_id)) { + DEBUG("Resolved symbolic name '%s' to conn_id %u", symbolic_or_connid, + conn_id); + } else { + WARN("Symbolic name '%s' could not be resolved", symbolic_or_connid); + } + } + + return conn_id; +} + +#define symbolic_to_conn_id(forwarder, symbolic) \ + _symbolic_to_conn_id(forwarder, symbolic, false, 0) + +#define symbolic_to_conn_id_self(forwarder, symbolic, ingress_id) \ + _symbolic_to_conn_id(forwarder, symbolic, true, ingress_id) + +connection_t *getConnectionBySymbolicOrId(forwarder_t *forwarder, + const char *symbolic_or_connid) { + connection_table_t *table = forwarder_get_connection_table(forwarder); + unsigned conn_id = symbolic_to_conn_id(forwarder, symbolic_or_connid); + if (!connection_id_is_valid(conn_id)) return NULL; + + /* conn_id is assumed validated here */ + return connection_table_at(table, conn_id); +} + +/* Listener */ + +uint8_t *configuration_on_listener_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: listener add (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_listener_add_t *msg = (msg_listener_add_t *)packet; + cmd_listener_add_t *control = &msg->payload; + + switch (control->type) { + case FACE_TYPE_UDP_LISTENER: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_HICN_LISTENER: + break; + default: + goto NACK; + } + + listener_table_t *table = forwarder_get_listener_table(forwarder); + assert(table); + + /* Verify that the listener DOES NOT exist */ + listener_t *listener = listener_table_get_by_name(table, control->symbolic); + if (listener) { + ERROR("Listener with name=%s already exists", control->symbolic); + goto NACK; + } + + address_t address; + if (address_from_ip_port(&address, control->family, &control->address, + control->port) < 0) { + WARN( + "Unsupported address type for HICN (ingress id %u): " + "must be either IPV4 or IPV6", + ingress_id); + goto NACK; + } + + if (!face_type_is_defined(control->type)) { + WARN("[configuration_on_listener_add] Invalid listener type"); + goto NACK; + } + + listener = listener_table_get_by_address(table, control->type, &address); + if (listener) { + char addr_str[NI_MAXHOST]; + int port; + address_to_string(&address, addr_str, &port); + ERROR("Listener for address=%s, type=%s already exists", addr_str, + face_type_str(control->type)); + goto NACK; + } + + // NOTE: interface_name is expected NULL for hICN listener + + listener = listener_create(control->type, &address, control->interface_name, + control->symbolic, forwarder); + if (!listener) goto NACK; + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +unsigned symbolic_to_listener_id(forwarder_t *forwarder, + const char *symbolic_or_listener_id) { + unsigned listener_id; + const listener_table_t *table = forwarder_get_listener_table(forwarder); + + if (is_number(symbolic_or_listener_id, SYMBOLIC_NAME_LEN)) { + // XXX type issue ! XXX No check, see man + unsigned id = atoi(symbolic_or_listener_id); + if (id < 0) return LISTENER_ID_UNDEFINED; + listener_id = id; + + if (!listener_table_validate_id(table, listener_id)) { + ERROR("Listener ID %d not found", id); + listener_id = LISTENER_ID_UNDEFINED; + } + } else { + // case for symbolic as input: check if symbolic name can be resolved + listener_id = listener_table_get_id_by_name(table, symbolic_or_listener_id); + if (listener_id_is_valid(listener_id)) { + DEBUG("Resolved symbolic name '%s' to conn_id %u", + symbolic_or_listener_id, listener_id); + } else { + WARN("Symbolic name '%s' could not be resolved", symbolic_or_listener_id); + } + } + + return listener_id; +} + +uint8_t *configuration_on_listener_remove(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: listener remove (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_listener_remove_t *msg = (msg_listener_remove_t *)packet; + cmd_listener_remove_t *control = &msg->payload; + + unsigned listener_id = + symbolic_to_listener_id(forwarder, control->symbolicOrListenerid); + if (!listener_id_is_valid(listener_id)) { + ERROR("Invalid listener id=%u", listener_id); + goto NACK; + } + + listener_table_t *listener_table = forwarder_get_listener_table(forwarder); + listener_t *listener = listener_table_get_by_id(listener_table, listener_id); + if (!listener) { + ERROR("Listener ID not found, check list listeners"); + goto NACK; + } + + // Do not remove listener if it is the one curretly used to send the command + connection_table_t *conn_table = forwarder_get_connection_table(forwarder); + connection_t *curr_connection = + connection_table_get_by_id(conn_table, ingress_id); + const address_pair_t *pair = connection_get_pair(curr_connection); + if (address_equals(listener_get_address(listener), + address_pair_get_local(pair))) { + ERROR("Cannot remove current listener"); + goto NACK; + } + + connection_table_t *table = forwarder_get_connection_table(forwarder); + connection_t *connection; + connection_table_foreach(table, connection, { + const address_pair_t *pair = connection_get_pair(connection); + if (!address_equals(listener_get_address(listener), + address_pair_get_local(pair))) + continue; + + unsigned conn_id = connection_table_get_connection_id(table, connection); + /* Remove connection from the FIB */ + forwarder_remove_connection_id_from_routes(forwarder, conn_id); + + /* Remove connection */ + connection_table_remove_by_id(table, conn_id); + }); + + /* Remove listener */ + listener_table_remove_by_id(listener_table, listener_id); + listener_finalize(listener); + WITH_DEBUG(listener_table_print_by_key(listener_table);) + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +// TODO(eloparco): Unused forwarder param +static inline void fill_listener_command(forwarder_t *forwarder, + listener_t *listener, + cmd_listener_list_item_t *cmd) { + assert(forwarder); + assert(listener); + assert(cmd); + + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + const address_t *addr = listener_get_address(listener); + + cmd->id = (uint32_t)listener_get_id(listener); + cmd->type = (uint8_t)listener_get_type(listener); + + switch (addr->as_ss.ss_family) { + case AF_INET: + sin = (struct sockaddr_in *)addr; + cmd->family = AF_INET; + cmd->address.v4.as_inaddr = sin->sin_addr; + cmd->port = sin->sin_port; + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)addr; + cmd->family = AF_INET6; + cmd->address.v6.as_in6addr = sin6->sin6_addr; + cmd->port = sin6->sin6_port; + break; + default: + break; + } + + const char *name = listener_get_name(listener); + snprintf(cmd->name, SYMBOLIC_NAME_LEN, "%s", name); + const char *interface_name = listener_get_interface_name(listener); + snprintf(cmd->interface_name, SYMBOLIC_NAME_LEN, "%s", interface_name); +} + +uint8_t *configuration_on_listener_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: listener list (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + listener_table_t *table = forwarder_get_listener_table(forwarder); + size_t n = listener_table_len(table); + msg_listener_list_t *msg_received = (msg_listener_list_t *)packet; + uint8_t command_id = msg_received->header.command_id; + uint32_t seq_num = msg_received->header.seq_num; + + msg_listener_list_reply_t *msg; + msg_malloc_list(msg, command_id, n, seq_num) if (!msg) goto NACK; + + cmd_listener_list_item_t *payload = &msg->payload; + listener_t *listener; + listener_table_foreach(table, listener, { + fill_listener_command(forwarder, listener, payload); + payload++; + }); + + *reply_size = sizeof(msg->header) + n * sizeof(msg->payload); + return (uint8_t *)msg; + +NACK: + *reply_size = sizeof(msg_header_t); + make_nack(msg); + return (uint8_t *)msg; +} + +/* Connection */ + +uint8_t *configuration_on_connection_add(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: connection add (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_connection_add_t *msg = (msg_connection_add_t *)packet; + cmd_connection_add_t *control = &msg->payload; + + switch (control->type) { + case FACE_TYPE_UDP: + case FACE_TYPE_TCP: + case FACE_TYPE_HICN: + break; + default: + goto NACK; + } + + const char *symbolic_name = control->symbolic; + + if (!face_type_is_defined(control->type)) goto NACK; + + connection_table_t *table = forwarder_get_connection_table(forwarder); + if (connection_table_get_by_name(table, symbolic_name)) { + ERROR("Connection symbolic name already exists"); + goto NACK; + } + + address_pair_t pair; + if (address_pair_from_ip_port(&pair, control->family, &control->local_ip, + control->local_port, &control->remote_ip, + control->remote_port) < 0) + goto NACK; + + connection_t *connection = connection_table_get_by_pair(table, &pair); +#ifdef WITH_MAPME + connection_event_t event; +#endif /* WITH_MAPME */ + + if (!connection) { + connection = + connection_create(control->type, symbolic_name, &pair, forwarder); + if (!connection) { + ERROR("Failed to create %s connection", face_type_str(control->type)); + goto NACK; + } + +#ifdef WITH_MAPME + event = CONNECTION_EVENT_CREATE; +#endif /* WITH_MAPME */ + } else { + WARN("Connection already exists"); + +#ifdef WITH_MAPME + event = CONNECTION_EVENT_UPDATE; +#endif /* WITH_MAPME */ + } + +#ifdef WITH_POLICY + connection_set_tags(connection, control->tags); + connection_set_priority(connection, control->priority); +#endif /* WITH_POLICY */ + + connection_set_admin_state(connection, control->admin_state); + +#ifdef WITH_MAPME + /* Hook: new connection created through the control protocol */ + forwarder_on_connection_event(forwarder, connection, event); +#endif /* WITH_MAPME */ + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +/** + * Add an IP-based tunnel. + * + * The call can fail if the symbolic name is a duplicate. It could also fail if + * there's an problem creating the local side of the tunnel (i.e. the local + * socket address is not usable). + * + * @return true Tunnel added + * @return false Tunnel not added (an error) + */ + +uint8_t *configuration_on_connection_remove(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: connection remove (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_connection_remove_t *msg = (msg_connection_remove_t *)packet; + cmd_connection_remove_t *control = &msg->payload; + + unsigned conn_id = symbolic_to_conn_id_self( + forwarder, control->symbolic_or_connid, ingress_id); + if (!connection_id_is_valid(conn_id)) { + ERROR("Invalid connection id=%u", conn_id); + goto NACK; + } + + if (strcmp(control->symbolic_or_connid, "SELF") != 0 && + conn_id == ingress_id) { + ERROR("Cannot remove current connection"); + goto NACK; + } + + /* Remove connection from the FIB */ + forwarder_remove_connection_id_from_routes(forwarder, conn_id); + + /* Remove connection */ + connection_table_t *table = forwarder_get_connection_table(forwarder); + connection_t *connection = connection_table_get_by_id(table, conn_id); + connection_table_remove_by_id(table, conn_id); + + // Don't close the fd for SELF otherwise it won't be possible + // to send the reply back + if (strcmp(control->symbolic_or_connid, "SELF") != 0) + connection_finalize(connection); + WITH_DEBUG(connection_table_print_by_pair(table);) + +#ifdef WITH_MAPME + /* Hook: new connection created through the control protocol */ + forwarder_on_connection_event(forwarder, NULL, CONNECTION_EVENT_DELETE); +#endif /* WITH_MAPME */ + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +static inline void tolower_str(char *str) { + char *p = str; + for (; *p; p++) *p = tolower(*p); +} + +// TODO(eloparco): Forwarder param not used +static inline void fill_connections_command(forwarder_t *forwarder, + connection_t *connection, + cmd_connection_list_item_t *cmd) { + assert(forwarder); + assert(connection); + assert(cmd); + + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + const address_pair_t *pair = connection_get_pair(connection); + + cmd->id = connection_get_id(connection), + cmd->state = connection_get_state(connection), + cmd->admin_state = connection_get_admin_state(connection), + cmd->type = connection_get_type(connection), +#ifdef WITH_POLICY + cmd->priority = connection_get_priority(connection), + cmd->tags = connection_get_tags(connection), +#endif /* WITH_POLICY */ + + snprintf(cmd->name, SYMBOLIC_NAME_LEN, "%s", connection_get_name(connection)); + tolower_str(cmd->name); + + snprintf(cmd->interface_name, SYMBOLIC_NAME_LEN, "%s", + connection_get_interface_name(connection)); + + switch (pair->local.as_ss.ss_family) { + case AF_INET: + cmd->family = AF_INET; + + sin = (struct sockaddr_in *)(&pair->local); + cmd->local_port = sin->sin_port; + cmd->local_addr.v4.as_inaddr = sin->sin_addr; + + sin = (struct sockaddr_in *)(&pair->remote); + cmd->remote_port = sin->sin_port; + cmd->remote_addr.v4.as_inaddr = sin->sin_addr; + break; + + case AF_INET6: + cmd->family = AF_INET6; + + sin6 = (struct sockaddr_in6 *)(&pair->local); + cmd->local_port = sin6->sin6_port; + cmd->local_addr.v6.as_in6addr = sin6->sin6_addr; + + sin6 = (struct sockaddr_in6 *)(&pair->remote); + cmd->remote_port = sin6->sin6_port; + cmd->remote_addr.v6.as_in6addr = sin6->sin6_addr; + break; + + default: + break; + } +} + +uint8_t *configuration_on_connection_list(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: connection list (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + connection_table_t *table = forwarder_get_connection_table(forwarder); + // -1 since current connection (i.e. the one used to send + // the command) is not considered + size_t n = connection_table_len(table) - 1; + msg_connection_list_t *msg_received = (msg_connection_list_t *)packet; + uint8_t command_id = msg_received->header.command_id; + uint32_t seq_num = msg_received->header.seq_num; + + msg_connection_list_reply_t *msg; + msg_malloc_list(msg, command_id, n, seq_num) if (!msg) goto NACK; + + cmd_connection_list_item_t *payload = &msg->payload; + connection_t *connection; + connection_table_foreach(table, connection, { + if (connection->id == ingress_id) continue; + fill_connections_command(forwarder, connection, payload); + payload++; + }); + + *reply_size = sizeof(msg->header) + n * sizeof(msg->payload); + return (uint8_t *)msg; + +NACK: + *reply_size = sizeof(msg_header_t); + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_connection_set_admin_state(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + assert(forwarder); + assert(packet); + + msg_connection_set_admin_state_t *msg = + (msg_connection_set_admin_state_t *)packet; + cmd_connection_set_admin_state_t *control = &msg->payload; + + if ((control->admin_state != FACE_STATE_UP) && + (control->admin_state != FACE_STATE_DOWN)) + goto NACK; + + connection_t *conn = + getConnectionBySymbolicOrId(forwarder, control->symbolic_or_connid); + if (!conn) goto NACK; + + connection_set_admin_state(conn, control->admin_state); + +#ifdef WITH_MAPME + /* Hook: connection event */ + forwarder_on_connection_event(forwarder, conn, + control->admin_state == FACE_STATE_UP + ? CONNECTION_EVENT_SET_UP + : CONNECTION_EVENT_SET_DOWN); +#endif /* WITH_MAPME */ + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_connection_update(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + assert(forwarder); + assert(packet); + +#ifdef WITH_POLICY + msg_connection_update_t *msg = (msg_connection_update_t *)packet; + cmd_connection_update_t *control = &msg->payload; + + connection_t *conn = + getConnectionBySymbolicOrId(forwarder, control->symbolic_or_connid); + if (!conn) goto NACK; + + connection_set_tags(conn, control->tags); + connection_set_admin_state(conn, control->admin_state); + if (control->priority > 0) connection_set_priority(conn, control->priority); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: +#endif /* WITH_POLICY */ + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_connection_set_priority(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + assert(forwarder); + assert(packet); + +#ifdef WITH_POLICY + msg_connection_set_priority_t *msg = (msg_connection_set_priority_t *)packet; + cmd_connection_set_priority_t *control = &msg->payload; + + connection_t *conn = + getConnectionBySymbolicOrId(forwarder, control->symbolic_or_connid); + if (!conn) goto NACK; + + connection_set_priority(conn, control->priority); + +#ifdef WITH_MAPME + /* Hook: connection event */ + forwarder_on_connection_event(forwarder, conn, + CONNECTION_EVENT_PRIORITY_CHANGED); +#endif /* WITH_MAPME */ + + make_ack(msg); + return (uint8_t *)msg; + +NACK: +#endif /* WITH_POLICY */ + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_connection_set_tags(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + assert(forwarder); + assert(packet); + +#ifdef WITH_POLICY + msg_connection_set_tags_t *msg = (msg_connection_set_tags_t *)packet; + cmd_connection_set_tags_t *control = &msg->payload; + + connection_t *conn = + getConnectionBySymbolicOrId(forwarder, control->symbolic_or_connid); + if (!conn) goto NACK; + + connection_set_tags(conn, control->tags); + +#ifdef WITH_MAPME + /* Hook: connection event */ + forwarder_on_connection_event(forwarder, conn, CONNECTION_EVENT_TAGS_CHANGED); +#endif /* WITH_MAPME */ + + make_ack(msg); + return (uint8_t *)msg; + +NACK: +#endif /* WITH_POLICY */ + make_nack(msg); + return (uint8_t *)msg; +} + +/* Route */ + +uint8_t *configuration_on_route_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + INFO("CMD: route add (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_route_add_t *msg = (msg_route_add_t *)packet; + cmd_route_add_t *control = &msg->payload; + + unsigned conn_id = symbolic_to_conn_id_self( + forwarder, control->symbolic_or_connid, ingress_id); + if (!connection_id_is_valid(conn_id)) goto NACK; + + ip_prefix_t prefix = {.family = control->family, + .address = control->address, + .len = control->len}; + + if (!forwarder_add_or_update_route(forwarder, &prefix, conn_id)) goto NACK; + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_route_remove(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: route remove (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_route_remove_t *msg = (msg_route_remove_t *)packet; + cmd_route_remove_t *control = &msg->payload; + + unsigned conn_id = + symbolic_to_conn_id(forwarder, control->symbolic_or_connid); + if (!connection_id_is_valid(conn_id)) goto NACK; + + ip_prefix_t prefix = {.family = control->family, + .address = control->address, + .len = control->len}; + + if (!forwarder_remove_route(forwarder, &prefix, conn_id)) goto NACK; + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_route_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + INFO("CMD: route list (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + msg_route_list_t *msg_received = (msg_route_list_t *)packet; + uint8_t command_id = msg_received->header.command_id; + uint32_t seq_num = msg_received->header.seq_num; + const fib_t *fib = forwarder_get_fib(forwarder); + fib_entry_t *entry; + + /* + * Two step approach to precompute the number of entries to allocate + * + * NOTE: we might have routes with no or multiple next hops. + */ + size_t n = 0; + fib_foreach_entry(fib, entry, { + const nexthops_t *nexthops = fib_entry_get_nexthops(entry); + assert(nexthops_get_len(nexthops) == nexthops_get_curlen(nexthops)); + n += nexthops_get_len(nexthops); + }); + + msg_route_list_reply_t *msg; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_route_list_item_t *payload = &msg->payload; + fib_foreach_entry(fib, entry, { + const nexthops_t *nexthops = fib_entry_get_nexthops(entry); + assert(nexthops_get_len(nexthops) == nexthops_get_curlen(nexthops)); + size_t num_nexthops = nexthops_get_len(nexthops); + + if (num_nexthops == 0) continue; + + NameBitvector *prefix = name_GetContentName(fib_entry_get_prefix(entry)); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + address_t address; + nameBitvector_ToAddress(prefix, &address); + switch (address_family(&address)) { + case AF_INET: + payload->family = AF_INET; + payload->address.v4.as_inaddr = address4_ip(&address); + break; + case AF_INET6: + payload->family = AF_INET6; + payload->address.v6.as_in6addr = address6_ip(&address); + break; + default: + break; + } + payload->connection_id = nexthop; + payload->len = nameBitvector_GetLength(prefix); + payload->cost = DEFAULT_COST; + + payload++; + }); + }); + + *reply_size = sizeof(msg->header) + n * sizeof(msg->payload); + return (uint8_t *)msg; + +NACK: + *reply_size = sizeof(msg_header_t); + make_nack(msg); + return (uint8_t *)msg; +} + +/* Cache */ + +uint8_t *configuration_on_cache_set_store(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: cache set store (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_cache_set_store_t *msg = (msg_cache_set_store_t *)packet; + cmd_cache_set_store_t *control = &msg->payload; + + if ((control->activate != 0) && (control->activate != 1)) goto NACK; + bool value = (bool)control->activate; + + forwarder_cs_set_store(forwarder, value); + assert(forwarder_cs_get_store(forwarder) == value); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_cache_set_serve(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: cache set serve (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_cache_set_serve_t *msg = (msg_cache_set_serve_t *)packet; + cmd_cache_set_serve_t *control = &msg->payload; + + if ((control->activate != 0) && (control->activate != 1)) goto NACK; + bool value = (bool)control->activate; + + forwarder_cs_set_serve(forwarder, value); + assert(forwarder_cs_get_serve(forwarder) == value); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_cache_clear(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + INFO("CMD: cache clear (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_cache_clear_t *msg = (msg_cache_clear_t *)packet; + + forwarder_cs_clear(forwarder); + + make_ack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_cache_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + INFO("CMD: cache list (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + msg_cache_list_t *msg_received = (msg_cache_list_t *)packet; + uint32_t seq_num = msg_received->header.seq_num; + + msg_cache_list_reply_t *msg = malloc(sizeof(*msg)); + *msg = (msg_cache_list_reply_t){ + .header = {.message_type = RESPONSE_LIGHT, + .length = 1, + .seq_num = seq_num}, + .payload = { + .store_in_cs = forwarder_cs_get_store(forwarder), + .serve_from_cs = forwarder_cs_get_serve(forwarder), + .cs_size = forwarder_cs_get_size(forwarder), + .num_stale_entries = forwarder_cs_get_num_stale_entries(forwarder)}}; + + *reply_size = sizeof(*msg); + return (uint8_t *)msg; +} + +/* Strategy */ + +uint8_t *configuration_on_strategy_set(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: strategy set (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_strategy_set_t *msg = (msg_strategy_set_t *)packet; + cmd_strategy_set_t *control = &msg->payload; + + char prefix_s[MAXSZ_IP_PREFIX]; + ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len, + }; + int rc = ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, &prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) goto NACK; + + strategy_type_t strategy = control->type; + configuration_t *config = forwarder_get_configuration(forwarder); + strategy_type_t existingFwdStrategy = + configuration_get_strategy(config, prefix_s); + strategy_options_t *options = NULL; + + Name name_prefix = EMPTY_NAME; + name_CreateFromAddress(&name_prefix, control->family, control->address, + control->len); + + // The strategy is not present in the hash table + // or has to be updated or to be restarted + if (existingFwdStrategy == STRATEGY_TYPE_UNDEFINED || + strategy != existingFwdStrategy || + (strategy == existingFwdStrategy && strategy == STRATEGY_TYPE_BESTPATH)) { + configuration_set_strategy(config, prefix_s, strategy); + + forwarder_set_strategy(forwarder, &name_prefix, strategy, options); + } else { + WITH_WARN({ + char *nameString = name_ToString(&name_prefix); + WARN("Strategy for prefix %s not updated", nameString); + free(nameString); + }) + } + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_strategy_add_local_prefix(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: strategy add local prefix (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_strategy_add_local_prefix_t *msg = + (msg_strategy_add_local_prefix_t *)packet; + cmd_strategy_add_local_prefix_t *control = &msg->payload; + + char prefix_s[MAXSZ_IP_PREFIX]; + ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len, + }; + int rc = ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, &prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) goto NACK; + + strategy_type_t strategy = control->type; + configuration_t *config = forwarder_get_configuration(forwarder); + strategy_type_t existingFwdStrategy = + configuration_get_strategy(config, prefix_s); + + if (strategy != existingFwdStrategy) goto NACK; + + if (strategy != STRATEGY_TYPE_BESTPATH && + strategy != STRATEGY_TYPE_REPLICATION) + goto NACK; + + Name name_prefix = EMPTY_NAME; + name_CreateFromAddress(&name_prefix, control->family, control->address, + control->len); + + strategy_options_t options; + Name local_prefix = EMPTY_NAME; + name_CreateFromAddress(&local_prefix, control->local_family, + control->local_address, control->local_len); + + // for the moment bestpath and replication are the same but we distinguish the + // two in case they will diverge in the future + if (strategy == STRATEGY_TYPE_BESTPATH) { + options.bestpath.local_prefixes = create_local_prefixes(); + local_prefixes_add_prefix(options.bestpath.local_prefixes, &local_prefix); + } else { + options.replication.local_prefixes = create_local_prefixes(); + local_prefixes_add_prefix(options.replication.local_prefixes, + &local_prefix); + } + + forwarder_add_strategy_options(forwarder, &name_prefix, strategy, &options); + + free_local_prefixes(options.bestpath.local_prefixes); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +/* WLDR */ + +uint8_t *configuration_on_wldr_set(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + assert(forwarder); + assert(packet); + + msg_wldr_set_t *msg = (msg_wldr_set_t *)packet; + cmd_wldr_set_t *control = &msg->payload; + + if ((control->activate != 0) && (control->activate != 1)) goto NACK; + bool value = (bool)control->activate; + + unsigned conn_id = + symbolic_to_conn_id(forwarder, control->symbolic_or_connid); + if (!connection_id_is_valid(conn_id)) goto NACK; + + connection_table_t *table = forwarder_get_connection_table(forwarder); + connection_t *conn = connection_table_at(table, conn_id); + + if (value) connection_wldr_enable(conn, value); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +/* Punting */ + +uint8_t *configuration_on_punting_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + // #if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) + msg_punting_add_t *msg = (msg_punting_add_t *)packet; + +#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) + cmd_punting_add_t *control = &msg->payload; + if (ip_address_empty(&control->address)) goto NACK; + + /* This is for hICN listeners only */ + // XXX add check ! + // comments: + // EncapType: I use the Hicn encap since the punting is available only for + // Hicn listeners LocalAddress: The only listern for which we need punting + // rules is the main one, which has no address + // so I create a fake empty address. This need to be consistent + // with the address set at creation time + address_t fakeaddr; + memset(&fakeaddr, 0, sizeof(address_t)); + fakeaddr = ADDRESS_ANY(control->family, DEFAULT_PORT); + + listener_table_t *table = forwarder_get_listener_table(forwarder); + listener_t *listener = + listener_table_get_by_address(table, FACE_TYPE_HICN, &fakeaddr); + if (!listener) { + ERROR("the main listener does not exist"); + goto NACK; + } + + ip_prefix_t prefix = {.family = control->family, + .address = control->address, + .len = control->len}; + char prefix_s[MAXSZ_IP_PREFIX]; + int rc = ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, &prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) goto NACK; + + if (listener_punt(listener, prefix_s) < 0) { + ERROR("error while adding the punting rule"); + goto NACK; + } + + make_ack(msg); + return (uint8_t *)msg; + +NACK: +#endif + make_nack(msg); + return (uint8_t *)msg; +} + +/* MAP-Me */ + +#ifdef WITH_MAPME +uint8_t *configuration_on_mapme_enable(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: mapme enable (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_mapme_enable_t *msg = (msg_mapme_enable_t *)packet; + cmd_mapme_enable_t *control = &msg->payload; + + if ((control->activate != 0) && (control->activate != 1)) goto NACK; + bool value = (bool)control->activate; + + INFO("MAP-Me SET enable: %s", value ? "on" : "off"); + mapme_t *mapme = forwarder_get_mapme(forwarder); + if (!mapme) goto NACK; + mapme_set_enable(mapme, value); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_mapme_set_discovery(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: mapme discovery (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_mapme_set_discovery_t *msg = (msg_mapme_set_discovery_t *)packet; + cmd_mapme_set_discovery_t *control = &msg->payload; + + if ((control->activate != 0) && (control->activate != 1)) goto NACK; + bool value = (bool)control->activate; + + INFO("MAP-Me SET discovery: %s", value ? "on" : "off"); + mapme_t *mapme = forwarder_get_mapme(forwarder); + if (!mapme) goto NACK; + mapme_set_discovery(mapme, value); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_mapme_set_timescale(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: mapme timescale (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_mapme_set_timescale_t *msg = (msg_mapme_set_timescale_t *)packet; + cmd_mapme_set_timescale_t *control = &msg->payload; + + INFO("MAP-Me SET timescale: %u", control->timePeriod); + mapme_t *mapme = forwarder_get_mapme(forwarder); + if (!mapme) goto NACK; + mapme_set_timescale(mapme, control->timePeriod); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_mapme_set_retx(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: mapme retransmission (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_mapme_set_retx_t *msg = (msg_mapme_set_retx_t *)packet; + cmd_mapme_set_retx_t *control = &msg->payload; + + INFO("MAP-Me SET retx: %u", control->timePeriod); + mapme_t *mapme = forwarder_get_mapme(forwarder); + if (!mapme) goto NACK; + mapme_set_retransmision(mapme, control->timePeriod); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_mapme_send_update(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + assert(forwarder); + assert(packet); + + INFO("CMD: mapme send update (ingress=%d)", ingress_id); + msg_mapme_send_update_t *msg = (msg_mapme_send_update_t *)packet; + + *reply_size = sizeof(msg_header_t); + + fib_t *fib = forwarder_get_fib(forwarder); + if (!fib) goto NACK; + + mapme_t *mapme = forwarder_get_mapme(forwarder); + + /* + * The command triggers a mapme update for all prefixes produced on this face + * */ + fib_entry_t *entry; + fib_foreach_entry(fib, entry, { + const nexthops_t *nexthops = fib_entry_get_nexthops(entry); + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + if (nexthop != ingress_id) continue; + /* This entry points to the producer face */ + mapme_set_all_adjacencies(mapme, entry); + break; + }); + }); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} +#endif /* WITH_MAPME */ + +/* Policy */ + +uint8_t *configuration_on_policy_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + assert(forwarder); + assert(packet); + +#ifdef WITH_POLICY + msg_policy_add_t *msg = (msg_policy_add_t *)packet; + cmd_policy_add_t *control = &msg->payload; + + ip_prefix_t prefix = {.family = control->family, + .address = control->address, + .len = control->len}; + + if (!forwarder_add_or_update_policy(forwarder, &prefix, &control->policy)) + goto NACK; + + make_ack(msg); + return (uint8_t *)msg; + +NACK: +#endif /* WITH_POLICY */ + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_policy_remove(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + assert(forwarder); + assert(packet); + +#ifdef WITH_POLICY + msg_policy_remove_t *msg = (msg_policy_remove_t *)packet; + cmd_policy_remove_t *control = &msg->payload; + + ip_prefix_t prefix = {.family = control->family, + .address = control->address, + .len = control->len}; + + if (!forwarder_remove_policy(forwarder, &prefix)) goto NACK; + + make_ack(msg); + return (uint8_t *)msg; + +NACK: +#endif /* WITH_POLICY */ + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_policy_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + assert(forwarder); + assert(packet); + + const fib_t *fib = forwarder_get_fib(forwarder); + assert(fib); + size_t n = fib_get_size(fib); + +#ifdef WITH_POLICY + msg_policy_list_t *msg_received = (msg_policy_list_t *)packet; + uint8_t command_id = msg_received->header.command_id; + uint32_t seq_num = msg_received->header.seq_num; + + msg_policy_list_reply_t *msg; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_policy_list_item_t *payload = &msg->payload; + + fib_entry_t *entry; + + fib_foreach_entry(fib, entry, { + NameBitvector *prefix = name_GetContentName(fib_entry_get_prefix(entry)); + address_t address; + nameBitvector_ToAddress(prefix, &address); + + switch (address_family(&address)) { + case AF_INET: + payload->family = AF_INET; + payload->address.v4.as_inaddr = address4_ip(&address); + break; + + case AF_INET6: + payload->family = AF_INET6; + payload->address.v6.as_in6addr = address6_ip(&address); + break; + + default: + break; + } + payload->len = nameBitvector_GetLength(prefix); + payload->policy = fib_entry_get_policy(entry); + + payload++; + }); + + return (uint8_t *)msg; +#endif /* WITH_POLICY */ + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +/* Subscription */ + +uint8_t *configuration_on_subscription_add(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: subscription add (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_subscription_add_t *msg = (msg_subscription_add_t *)packet; + cmd_subscription_add_t *control = &msg->payload; + hc_topics_t topics = control->topics; + + subscription_table_t *subscriptions = forwarder_get_subscriptions(forwarder); + assert(subscriptions); + + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + ingress_id); + if (ret < 0) goto NACK; + + WITH_DEBUG(subscription_table_print(subscriptions);) + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_subscription_remove(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + INFO("CMD: subscription remove (ingress=%d)", ingress_id); + assert(forwarder); + assert(packet); + + *reply_size = sizeof(msg_header_t); + msg_subscription_add_t *msg = (msg_subscription_add_t *)packet; + cmd_subscription_add_t *control = &msg->payload; + hc_topics_t topics = control->topics; + + subscription_table_t *subscriptions = forwarder_get_subscriptions(forwarder); + assert(subscriptions); + + subscription_table_remove_topics_for_connection(subscriptions, topics, + ingress_id); + WITH_DEBUG(subscription_table_print(subscriptions);) + + make_ack(msg); + return (uint8_t *)msg; +} + +uint8_t *command_process(forwarder_t *forwarder, uint8_t *packet, + command_type_t command_type, unsigned ingress_id, + size_t *reply_size) { + uint8_t *reply = NULL; + + /* + * For most commands, the packet will simply be transformed into an ack. + * For list commands, a new message will be allocated, and the return value + * might eventually be NULL in case of an error. That is why the free the + * reply at the end in these circumstances. + * + * XXX rework this part. + */ + switch (command_type) { +#define _(l, u) \ + case COMMAND_TYPE_##u: \ + reply = configuration_on_##l(forwarder, packet, ingress_id, reply_size); \ + assert(reply); \ + break; + foreach_command_type +#undef _ + case COMMAND_TYPE_UNDEFINED : case COMMAND_TYPE_N + : ERROR("Unexpected command type"); + reply = packet; + make_nack(reply); + if (reply_size) *reply_size = sizeof(msg_header_t); + break; + } + + return reply; +} + +ssize_t command_process_msgbuf(forwarder_t *forwarder, msgbuf_t *msgbuf) { + assert(forwarder); + assert(msgbuf); + + uint8_t *packet = msgbuf_get_packet(msgbuf); + unsigned ingress_id = msgbuf_get_connection_id(msgbuf); + + uint8_t *reply = NULL; + size_t reply_size = 0; + + command_type_t command_type = msgbuf_get_command_type(msgbuf); + + reply = + command_process(forwarder, packet, command_type, ingress_id, &reply_size); + if (connection_id_is_valid(msgbuf->connection_id)) { + connection_table_t *table = forwarder_get_connection_table(forwarder); + const connection_t *connection = connection_table_at(table, ingress_id); + connection_send_packet(connection, reply, reply_size); + } + + switch (msgbuf->command.type) { + case COMMAND_TYPE_LISTENER_LIST: + case COMMAND_TYPE_CONNECTION_LIST: + case COMMAND_TYPE_ROUTE_LIST: + case COMMAND_TYPE_POLICY_LIST: + /* Free replies that have been allocated (not NACK's) */ + if (((msg_header_t *)reply)->header.message_type != NACK_LIGHT) + free(reply); + break; + default: + break; + } + + return msgbuf_get_len(msgbuf); +} diff --git a/hicn-light/src/hicn/config/commands.h b/hicn-light/src/hicn/config/commands.h new file mode 100644 index 000000000..cedf4de01 --- /dev/null +++ b/hicn-light/src/hicn/config/commands.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file commands.h + * @brief hicn-light configuration, such as in-band commands or CLI + * + * Manages all user configuration of the system, such as from the CLI or web + * interface It remembers the user commands and will be able to write out a + * config file. + * + */ + +#ifndef HICNLIGHT_COMMANDS_H +#define HICNLIGHT_COMMANDS_H + +#include "../core/msgbuf.h" +#include "../core/strategy.h" +#include <hicn/ctrl/api.h> +#include <hicn/ctrl/hicn-light-ng.h> + +uint8_t *command_process(forwarder_t *forwarder, uint8_t *packet, + command_type_t command_type, unsigned ingress_id, + size_t *reply_size); + +ssize_t command_process_msgbuf(forwarder_t *forwarder, msgbuf_t *msgbuf); + +uint8_t *configuration_on_listener_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_listener_remove(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_listener_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_connection_add(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_connection_remove(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_connection_list(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_connection_set_admin_state(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_connection_update(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_connection_set_priority(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_connection_set_tags(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_route_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_route_remove(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_route_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_cache_set_store(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_cache_set_serve(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_cache_clear(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_strategy_set(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_strategy_add_local_prefix(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_wldr_set(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_punting_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +#ifdef WITH_MAPME +uint8_t *configuration_on_mapme_enable(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_mapme_set_discovery(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_mapme_set_timescale(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_mapme_set_retx(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_mapme_send_update(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); +#endif /* WITH_MAPME */ + +uint8_t *configuration_on_policy_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +uint8_t *configuration_on_policy_remove(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, + size_t *reply_size); + +uint8_t *configuration_on_policy_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +#endif // HICNLIGHT_COMMANDS_H diff --git a/hicn-light/src/hicn/config/configuration.c b/hicn-light/src/hicn/config/configuration.c index e414f05e3..9123ceebf 100644 --- a/hicn-light/src/hicn/config/configuration.c +++ b/hicn-light/src/hicn/config/configuration.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -26,1504 +26,169 @@ #include <unistd.h> #endif #include <ctype.h> -#include <parc/assert/parc_Assert.h> #include <hicn/hicn-light/config.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <parc/algol/parc_HashMap.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_String.h> - -#include <hicn/config/configurationListeners.h> -#include <hicn/config/symbolicNameTable.h> - #include <hicn/core/connection.h> -#include <hicn/core/connectionTable.h> +#include <hicn/core/connection_table.h> #include <hicn/core/forwarder.h> -#include <hicn/core/system.h> +//#include <hicn/core/system.h> #ifdef WITH_MAPME #include <hicn/core/mapme.h> #endif /* WITH_MAPME */ -#include <hicn/io/streamConnection.h> - -#include <hicn/io/hicnTunnel.h> -#include <hicn/io/tcpTunnel.h> -#include <hicn/io/udpTunnel.h> +#include <hicn/core/listener.h> //the listener list +#include <hicn/core/listener_table.h> +#include <hicn/ctrl/hicn-light-ng.h> +#include <hicn/utils/punting.h> +#include <hicn/util/log.h> +#include <hicn/face.h> -#include <parc/algol/parc_Unsigned.h> -#include <hicn/io/listener.h> //the listener list -#include <hicn/io/listenerSet.h> // needed to print -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -#include <hicn/utils/address.h> +#include "configuration.h" #define ETHERTYPE 0x0801 - -struct configuration { - Forwarder *forwarder; - Logger *logger; - - size_t maximumContentObjectStoreSize; - - // map from prefix (parcString) to strategy (parcString) - PARCHashMap *strategy_map; - - // translates between a symblic name and a connection id - SymbolicNameTable *symbolicNameTable; +#define DEFAULT_COST 1 +#define DEFAULT_PORT 1234 +#define DEFAULT_LOGLEVEL "info" +#define DEFAULT_CS_CAPACITY 100000 + +#define msg_malloc_list(msg, N, seq_number) \ + do { \ + msg = malloc(sizeof((msg)->header) + N * sizeof((msg)->payload)); \ + (msg)->header.message_type = RESPONSE_LIGHT; \ + (msg)->header.length = (uint16_t)(N); \ + (msg)->header.seq_num = (seq_number); \ + } while (0); + +struct configuration_s { + const char *fn_config; + uint16_t port; + uint16_t configuration_port; + size_t cs_capacity; + int loglevel; + const char *logfile; + int logfile_fd; + bool daemon; + kh_strategy_map_t *strategy_map; }; -// ======================================================================================== - -Connection * -getConnectionBySymbolicOrId(Configuration * config, const char * symbolicOrConnid) -{ - ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder); - unsigned connid; - Connection *conn = NULL; - - /* Try to resolve an eventual symbolic name as input */ - if (utils_IsNumber(symbolicOrConnid)) { - connid = (unsigned int)strtold(symbolicOrConnid, NULL); - - } else { - connid = symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid); - if (connid == UINT32_MAX) { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Warning)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "Symbolic name '%s' could not be resolved", - symbolicOrConnid); - } - } - } - - /* Get connection by ID */ - conn = (Connection *)connectionTable_FindById( table, connid); - if (!conn) { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Warning)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "ConnID not found, check list connections"); - } - } - - return conn; -} - -// ======================================================================================== - -Configuration *configuration_Create(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter hicn-fwd must be non-null"); - Configuration *config = parcMemory_AllocateAndClear(sizeof(Configuration)); - parcAssertNotNull(config, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Configuration)); - config->forwarder = forwarder; - config->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - config->maximumContentObjectStoreSize = 100000; - config->strategy_map = parcHashMap_Create(); - config->symbolicNameTable = symbolicNameTable_Create(); - - return config; -} - -void configuration_Destroy(Configuration **configPtr) { - parcAssertNotNull(configPtr, "Parameter must be non-null double poitner"); - parcAssertNotNull(*configPtr, - "Parameter must dereference to non-null pointer"); - - Configuration *config = *configPtr; - logger_Release(&config->logger); - parcHashMap_Release(&(config->strategy_map)); - symbolicNameTable_Destroy(&config->symbolicNameTable); - parcMemory_Deallocate((void **)&config); - *configPtr = NULL; -} - -struct iovec *configuration_ProcessRegisterHicnPrefix(Configuration *config, - struct iovec *request, - unsigned ingressId) { - header_control_message *header = request[0].iov_base; - add_route_command *control = request[1].iov_base; - - bool success = false; - - const char *symbolicOrConnid = control->symbolicOrConnid; - - if (strcmp(symbolicOrConnid, "SELF") == 0) { - success = forwarder_AddOrUpdateRoute(config->forwarder, control, ingressId); - } else if (utils_IsNumber(symbolicOrConnid)) { - // case for connid as input - unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL); - ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder); - - // check if iconnID present in the fwd table - if (connectionTable_FindById(table, connid)) { - success = forwarder_AddOrUpdateRoute(config->forwarder, control, connid); - } else { - logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "ConnID not found, check list connections"); - // failure - } - - } else { - // case for symbolic as input: check if symbolic name can be resolved - unsigned connid = - symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid); - // connid = UINT_MAX when symbolicName is not found - if (connid != UINT32_MAX) { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Debug)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug, - __func__, "Add route resolve name '%s' to connid %u", - symbolicOrConnid, connid); - } - - success = forwarder_AddOrUpdateRoute(config->forwarder, control, connid); - - } else { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Warning)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Warning, - __func__, - "Add route symbolic name '%s' could not be resolved", - symbolicOrConnid); - } - // failure - } - } - - // generate ACK/NACK - struct iovec *response; - - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(add_route_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(add_route_command)); - } - - return response; -} - -struct iovec *configuration_ProcessUnregisterHicnPrefix(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - remove_route_command *control = request[1].iov_base; - - bool success = false; - - const char *symbolicOrConnid = control->symbolicOrConnid; - - if (utils_IsNumber(symbolicOrConnid)) { - // case for connid as input - unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL); - ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder); - - // check if interface index present in the fwd table - if (connectionTable_FindById(table, connid)) { - success = forwarder_RemoveRoute(config->forwarder, control, connid); - } else { - logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "ConnID not found, check list connections"); - // failure - } - - } else { - // case for symbolic as input: chech if symbolic name can be resolved - unsigned connid = - symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid); - // connid = UINT_MAX when symbolicName is not found - if (connid != UINT32_MAX) { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Debug)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug, - __func__, "Remove route resolve name '%s' to connid %u", - symbolicOrConnid, connid); - } - success = forwarder_RemoveRoute(config->forwarder, control, connid); - } else { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Warning)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Warning, - __func__, - "Remove route symbolic name '%s' could not be resolved", - symbolicOrConnid); - } - // failure - } - } - - // generate ACK/NACK - struct iovec *response; - - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(remove_route_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(remove_route_command)); - } - - return response; -} - -struct iovec *configuration_ProcessRegistrationList(Configuration *config, - struct iovec *request) { - FibEntryList *fibList = forwarder_GetFibEntries(config->forwarder); - - size_t payloadSize = fibEntryList_Length(fibList); - size_t effective_payloadSize = 0; - size_t pointerLocation = 0; - struct sockaddr_in tmpAddr; - struct sockaddr_in6 tmpAddr6; - - // allocate payload, cast from void* to uint8_t* = bytes granularity - uint8_t *payloadResponse = - parcMemory_AllocateAndClear(sizeof(list_routes_command) * payloadSize); - - for (size_t i = 0; i < fibEntryList_Length(fibList); i++) { - FibEntry *entry = (FibEntry *)fibEntryList_Get(fibList, i); - NameBitvector *prefix = name_GetContentName(fibEntry_GetPrefix(entry)); - const NumberSet *nexthops = fibEntry_GetNexthops(entry); - - if (numberSet_Length(nexthops) == 0) - continue; - - if (numberSet_Length(nexthops) > 1) { - // payload extended, need reallocate, further entries via nexthops - payloadSize = payloadSize + numberSet_Length(nexthops) - 1; - payloadResponse = (uint8_t *) parcMemory_Reallocate( - payloadResponse, sizeof(list_routes_command) * payloadSize); - } - - for (size_t j = 0; j < numberSet_Length(nexthops); j++) { - list_routes_command *listRouteCommand = - (list_routes_command *)(payloadResponse + - (pointerLocation * - sizeof(list_routes_command))); - - Address *addressEntry = nameBitvector_ToAddress(prefix); - if (addressGetType(addressEntry) == ADDR_INET) { - addressGetInet(addressEntry, &tmpAddr); - listRouteCommand->addressType = ADDR_INET; - listRouteCommand->address.v4.as_inaddr = tmpAddr.sin_addr; - } else if (addressGetType(addressEntry) == ADDR_INET6) { - addressGetInet6(addressEntry, &tmpAddr6); - listRouteCommand->addressType = ADDR_INET6; - listRouteCommand->address.v6.as_in6addr = tmpAddr6.sin6_addr; - } - listRouteCommand->connid = numberSet_GetItem(nexthops, j); - listRouteCommand->len = nameBitvector_GetLength(prefix); - listRouteCommand->cost = 1; // cost - - pointerLocation++; - effective_payloadSize++; - addressDestroy(&addressEntry); - } - } - - // send response - header_control_message *header = request[0].iov_base; - header->messageType = RESPONSE_LIGHT; - header->length = (unsigned)effective_payloadSize; - - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); - - response[0].iov_base = header; - response[0].iov_len = sizeof(header_control_message); - response[1].iov_base = payloadResponse; - response[1].iov_len = sizeof(list_routes_command) * effective_payloadSize; - - fibEntryList_Destroy(&fibList); - return response; -} - -static void configuration_SendResponse(Configuration *config, struct iovec *msg, - unsigned egressId) { - ConnectionTable *connectionTable = - forwarder_GetConnectionTable(config->forwarder); - const Connection *conn = connectionTable_FindById(connectionTable, egressId); - - if (conn == NULL) { - return; - } - connection_SendIOVBuffer(conn, msg, 2); -} - -struct iovec *configuration_ProcessCreateTunnel(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - add_connection_command *control = request[1].iov_base; - - bool success = false; - - Connection *conn; - const char *symbolicName = control->symbolic; - - Address *source = NULL; - Address *destination = NULL; - - if (symbolicNameTable_Exists(config->symbolicNameTable, symbolicName)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "Connection symbolic name already exists"); - goto ERR; - } - - if (control->ipType == ADDR_INET) { - source = - addressFromInaddr4Port(&control->localIp.v4.as_u32, &control->localPort); - destination = - addressFromInaddr4Port(&control->remoteIp.v4.as_u32, &control->remotePort); - } else if (control->ipType == ADDR_INET6) { - source = - addressFromInaddr6Port(&control->localIp.v6.as_in6addr, &control->localPort); - destination = - addressFromInaddr6Port(&control->remoteIp.v6.as_in6addr, &control->remotePort); - } else { - printf("Invalid IP type.\n"); // will generate a Nack - } - - AddressPair *pair = addressPair_Create(source, destination); - conn = (Connection *)connectionTable_FindByAddressPair( - forwarder_GetConnectionTable(config->forwarder), pair); - - addressPair_Release(&pair); - - if (!conn) { - IoOperations *ops = NULL; - switch (control->connectionType) { - case TCP_CONN: - // logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - // __func__, - // "Unsupported tunnel protocol: TCP"); - ops = tcpTunnel_Create(config->forwarder, source, destination); - break; - case UDP_CONN: - ops = udpTunnel_Create(config->forwarder, source, destination); - break; - case GRE_CONN: - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "Unsupported tunnel protocol: GRE"); - break; -#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) - case HICN_CONN: - ops = hicnTunnel_Create(config->forwarder, source, destination); - break; -#endif /* __APPLE__ _WIN32*/ - default: - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "Unsupported tunnel protocol: %d", - control->connectionType); - break; - } - - if (ops != NULL) { - Connection *conn = connection_Create(ops); -#ifdef WITH_POLICY - connection_SetTags(conn, control->tags); - connection_SetPriority(conn, control->priority); -#endif /* WITH_POLICY */ +configuration_t *configuration_create() { + configuration_t *config = malloc(sizeof(configuration_t)); + if (!config) return NULL; - connection_SetAdminState(conn, control->admin_state); - - connectionTable_Add(forwarder_GetConnectionTable(config->forwarder), - conn); - symbolicNameTable_Add(config->symbolicNameTable, symbolicName, - connection_GetConnectionId(conn)); - -#ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, conn, CONNECTION_EVENT_CREATE); -#endif /* WITH_MAPME */ - - success = true; - - } else { - printf("failed, could not create IoOperations"); - } - - } else { -#ifdef WITH_POLICY - connection_SetTags(conn, control->tags); - connection_SetPriority(conn, control->priority); - connection_SetAdminState(conn, control->admin_state); - -#ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, conn, CONNECTION_EVENT_UPDATE); -#endif /* WITH_MAPME */ - if (source) - addressDestroy(&source); - if (destination) - addressDestroy(&destination); - - success = true; + config->fn_config = NULL; + config->port = PORT_NUMBER; + config->configuration_port = 2001; // TODO(eloparco): What is this? + config->cs_capacity = DEFAULT_CS_CAPACITY; + config->logfile = NULL; + config->logfile_fd = -1; +#ifndef _WIN32 + config->daemon = false; #else - printf("failed, symbolic name or connection already exist\n"); -#endif /* WITH_POLICY */ - } - - if (source) - addressDestroy(&source); - if (destination) - addressDestroy(&destination); - - if (!success) - goto ERR; - - // ACK - return utils_CreateAck(header, control, sizeof(add_connection_command)); - -ERR: - return utils_CreateNack(header, control, sizeof(add_connection_command)); -} - -struct iovec *configuration_ProcessRemoveListener(Configuration *config, - struct iovec *request, - unsigned ingressId) { - header_control_message *header = request[0].iov_base; - remove_listener_command *control = request[1].iov_base; - - bool success = false; - - const char *symbolicOrListenerid = control->symbolicOrListenerid; - int listenerId = -1; - ListenerSet *listenerSet = forwarder_GetListenerSet(config->forwarder); - if (utils_IsNumber(symbolicOrListenerid)) { - // case for connid as input - listenerId = (unsigned)strtold(symbolicOrListenerid, NULL); - } else { - listenerId = listenerSet_FindIdByListenerName(listenerSet, symbolicOrListenerid); - } - - if (listenerId >= 0) { - - ConnectionTable *connTable = forwarder_GetConnectionTable(config->forwarder); - ListenerOps *listenerOps = listenerSet_FindById(listenerSet, listenerId); - if (listenerOps) { - ConnectionList *connectionList = connectionTable_GetEntries(connTable); - for (size_t i = 0; i < connectionList_Length(connectionList); i++) { - Connection *connection = connectionList_Get(connectionList, i); - const AddressPair *addressPair = connection_GetAddressPair(connection); - const Address *address = addressPair_GetLocal(addressPair); - if (addressEquals(listenerOps->getListenAddress(listenerOps),address)) { - // case for connid as input - unsigned connid = connection_GetConnectionId(connection); - // remove connection from the FIB - forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid); - // remove connection - connectionTable_RemoveById(connTable, connid); - const char *symbolicConnection = symbolicNameTable_GetNameByIndex(config->symbolicNameTable,connid); - symbolicNameTable_Remove(config->symbolicNameTable, symbolicConnection); - } - } - connectionList_Destroy(&connectionList); - // remove listener - listenerSet_RemoveById(listenerSet, listenerId); - success = true; - } else { - logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "Listener Id not found, check list listeners"); - } - } - - // generate ACK/NACK - struct iovec *response; - - if (success) { // ACK - response = - utils_CreateAck(header, control, sizeof(remove_listener_command)); - } else { // NACK - response = - utils_CreateNack(header, control, sizeof(remove_connection_command)); - } - - return response; -} - - -/** - * Add an IP-based tunnel. - * - * The call cal fail if the symbolic name is a duplicate. It could also fail if - * there's an problem creating the local side of the tunnel (i.e. the local - * socket address is not usable). - * - * @return true Tunnel added - * @return false Tunnel not added (an error) - */ - -struct iovec *configuration_ProcessRemoveTunnel(Configuration *config, - struct iovec *request, - unsigned ingressId) { - header_control_message *header = request[0].iov_base; - remove_connection_command *control = request[1].iov_base; - - bool success = false; - - const char *symbolicOrConnid = control->symbolicOrConnid; - ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder); - if (strcmp(symbolicOrConnid, "SELF") == 0) { - forwarder_RemoveConnectionIdFromRoutes(config->forwarder, ingressId); - connectionTable_RemoveById(table, ingressId); - -#ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, NULL, CONNECTION_EVENT_DELETE); -#endif /* WITH_MAPME */ - - success = true; - } else if (utils_IsNumber(symbolicOrConnid)) { - // case for connid as input - unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL); - - // check if interface index present in the fwd table - //(it was missing and therefore caused a program crash) - if (connectionTable_FindById(table, connid)) { - // remove connection from the FIB - forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid); - // remove connection - connectionTable_RemoveById(table, connid); - // remove connection from symbolicNameTable - const char *symbolicConnection = symbolicNameTable_GetNameByIndex(config->symbolicNameTable,connid); - symbolicNameTable_Remove(config->symbolicNameTable, symbolicConnection); - -#ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, NULL, CONNECTION_EVENT_DELETE); -#endif /* WITH_MAPME */ - - success = true; - } else { - logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "ConnID not found, check list connections"); - // failure - } - - } else { - // case for symbolic as input - // chech if symbolic name can be resolved - unsigned connid = - symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid); - // connid = UINT_MAX when symbolicName is not found - if (connid != UINT32_MAX) { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Debug)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug, - __func__, "Remove connection resolve name '%s' to connid %u", - symbolicOrConnid, connid); - } - - // remove connection from the FIB - forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid); - // remove connection - connectionTable_RemoveById(table, connid); - // remove connection from symbolicNameTable since we have symbolic input - symbolicNameTable_Remove(config->symbolicNameTable, symbolicOrConnid); - -#ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, NULL, CONNECTION_EVENT_DELETE); -#endif /* WITH_MAPME */ - - success = true; // to write - } else { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Warning)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, - "Remove connection symbolic name '%s' could not be resolved", - symbolicOrConnid); - } - // failure - } - } - - - - // generate ACK/NACK - struct iovec *response; - - if (success) { // ACK - response = - utils_CreateAck(header, control, sizeof(remove_connection_command)); - } else { // NACK - response = - utils_CreateNack(header, control, sizeof(remove_connection_command)); - } - - return response; -} - -void _parc_strlwr(char *string) { - char *p = string; - while ((*p = tolower(*p))) { - p++; - } -} - -struct iovec *configuration_ProcessConnectionList(Configuration *config, - struct iovec *request) { - ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder); - ConnectionList *connList = connectionTable_GetEntries(table); - struct sockaddr_in tmpAddr; - struct sockaddr_in6 tmpAddr6; - - // allocate payload, cast from void* to uint8_t* fot bytes granularity - uint8_t *payloadResponse = parcMemory_AllocateAndClear( - sizeof(list_connections_command) * connectionList_Length(connList)); - - for (size_t i = 0; i < connectionList_Length(connList); i++) { - // Don't release original, it is not stored - Connection *original = connectionList_Get(connList, i); - - const AddressPair *addressPair = connection_GetAddressPair(original); - Address *localAddress = addressCopy(addressPair_GetLocal(addressPair)); - Address *remoteAddress = addressCopy(addressPair_GetRemote(addressPair)); - - // Fill payload by shifting and casting at each 'i' step. - list_connections_command *listConnectionsCommand = - (list_connections_command *)(payloadResponse + - (i * sizeof(list_connections_command))); - // set structure fields - - listConnectionsCommand->connid = connection_GetConnectionId(original); - - const char *connectionName = symbolicNameTable_GetNameByIndex(config->symbolicNameTable, connection_GetConnectionId(original)); - snprintf(listConnectionsCommand->connectionName, SYMBOLIC_NAME_LEN, "%s", connectionName); - _parc_strlwr(listConnectionsCommand->connectionName); - - snprintf(listConnectionsCommand->interfaceName, SYMBOLIC_NAME_LEN, "%s", ioOperations_GetInterfaceName(connection_GetIoOperations(original))); - - listConnectionsCommand->state = - connection_IsUp(original) ? IFACE_UP : IFACE_DOWN; - listConnectionsCommand->connectionData.admin_state = - (connection_GetAdminState(original) == CONNECTION_STATE_UP) ? IFACE_UP : IFACE_DOWN; - listConnectionsCommand->connectionData.connectionType = - ioOperations_GetConnectionType(connection_GetIoOperations(original)); - - listConnectionsCommand->connectionData.admin_state = connection_GetAdminState(original); - -#ifdef WITH_POLICY - listConnectionsCommand->connectionData.priority = connection_GetPriority(original); - listConnectionsCommand->connectionData.tags = connection_GetTags(original); -#endif /* WITH_POLICY */ - - if (addressGetType(localAddress) == ADDR_INET && - addressGetType(remoteAddress) == ADDR_INET) { - listConnectionsCommand->connectionData.ipType = ADDR_INET; - - // get local port/address - addressGetInet(localAddress, &tmpAddr); - listConnectionsCommand->connectionData.localPort = tmpAddr.sin_port; - listConnectionsCommand->connectionData.localIp.v4.as_inaddr = - tmpAddr.sin_addr; - memset(&tmpAddr, 0, sizeof(tmpAddr)); - // get remote port/address - addressGetInet(remoteAddress, &tmpAddr); - listConnectionsCommand->connectionData.remotePort = tmpAddr.sin_port; - listConnectionsCommand->connectionData.remoteIp.v4.as_inaddr = - tmpAddr.sin_addr; - - } else if (addressGetType(localAddress) == ADDR_INET6 && - addressGetType(remoteAddress) == ADDR_INET6) { - listConnectionsCommand->connectionData.ipType = ADDR_INET6; - - // get local port/address - addressGetInet6(localAddress, &tmpAddr6); - listConnectionsCommand->connectionData.localPort = tmpAddr6.sin6_port; - listConnectionsCommand->connectionData.localIp.v6.as_in6addr = tmpAddr6.sin6_addr; - memset(&tmpAddr6, 0, sizeof(tmpAddr6)); - // get remote port/address - addressGetInet6(remoteAddress, &tmpAddr6); - listConnectionsCommand->connectionData.remotePort = tmpAddr6.sin6_port; - listConnectionsCommand->connectionData.remoteIp.v6.as_in6addr = tmpAddr6.sin6_addr; - - } // no need further else, control on the addressed already done at the - // time of insertion in the connection table - addressDestroy(&localAddress); - addressDestroy(&remoteAddress); - } - - // send response - header_control_message *header = request[0].iov_base; - header->messageType = RESPONSE_LIGHT; - header->length = (uint16_t)connectionList_Length(connList); - - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); - - response[0].iov_base = header; - response[0].iov_len = sizeof(header_control_message); - response[1].iov_base = payloadResponse; - response[1].iov_len = - sizeof(list_connections_command) * connectionList_Length(connList); - - connectionList_Destroy(&connList); - return response; -} - -struct iovec *configuration_ProcessListenersList(Configuration *config, - struct iovec *request) { - ListenerSet *listenerList = forwarder_GetListenerSet(config->forwarder); - struct sockaddr_in tmpAddr; - struct sockaddr_in6 tmpAddr6; - - // allocate payload, cast from void* to uint8_t* fot bytes granularity - uint8_t *payloadResponse = parcMemory_AllocateAndClear( - sizeof(list_listeners_command) * listenerSet_Length(listenerList)); - - for (size_t i = 0; i < listenerSet_Length(listenerList); i++) { - ListenerOps *listenerEntry = listenerSet_Get(listenerList, i); - - // Fill payload by shifting and casting at each 'i' step. - list_listeners_command *listListenersCommand = - (list_listeners_command *)(payloadResponse + - (i * sizeof(list_listeners_command))); - - listListenersCommand->connid = - (uint32_t)listenerEntry->getInterfaceIndex(listenerEntry); - listListenersCommand->encapType = - (uint8_t)listenerEntry->getEncapType(listenerEntry); - if (addressGetType((const Address *)listenerEntry->getListenAddress( - listenerEntry)) == ADDR_INET) { - addressGetInet( - (const Address *)listenerEntry->getListenAddress(listenerEntry), - &tmpAddr); - listListenersCommand->addressType = ADDR_INET; - listListenersCommand->address.v4.as_inaddr = tmpAddr.sin_addr; - listListenersCommand->port = tmpAddr.sin_port; - } else if (addressGetType((const Address *)listenerEntry->getListenAddress( - listenerEntry)) == ADDR_INET6) { - addressGetInet6( - (const Address *)listenerEntry->getListenAddress(listenerEntry), - &tmpAddr6); - listListenersCommand->addressType = ADDR_INET6; - listListenersCommand->address.v6.as_in6addr = tmpAddr6.sin6_addr; - listListenersCommand->port = tmpAddr6.sin6_port; - } - - const char * listenerName = listenerEntry->getListenerName(listenerEntry); - snprintf(listListenersCommand->listenerName, SYMBOLIC_NAME_LEN, "%s", listenerName); - if (listenerEntry->getEncapType(listenerEntry) == ENCAP_TCP || - listenerEntry->getEncapType(listenerEntry) == ENCAP_UDP) { - const char * interfaceName = listenerEntry->getInterfaceName(listenerEntry); - snprintf(listListenersCommand->interfaceName, SYMBOLIC_NAME_LEN, "%s", interfaceName); - } - } - - // send response - header_control_message *header = request[0].iov_base; - header->messageType = RESPONSE_LIGHT; - header->length = (uint16_t)listenerSet_Length(listenerList); - - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); - - response[0].iov_base = header; - response[0].iov_len = sizeof(header_control_message); - response[1].iov_base = payloadResponse; - response[1].iov_len = - sizeof(list_listeners_command) * listenerSet_Length(listenerList); - - return response; -} - -struct iovec *configuration_ProcessCacheStore(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - ; - cache_store_command *control = request[1].iov_base; - ; - - bool success = false; - - switch (control->activate) { - case ACTIVATE_ON: - forwarder_SetChacheStoreFlag(config->forwarder, true); - if (forwarder_GetChacheStoreFlag(config->forwarder)) { - success = true; - } - break; - - case ACTIVATE_OFF: - forwarder_SetChacheStoreFlag(config->forwarder, false); - if (!forwarder_GetChacheStoreFlag(config->forwarder)) { - success = true; - } - break; - - default: - break; - } - - struct iovec *response; - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(cache_store_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(cache_store_command)); - } - - return response; -} - -struct iovec *configuration_ProcessCacheServe(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - cache_serve_command *control = request[1].iov_base; - - bool success = false; - - switch (control->activate) { - case ACTIVATE_ON: - forwarder_SetChacheServeFlag(config->forwarder, true); - if (forwarder_GetChacheServeFlag(config->forwarder)) { - success = true; - } - break; - - case ACTIVATE_OFF: - forwarder_SetChacheServeFlag(config->forwarder, false); - if (!forwarder_GetChacheServeFlag(config->forwarder)) { - success = true; - } - break; - - default: - break; - } - - struct iovec *response; - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(cache_store_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(cache_store_command)); - } - - return response; -} - -struct iovec *configuration_ProcessCacheClear(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - - forwarder_ClearCache(config->forwarder); - - struct iovec *response = utils_CreateAck(header, NULL, 0); - return response; -} - -size_t configuration_GetObjectStoreSize(Configuration *config) { - return config->maximumContentObjectStoreSize; -} + WSADATA wsaData = {0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); +#endif + configuration_set_loglevel(config, loglevel_from_str(DEFAULT_LOGLEVEL)); + config->strategy_map = kh_init_strategy_map(); -void _configuration_StoreFwdStrategy(Configuration *config, const char *prefix, - strategy_type strategy) { - PARCString *prefixStr = parcString_Create(prefix); - PARCUnsigned *strategyValue = parcUnsigned_Create((unsigned)strategy); - parcHashMap_Put(config->strategy_map, prefixStr, strategyValue); - parcUnsigned_Release(&strategyValue); - parcString_Release(&prefixStr); + return config; } -struct iovec *configuration_SetWldr(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - set_wldr_command *control = request[1].iov_base; - ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder); - Connection *conn = NULL; - bool success = false; +void configuration_free(configuration_t *config) { + assert(config); - const char *symbolicOrConnid = control->symbolicOrConnid; + const char *k_prefix; + unsigned _; + (void)_; - if (utils_IsNumber(symbolicOrConnid)) { - // case for connid as input: check if connID present in the fwd table - conn = (Connection *)connectionTable_FindById( - table, (unsigned)strtold(symbolicOrConnid, NULL)); - if (conn) { - success = true; - } else { - logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "ConnID not found, check list connections"); // failure - } - } else { - // case for symbolic as input: check if symbolic name can be resolved - unsigned connid = - symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid); - if (connid != UINT32_MAX) { - conn = (Connection *)connectionTable_FindById(table, connid); - if (conn) { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Debug)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug, - __func__, "Set wldr resolve name '%s' to connid %u", - symbolicOrConnid, connid); - } - success = true; - } - } else { - if (logger_IsLoggable(config->logger, LoggerFacility_Config, - PARCLogLevel_Warning)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "Symbolic name '%s' could not be resolved", - symbolicOrConnid); - } // failure - } - } + // Free the strategy hashmap + kh_foreach(config->strategy_map, k_prefix, _, { free((char *)k_prefix); }); + kh_destroy_strategy_map(config->strategy_map); - // generate ACK/NACK - struct iovec *response; - - if (success) { - switch (control->activate) { - case ACTIVATE_ON: - connection_EnableWldr(conn); - response = utils_CreateAck(header, control, sizeof(set_wldr_command)); - break; - - case ACTIVATE_OFF: - connection_DisableWldr(conn); - response = utils_CreateAck(header, control, sizeof(set_wldr_command)); - break; - - default: // received wrong value - response = utils_CreateNack(header, control, sizeof(set_wldr_command)); - break; - } - } else { - response = utils_CreateNack(header, control, sizeof(set_wldr_command)); - } - - return response; + free(config); } -strategy_type configuration_GetForwardingStrategy(Configuration *config, - const char *prefix) { - PARCString *prefixStr = parcString_Create(prefix); - const unsigned *val = parcHashMap_Get(config->strategy_map, prefixStr); - parcString_Release(&prefixStr); - - if (val == NULL) { - return LAST_STRATEGY_VALUE; - } else { - return (strategy_type)*val; - } +size_t configuration_get_cs_size(const configuration_t *config) { + return config->cs_capacity; } -struct iovec *configuration_SetForwardingStrategy(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - set_strategy_command *control = request[1].iov_base; - - const char *prefix = utils_PrefixLenToString( - control->addressType, &control->address, &control->len); - strategy_type strategy = control->strategyType; - strategy_type existingFwdStrategy = - configuration_GetForwardingStrategy(config, prefix); - - if (existingFwdStrategy == LAST_STRATEGY_VALUE || - strategy != existingFwdStrategy) { - // means such a new strategy is not present in the hash table or has to be - // updated - _configuration_StoreFwdStrategy(config, prefix, strategy); - Name *hicnPrefix = name_CreateFromAddress(control->addressType, - control->address, control->len); - Name *related_prefixes[MAX_FWD_STRATEGY_RELATED_PREFIXES]; - if(control->related_prefixes != 0){ - for(int i = 0; i < control->related_prefixes; i++){ - related_prefixes[i] = name_CreateFromAddress( - control->addresses_type[i], - control->addresses[i], control->lens[i]); - } - } - forwarder_SetStrategy(config->forwarder, hicnPrefix, strategy, - control->related_prefixes, related_prefixes); - name_Release(&hicnPrefix); - if(control->related_prefixes != 0){ - for(int i = 0; i < control->related_prefixes; i++){ - name_Release(&related_prefixes[i]); - } - } - } - - free((char *) prefix); - struct iovec *response = - utils_CreateAck(header, control, sizeof(set_strategy_command)); - - return response; +void configuration_set_cs_size(configuration_t *config, size_t size) { + config->cs_capacity = size; } -void configuration_SetObjectStoreSize(Configuration *config, - size_t maximumObjectCount) { - config->maximumContentObjectStoreSize = maximumObjectCount; - - forwarder_SetContentObjectStoreSize(config->forwarder, - config->maximumContentObjectStoreSize); +const char *configuration_get_fn_config(const configuration_t *config) { + return config->fn_config; } -Forwarder *configuration_GetForwarder(const Configuration *config) { - return config->forwarder; +void configuration_set_fn_config(configuration_t *config, + const char *fn_config) { + config->fn_config = fn_config; } -Logger *configuration_GetLogger(const Configuration *config) { - return config->logger; +void configuration_set_port(configuration_t *config, uint16_t port) { + config->port = port; } -struct iovec *configuration_MapMeEnable(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - mapme_activator_command *control = request[1].iov_base; - const char *stateString[2] = {"on", "off"}; - - PARCBufferComposer *composer = parcBufferComposer_Create(); - parcBufferComposer_Format(composer, - "The mapme enable setting received is: %s", - stateString[control->activate]); - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - puts(result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); - - return utils_CreateAck(header, control, sizeof(mapme_timing_command)); +uint16_t configuration_get_port(const configuration_t *config) { + return config->port; } -struct iovec *configuration_MapMeDiscovery(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - mapme_activator_command *control = request[1].iov_base; - const char *stateString[2] = {"on", "off"}; - - PARCBufferComposer *composer = parcBufferComposer_Create(); - parcBufferComposer_Format(composer, - "The mapme discovery setting received is: %s", - stateString[control->activate]); - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - puts(result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); - - return utils_CreateAck(header, control, sizeof(mapme_timing_command)); +void configuration_set_configuration_port(configuration_t *config, + uint16_t configuration_port) { + config->configuration_port = configuration_port; } -struct iovec *configuration_MapMeTimescale(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - mapme_timing_command *control = request[1].iov_base; - - PARCBufferComposer *composer = parcBufferComposer_Create(); - parcBufferComposer_Format(composer, - "The mapme timescale value received is: %u", - control->timePeriod); - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - puts(result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); - - return utils_CreateAck(header, control, sizeof(mapme_timing_command)); -} - -struct iovec *configuration_MapMeRetx(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - mapme_timing_command *control = request[1].iov_base; - - PARCBufferComposer *composer = parcBufferComposer_Create(); - parcBufferComposer_Format( - composer, "The mapme retransmission time value received is: %u", - control->timePeriod); - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - puts(result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); - - return utils_CreateAck(header, control, sizeof(mapme_timing_command)); +uint16_t configuration_get_configuration_port(const configuration_t *config) { + return config->configuration_port; } -struct iovec * configuration_MapMeSendUpdate(Configuration *config, - struct iovec *request, unsigned ingressId) { - header_control_message *header = request[0].iov_base; - mapme_send_update_command *control = request[1].iov_base; - - FIB * fib = forwarder_getFib(config->forwarder); - if (!fib) - goto ERR; - Name *prefix = name_CreateFromAddress(control->addressType, control->address, - control->len); - if (!prefix) - goto ERR; - FibEntry *entry = fib_Contains(fib, prefix); - name_Release(&prefix); - if (!entry) - goto ERR; - - const NumberSet * nexthops = fibEntry_GetNexthops(entry); - unsigned size = (unsigned) numberSet_Length(nexthops); - - /* The command is accepted iif triggered by (one of) the producer of this prefix */ - for (unsigned i = 0; i < size; i++) { - unsigned nhop = numberSet_GetItem(nexthops, i); - if (nhop == ingressId) { - MapMe * mapme = forwarder_getMapmeInstance(config->forwarder); - mapme_send_updates(mapme, entry, nexthops); - return utils_CreateAck(header, control, sizeof(mapme_timing_command)); - } - } - -ERR: - return utils_CreateNack(header, control, sizeof(connection_set_admin_state_command)); +void configuration_set_loglevel(configuration_t *config, int loglevel) { + config->loglevel = loglevel; + log_conf.log_level = loglevel; } - -struct iovec *configuration_ConnectionSetAdminState(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - connection_set_admin_state_command *control = request[1].iov_base; - - if ((control->admin_state != CONNECTION_STATE_UP) && (control->admin_state != CONNECTION_STATE_DOWN)) - return utils_CreateNack(header, control, sizeof(connection_set_admin_state_command)); - - Connection * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); - if (!conn) - return utils_CreateNack(header, control, sizeof(connection_set_admin_state_command)); - - connection_SetAdminState(conn, control->admin_state); - -#ifdef WITH_MAPME - /* Hook: connection event */ - forwarder_onConnectionEvent(config->forwarder, conn, - control->admin_state == CONNECTION_STATE_UP - ? CONNECTION_EVENT_SET_UP - : CONNECTION_EVENT_SET_DOWN); -#endif /* WITH_MAPME */ - - return utils_CreateAck(header, control, sizeof(connection_set_admin_state_command)); +int configuration_get_loglevel(const configuration_t *config) { + return config->loglevel; } -#ifdef WITH_POLICY - -struct iovec *configuration_ConnectionSetPriority(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - connection_set_priority_command *control = request[1].iov_base; - - Connection * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); - if (!conn) - return utils_CreateNack(header, control, sizeof(connection_set_priority_command)); - - connection_SetPriority(conn, control->priority); - -#ifdef WITH_MAPME - /* Hook: connection event */ - forwarder_onConnectionEvent(config->forwarder, conn, - CONNECTION_EVENT_PRIORITY_CHANGED); -#endif /* WITH_MAPME */ - - return utils_CreateAck(header, control, sizeof(connection_set_priority_command)); +void configuration_set_logfile(configuration_t *config, const char *logfile) { + config->logfile = logfile; + log_conf.log_file = fopen(logfile, "w"); + config->logfile_fd = fileno(log_conf.log_file); } -struct iovec *configuration_ConnectionSetTags(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - connection_set_tags_command *control = request[1].iov_base; - - Connection * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); - if (!conn) - return utils_CreateNack(header, control, sizeof(connection_set_tags_command)); - - connection_SetTags(conn, control->tags); - -#ifdef WITH_MAPME - /* Hook: connection event */ - forwarder_onConnectionEvent(config->forwarder, conn, - CONNECTION_EVENT_TAGS_CHANGED); -#endif /* WITH_MAPME */ - - return utils_CreateAck(header, control, sizeof(connection_set_tags_command)); +const char *configuration_get_logfile(const configuration_t *config) { + return config->logfile; } -struct iovec *configuration_ProcessPolicyAdd(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - add_policy_command *control = request[1].iov_base; - - if (forwarder_AddOrUpdatePolicy(config->forwarder, control)) { - return utils_CreateAck(header, control, sizeof(add_policy_command)); - } else { - return utils_CreateNack(header, control, sizeof(add_policy_command)); - } +int configuration_get_logfile_fd(const configuration_t *config) { + return config->logfile_fd; } -struct iovec *configuration_ProcessPolicyList(Configuration *config, - struct iovec *request) { - FibEntryList *fibList = forwarder_GetFibEntries(config->forwarder); - - size_t payloadSize = fibEntryList_Length(fibList); - struct sockaddr_in tmpAddr; - struct sockaddr_in6 tmpAddr6; - - // allocate payload, cast from void* to uint8_t* = bytes granularity - uint8_t *payloadResponse = - parcMemory_AllocateAndClear(sizeof(list_policies_command) * payloadSize); - - for (size_t i = 0; i < fibEntryList_Length(fibList); i++) { - FibEntry *entry = (FibEntry *)fibEntryList_Get(fibList, i); - NameBitvector *prefix = name_GetContentName(fibEntry_GetPrefix(entry)); - - list_policies_command *listPoliciesCommand = - (list_policies_command *)(payloadResponse + - (i * sizeof(list_policies_command))); - - Address *addressEntry = nameBitvector_ToAddress(prefix); - if (addressGetType(addressEntry) == ADDR_INET) { - addressGetInet(addressEntry, &tmpAddr); - listPoliciesCommand->addressType = ADDR_INET; - listPoliciesCommand->address.v4.as_inaddr = tmpAddr.sin_addr; - } else if (addressGetType(addressEntry) == ADDR_INET6) { - addressGetInet6(addressEntry, &tmpAddr6); - listPoliciesCommand->addressType = ADDR_INET6; - listPoliciesCommand->address.v6.as_in6addr = tmpAddr6.sin6_addr; - } - listPoliciesCommand->len = nameBitvector_GetLength(prefix); - listPoliciesCommand->policy = fibEntry_GetPolicy(entry); - - addressDestroy(&addressEntry); - } - - // send response - header_control_message *header = request[0].iov_base; - header->messageType = RESPONSE_LIGHT; - header->length = (unsigned)payloadSize; - - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); - - response[0].iov_base = header; - response[0].iov_len = sizeof(header_control_message); - response[1].iov_base = payloadResponse; - response[1].iov_len = sizeof(list_policies_command) * payloadSize; - - fibEntryList_Destroy(&fibList); - return response; +void configuration_set_daemon(configuration_t *config, bool daemon) { + config->daemon = daemon; } -struct iovec *configuration_ProcessPolicyRemove(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - remove_policy_command *control = request[1].iov_base; - - if (forwarder_RemovePolicy(config->forwarder, control)) - return utils_CreateAck(header, control, sizeof(remove_policy_command)); - else - return utils_CreateNack(header, control, sizeof(remove_policy_command)); +bool configuration_get_daemon(const configuration_t *config) { + return config->daemon; } -struct iovec *configuration_UpdateConnection(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - update_connection_command *control = request[1].iov_base; - - Connection * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); - if (!conn) - return utils_CreateNack(header, control, sizeof(update_connection_command)); - - connection_SetTags(conn, control->tags); - connection_SetAdminState(conn, control->admin_state); - if (control->priority > 0) - connection_SetPriority(conn, control->priority); - - return utils_CreateAck(header, control, sizeof(update_connection_command)); +void configuration_set_strategy(configuration_t *config, const char *prefix, + strategy_type_t strategy_type) { + int res; + khiter_t k = kh_put_strategy_map(config->strategy_map, strdup(prefix), &res); + kh_value(config->strategy_map, k) = strategy_type; } -#endif /* WITH_POLICY */ - -// =========================== -// Main functions that deal with receiving commands, executing them, and sending -// ACK/NACK - -struct iovec *configuration_DispatchCommand(Configuration *config, - command_id command, - struct iovec *control, - unsigned ingressId) { - struct iovec *response = NULL; - switch (command) { - case ADD_LISTENER: - response = configurationListeners_Add(config, control, ingressId); - break; - - case ADD_CONNECTION: - response = configuration_ProcessCreateTunnel(config, control); - break; - - case LIST_CONNECTIONS: - response = configuration_ProcessConnectionList(config, control); - break; - - case ADD_ROUTE: - response = - configuration_ProcessRegisterHicnPrefix(config, control, ingressId); - break; - - case LIST_ROUTES: - response = configuration_ProcessRegistrationList(config, control); - break; - - case REMOVE_CONNECTION: - response = configuration_ProcessRemoveTunnel(config, control, ingressId); - break; - - case REMOVE_LISTENER: - response = configuration_ProcessRemoveListener(config, control, ingressId); - break; - - case REMOVE_ROUTE: - response = configuration_ProcessUnregisterHicnPrefix(config, control); - break; - - case CACHE_STORE: - response = configuration_ProcessCacheStore(config, control); - break; - - case CACHE_SERVE: - response = configuration_ProcessCacheServe(config, control); - break; - - case CACHE_CLEAR: - response = configuration_ProcessCacheClear(config, control); - break; - - case SET_STRATEGY: - response = configuration_SetForwardingStrategy(config, control); - break; - - case SET_WLDR: - response = configuration_SetWldr(config, control); - break; - - case ADD_PUNTING: - response = configurationListeners_AddPunting(config, control, ingressId); - break; - case LIST_LISTENERS: - response = configuration_ProcessListenersList(config, control); - break; - - case MAPME_ENABLE: - response = configuration_MapMeEnable(config, control); - break; - - case MAPME_DISCOVERY: - response = configuration_MapMeDiscovery(config, control); - break; - - case MAPME_TIMESCALE: - response = configuration_MapMeTimescale(config, control); - break; - - case MAPME_RETX: - response = configuration_MapMeRetx(config, control); - break; - - case MAPME_SEND_UPDATE: - response = configuration_MapMeSendUpdate(config, control, ingressId); - break; - - case CONNECTION_SET_ADMIN_STATE: - response = configuration_ConnectionSetAdminState(config, control); - break; - -#ifdef WITH_POLICY - case ADD_POLICY: - response = configuration_ProcessPolicyAdd(config, control); - break; - - case LIST_POLICIES: - response = configuration_ProcessPolicyList(config, control); - break; - - case REMOVE_POLICY: - response = configuration_ProcessPolicyRemove(config, control); - break; - - case UPDATE_CONNECTION: - response = configuration_UpdateConnection(config, control); - break; - - case CONNECTION_SET_PRIORITY: - response = configuration_ConnectionSetPriority(config, control); - break; - - case CONNECTION_SET_TAGS: - response = configuration_ConnectionSetTags(config, control); - break; -#endif /* WITH_POLICY */ - - default: - break; - } - - return response; +strategy_type_t configuration_get_strategy(const configuration_t *config, + const char *prefix) { + khiter_t k = kh_get_strategy_map(config->strategy_map, prefix); + if (k == kh_end(config->strategy_map)) return STRATEGY_TYPE_UNDEFINED; + return kh_val(config->strategy_map, k); } -void configuration_ReceiveCommand(Configuration *config, command_id command, - struct iovec *request, unsigned ingressId) { - parcAssertNotNull(config, "Parameter config must be non-null"); - parcAssertNotNull(request, "Parameter request must be non-null"); - struct iovec *response = - configuration_DispatchCommand(config, command, request, ingressId); - configuration_SendResponse(config, response, ingressId); - - /* - * The message is originally received by a listener, and will be freed in - * different parts of the code. - * - * For the special case of commands, a iovec is created, eg in - * udpListener::_readCommand, which has to be freed (it is commented in the - * listener). On the contrary, the original message is freed. - * - * From this function, commands are dispatched to different processing - * functions, which have two general behaviours: - * - * - LIST commands: - * . a payload for the response is allocated - * . a iovec for the response is allocated with header = request header, - * payload = newly allocated payload - * - * - Other commands: - * . a ack/nack packet is generated thanks to utils/utils.cc - * . this allocates a iovec which reuses the header of the request just - * updating the messageType field inside. - */ - parcMemory_Deallocate(&request); - - switch (command) { - case LIST_CONNECTIONS: - case LIST_ROUTES: // case LIST_INTERFACES: case ETC...: - case LIST_LISTENERS: - case LIST_POLICIES: - /* Deallocate payload */ - parcMemory_Deallocate(&response[1].iov_base); - break; - default: - break; - } - - parcMemory_Deallocate(&response); +void configuration_flush_log() { + if (log_conf.log_file) fclose(log_conf.log_file); } diff --git a/hicn-light/src/hicn/config/configuration.h b/hicn-light/src/hicn/config/configuration.h index 5090f1413..9861b6c9f 100644 --- a/hicn-light/src/hicn/config/configuration.h +++ b/hicn-light/src/hicn/config/configuration.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -23,17 +23,18 @@ * */ -#ifndef configuration_h -#define configuration_h +#ifndef HICNLIGHT_CONFIGURATION_H +#define HICNLIGHT_CONFIGURATION_H -#include <hicn/core/logger.h> -#include <hicn/utils/commands.h> +#include "../base/khash.h" +#include "../core/msgbuf.h" +#include "../core/strategy.h" +#include <hicn/ctrl/api.h> +#include <hicn/ctrl/hicn-light-ng.h> -struct configuration; -typedef struct configuration Configuration; +KHASH_MAP_INIT_STR(strategy_map, unsigned); -struct forwarder; -typedef struct forwarder Forwarder; +typedef struct configuration_s configuration_t; /** * <#One Line Description#> @@ -49,7 +50,7 @@ typedef struct forwarder Forwarder; * <#example#> * @endcode */ -Configuration *configuration_Create(Forwarder *forwarder); +configuration_t *configuration_create(); /** * <#One Line Description#> @@ -65,13 +66,7 @@ Configuration *configuration_Create(Forwarder *forwarder); * <#example#> * @endcode */ -void configuration_Destroy(Configuration **configPtr); - -void configuration_SetupAllListeners(Configuration *config, uint16_t port, - const char *localPath); - -void configuration_ReceiveCommand(Configuration *config, command_id command, - struct iovec *request, unsigned ingressId); +void configuration_free(configuration_t *config); /** * Returns the configured size of the content store @@ -87,7 +82,7 @@ void configuration_ReceiveCommand(Configuration *config, command_id command, * <#example#> * @endcode */ -size_t configuration_GetObjectStoreSize(Configuration *config); +size_t configuration_get_cs_size(const configuration_t *config); /** * Sets the size of the content store (in objects, not bytes) @@ -101,52 +96,42 @@ size_t configuration_GetObjectStoreSize(Configuration *config); * <#example#> * @endcode */ -void configuration_SetObjectStoreSize(Configuration *config, - size_t maximumContentObjectCount); +void configuration_set_cs_size(configuration_t *config, size_t size); -strategy_type configuration_GetForwardingStrategy(Configuration *config, - const char *prefix); +const char *configuration_get_fn_config(const configuration_t *config); -/** - * Returns the Forwarder that owns the Configuration - * - * Returns the hicn-light Forwarder. Used primarily by associated classes in - * the configuration group. - * - * @param [in] config An allocated Configuration - * - * @return non-null The owning Forwarder - * @return null An error - * - * Example: - * @code - * { - * <#example#> - * } - * @endcode - */ -Forwarder *configuration_GetForwarder(const Configuration *config); +void configuration_set_fn_config(configuration_t *config, + const char *fn_config); -/** - * Returns the logger used by the Configuration subsystem - * - * Returns the logger specified when the Configuration was created. - * - * @param [in] config An allocated Configuration - * - * @retval non-null The logger - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -Logger *configuration_GetLogger(const Configuration *config); +void configuration_set_port(configuration_t *config, uint16_t port); + +uint16_t configuration_get_port(const configuration_t *config); + +void configuration_set_configuration_port(configuration_t *config, + uint16_t configuration_port); + +uint16_t configuration_get_configuration_port(const configuration_t *config); + +void configuration_set_loglevel(configuration_t *config, int loglevel); + +int configuration_get_loglevel(const configuration_t *config); + +void configuration_set_logfile(configuration_t *config, const char *logfile); + +const char *configuration_get_logfile(const configuration_t *config); + +int configuration_get_logfile_fd(const configuration_t *config); + +void configuration_set_daemon(configuration_t *config, bool daemon); + +bool configuration_get_daemon(const configuration_t *config); + +void configuration_set_strategy(configuration_t *config, const char *prefix, + strategy_type_t strategy_type); + +strategy_type_t configuration_get_strategy(const configuration_t *config, + const char *prefix); -struct iovec *configuration_DispatchCommand(Configuration *config, - command_id command, - struct iovec *control, - unsigned ingressId); +void configuration_flush_log(); -#endif // configuration_h +#endif // HICNLIGHT_CONFIGURATION_H diff --git a/hicn-light/src/hicn/config/configurationFile.c b/hicn-light/src/hicn/config/configurationFile.c deleted file mode 100644 index ebf057fa6..000000000 --- a/hicn-light/src/hicn/config/configurationFile.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 _WIN32 -#include <unistd.h> -#endif -#include <ctype.h> -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <string.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_List.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/config/configuration.h> -#include <hicn/config/configurationFile.h> -#include <hicn/config/controlRoot.h> -#include <hicn/config/controlState.h> - -struct configuration_file { - Forwarder *forwarder; - const char *filename; - FILE *fh; - - size_t linesRead; - - // our custom state machine. - ControlState *controlState; -}; - -/* - * Called by a command to dispatch the correct command - */ -struct iovec *_writeRead(ControlState *state, struct iovec *msg) { - ConfigurationFile *configFile = - (ConfigurationFile *)controlState_GetUserdata(state); - - parcAssertNotNull(msg, "Parameter msg must be non-null"); - struct iovec *response = configuration_DispatchCommand( - forwarder_GetConfiguration(configFile->forwarder), - ((header_control_message *)msg[0].iov_base)->commandID, msg, 0); - - return response; -} - -/** - * Removes leading whitespace (space + tab). - * - * If the string is all whitespace, the return value will point to the - * terminating '\0'. - * - * @param [in] str A null-terminated c-string - * - * @retval non-null A pointer in to string of the first non-whitespace - * - * - * Example: - * @code - * <#example#> - * @endcode - */ -static char *_stripLeadingWhitespace(char *str) { - while (isspace(*str)) { - str++; - } - return str; -} - -/** - * Removes trailing whitespace - * - * Inserts a NULL after the last non-whitespace character, modiyfing the input - * string. - * - * @param [in] str A null-terminated c-string - * - * @return non-null A pointer to the input string - * - * Example: - * @code - * { - * <#example#> - * } - * @endcode - */ -static char *_stripTrailingWhitespace(char *str) { - char *p = str + strlen(str) - 1; - while (p > str && isspace(*p)) { - p--; - } - - // cap it. If no whitespace, p+1 == str + strlen(str), so will overwrite the - // current null. If all whitespace p+1 == str+1. For an empty string, p+1 = - // str. - *(p + 1) = 0; - - // this does not catch the case where the entire string is whitespace - if (p == str && isspace(*p)) { - *p = 0; - } - - return str; -} - -/** - * Removed leading and trailing whitespace - * - * Modifies the input string (may add a NULL at the end). Will return - * a pointer to the first non-whitespace character or the terminating NULL. - * - * @param [in] str A null-terminated c-string - * - * @return non-null A pointer in to the input string - * - * Example: - * @code - * { - * <#example#> - * } - * @endcode - */ -static char *_trim(char *str) { - return _stripTrailingWhitespace(_stripLeadingWhitespace(str)); -} - -/** - * Parse a string in to a PARCList with one word per element - * - * The string passed will be modified by inserting NULLs after each token. - * - * @param [in] str A c-string (will be modified) - * - * @retval non-null A PARCList where each item is a single word - * - * Example: - * @code - * <#example#> - * @endcode - */ -static PARCList *_parseArgs(char *str) { - PARCList *list = - parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); - - const char delimiters[] = " \t"; - - char *token; - token = strtok(str, delimiters); - while (token != NULL) { - if (strlen(token) > 0) { - parcList_Add(list, strdup(token)); - } - token = strtok(NULL, delimiters); - } - // while ((token = strsep(&str, delimiters)) != NULL) { - // parcList_Add(list, token); - // } - - return list; -} - -// ============================================================= - -static void _destroy(ConfigurationFile **configFilePtr) { - ConfigurationFile *configFile = *configFilePtr; - parcMemory_Deallocate((void **)&configFile->filename); - - if (configFile->fh != NULL) { - fclose(configFile->fh); - } - - controlState_Destroy(&configFile->controlState); -} - -parcObject_ExtendPARCObject(ConfigurationFile, _destroy, NULL, NULL, NULL, NULL, - NULL, NULL); - -parcObject_ImplementRelease(configurationFile, ConfigurationFile); - -ConfigurationFile *configurationFile_Create(Forwarder *forwarder, - const char *filename) { - parcAssertNotNull(forwarder, "Parameter hicn-fwd must be non-null"); - parcAssertNotNull(filename, "Parameter filename must be non-null"); - - ConfigurationFile *configFile = parcObject_CreateInstance(ConfigurationFile); - - if (configFile) { - configFile->linesRead = 0; - configFile->forwarder = forwarder; - configFile->filename = - parcMemory_StringDuplicate(filename, strlen(filename)); - parcAssertNotNull(configFile->filename, "Could not copy string '%s'", - filename); - - // setup the control state for the command parser: last parameter NULL - // because - // writeRead still not implemented from configuration file. - configFile->controlState = - controlState_Create(configFile, _writeRead, false, - SRV_CTRL_IP, SRV_CTRL_PORT); - - // we do not register Help commands - controlState_RegisterCommand(configFile->controlState, - controlRoot_Create(configFile->controlState)); - - // open the file and make sure we can read it - configFile->fh = fopen(configFile->filename, "r"); - - if (configFile->fh) { - if (logger_IsLoggable(forwarder_GetLogger(forwarder), - LoggerFacility_Config, PARCLogLevel_Debug)) { - logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_Config, - PARCLogLevel_Debug, __func__, "Open config file %s", - configFile->filename); - } - } else { - if (logger_IsLoggable(forwarder_GetLogger(forwarder), - LoggerFacility_Config, PARCLogLevel_Error)) { - logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_Config, - PARCLogLevel_Error, __func__, - "Could not open config file %s: (%d) %s", - configFile->filename, errno, strerror(errno)); - } - - // failure cleanup the object -- this nulls it so final return null be - // NULL - configurationFile_Release(&configFile); - } - } - return configFile; -} - -bool configurationFile_Process(ConfigurationFile *configFile) { - parcAssertNotNull(configFile, "Parameter configFile must be non-null"); - - // default to a "true" return value and only set to false if we encounter an - // error. - bool success = true; - -#define BUFFERLEN 2048 - char buffer[BUFFERLEN]; - - configFile->linesRead = 0; - - // always clear errors and fseek to start of file in case we get called - // multiple times. - clearerr(configFile->fh); - rewind(configFile->fh); - - while (success && fgets(buffer, BUFFERLEN, configFile->fh) != NULL) { - configFile->linesRead++; - - char *stripedBuffer = _trim(buffer); - if (strlen(stripedBuffer) > 0) { - if (stripedBuffer[0] != '#') { - // not empty and not a comment - - // _parseArgs will modify the string - char *copy = - parcMemory_StringDuplicate(stripedBuffer, strlen(stripedBuffer)); - PARCList *args = _parseArgs(copy); - char output[8192]; - CommandReturn result = - controlState_DispatchCommand(configFile->controlState, args, output, sizeof(output)); - - // we ignore EXIT from the configuration file - if (result == CommandReturn_Failure) { - if (logger_IsLoggable(forwarder_GetLogger(configFile->forwarder), - LoggerFacility_Config, PARCLogLevel_Error)) { - logger_Log(forwarder_GetLogger(configFile->forwarder), - LoggerFacility_Config, PARCLogLevel_Error, __func__, - "Error on input file %s line %d: %s", - configFile->filename, configFile->linesRead, - stripedBuffer); - } - success = false; - } - for(int i = 0; i < parcList_Size(args); i++){ - free(parcList_GetAtIndex(args, i)); - } - parcList_Release(&args); - parcMemory_Deallocate((void **)©); - } - } - } - - if (ferror(configFile->fh)) { - if (logger_IsLoggable(forwarder_GetLogger(configFile->forwarder), - LoggerFacility_Config, PARCLogLevel_Error)) { - logger_Log(forwarder_GetLogger(configFile->forwarder), - LoggerFacility_Config, PARCLogLevel_Error, __func__, - "Error on input file %s line %d: (%d) %s", - configFile->filename, configFile->linesRead, errno, - strerror(errno)); - } - success = false; - } - - return success; -} diff --git a/hicn-light/src/hicn/config/configurationFile.h b/hicn-light/src/hicn/config/configurationFile.h deleted file mode 100644 index b748dfc15..000000000 --- a/hicn-light/src/hicn/config/configurationFile.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file configurationFile.h - * @brief Accepts a filename and provides a means to read it into Configuration - * - * Reads a configuration file and converts the lines in to configuration - * commands for use in Configuration. - * - * Accepts '#' lines as comments. Skips blank and whitespace-only lines. - * - */ - -#ifndef configurationFile_h -#define configurationFile_h - -#include <hicn/core/forwarder.h> - -struct configuration_file; -typedef struct configuration_file ConfigurationFile; - -/** - * Creates a ConfigurationFile to prepare to process the file - * - * Prepares the object and opens the file. Makes sure we can read the file. - * Does not read the file or process any commands from the file. - * - * @param [in] hicn-light An allocated Forwarder to configure with the file - * @param [in] filename The file to use - * - * @retval non-null An allocated ConfigurationFile that is readable - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -ConfigurationFile *configurationFile_Create(Forwarder *forwarder, - const char *filename); - -/** - * Reads the configuration file line-by-line and issues commands to - * Configuration - * - * Reads the file line by line. Skips '#' and blank lines. - * - * Will stop on the first error. Lines already processed will not be un-done. - * - * @param [in] configFile An allocated ConfigurationFile - * - * @retval true The entire files was processed without error. - * @retval false There was an error in the file. - * - * Example: - * @code - * <#example#> - * @endcode - */ -bool configurationFile_Process(ConfigurationFile *configFile); - -// void configurationFile_ProcessForwardingStrategies(Configuration * config, -// ConfigurationFile * configFile); - -/** - * Closes the underlying file and releases memory - * - * <#Paragraphs Of Explanation#> - * - * @param [in,out] configFilePtr An allocated ConfigurationFile that will be - * NULL'd as output - * - * Example: - * @code - * <#example#> - * @endcode - */ -void configurationFile_Release(ConfigurationFile **configFilePtr); - -#endif /* defined(configurationFile_h) */ diff --git a/hicn-light/src/hicn/config/configurationListeners.c b/hicn-light/src/hicn/config/configurationListeners.c deleted file mode 100644 index 31a0c4776..000000000 --- a/hicn-light/src/hicn/config/configurationListeners.c +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 _WIN32 -#include <arpa/inet.h> -#include <unistd.h> -#endif -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> - -#include <hicn/core/system.h> -#include <hicn/utils/interfaceSet.h> -#include <hicn/utils/punting.h> - -#include <hicn/config/configurationListeners.h> -#include <hicn/io/hicnListener.h> -#include <hicn/io/tcpListener.h> -#include <hicn/io/udpListener.h> - -#include <hicn/utils/address.h> -#include <hicn/utils/addressList.h> -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static bool _setupHicnListenerOnInet4(Forwarder *forwarder, - const char *symbolic, Address *address) { - bool success = false; -#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) - ListenerOps *ops = - hicnListener_CreateInet(forwarder, (char *)symbolic, address); - if (ops != NULL) { - success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops); - parcAssertTrue(success, "Failed to add Hicn listener %s to ListenerSet", - symbolic); - } -#endif /* __APPLE__ _WIN32*/ - return success; -} - -static bool _setupHicnListenerOnInet6(Forwarder *forwarder, - const char *symbolic, Address *address) { - bool success = false; -#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) - ListenerOps *ops = - hicnListener_CreateInet6(forwarder, (char *)symbolic, address); - if (ops != NULL) { - success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops); - parcAssertTrue(success, "Failed to add Hicn listener %s to ListenerSet", - symbolic); - } -#endif /* __APPLE__ _WIN32 */ - return success; -} - -bool configurationListeners_Remove(const Configuration *config) { - Logger *logger = configuration_GetLogger(config); - if (logger_IsLoggable(logger, LoggerFacility_Config, PARCLogLevel_Warning)) { - logger_Log(logger, LoggerFacility_Config, PARCLogLevel_Warning, __func__, - "Removing a listener not supported: ingress %u control %s"); - } - - return false; -} - -bool _AddPuntingInet(const Configuration *config, Punting *punting, - unsigned ingressId) { -#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) - struct sockaddr *addr = parcNetwork_SockAddress("0.0.0.0", 1234); - if (addr == NULL) { - printf("Error creating address\n"); - return false; - } - - Address *fakeAddr = addressCreateFromInet((struct sockaddr_in *)addr); - - ListenerOps *listenerOps = listenerSet_Find( - forwarder_GetListenerSet(configuration_GetForwarder(config)), ENCAP_HICN, - fakeAddr); - addressDestroy(&fakeAddr); - - if (listenerOps == NULL) { - printf("the main listener (IPV4) does not exists\n"); - return false; - } - - struct sockaddr_in puntingAddr; - - Address *address = puntingGetAddress(punting); - if (address == NULL) return false; - - bool res = addressGetInet(address, &puntingAddr); - if (!res) { - printf("unable to read the punting address\n"); - return false; - } - - char prefix[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(puntingAddr.sin_addr), prefix, INET_ADDRSTRLEN); - - char len[5]; - sprintf(len, "%d", puntingPrefixLen(punting)); - - char *prefixStr = - malloc(strlen(prefix) + strlen(len) + 2); //+1 for the zero-terminator - if (prefixStr == NULL) { - printf("error while create the prefix string\n"); - return false; - } - strcpy(prefixStr, prefix); - strcat(prefixStr, "/"); - strcat(prefixStr, len); - - res = hicnListener_Punting(listenerOps, prefixStr); - if (!res) { - printf("error while adding the punting rule\n"); - return false; - } - - return true; -#else - return false; -#endif -} - -bool _AddPuntingInet6(const Configuration *config, Punting *punting, - unsigned ingressId) { -#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) - struct sockaddr *addr = parcNetwork_SockAddress("0::0", 1234); - if (addr == NULL) { - printf("Error creating address\n"); - return false; - } - - Address *fakeAddr = addressCreateFromInet6((struct sockaddr_in6 *)addr); - - // comments: - // EncapType: I use the Hicn encap since the punting is available only for - // Hicn listeners LocalAddress: The only listern for which we need punting - // rules is the main one, which has no address - // so I create a fake empty address. This need to be consistent - // with the address set at creation time - - ListenerOps *listenerOps = listenerSet_Find( - forwarder_GetListenerSet(configuration_GetForwarder(config)), ENCAP_HICN, - fakeAddr); - addressDestroy(&fakeAddr); - - if (listenerOps == NULL) { - printf("the main listener does not exists\n"); - return false; - } - - struct sockaddr_in6 puntingAddr; - bool res = addressGetInet6(puntingGetAddress(punting), &puntingAddr); - if (!res) { - printf("unable to read the punting address\n"); - return false; - } - - char prefix[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(puntingAddr.sin6_addr), prefix, INET6_ADDRSTRLEN); - - char len[5]; - sprintf(len, "%d", puntingPrefixLen(punting)); - - char *prefixStr = - malloc(strlen(prefix) + strlen(len) + 2); //+1 for the zero-terminator - if (prefixStr == NULL) { - printf("error while create the prefix string\n"); - return false; - } - strcpy(prefixStr, prefix); - strcat(prefixStr, "/"); - strcat(prefixStr, len); - - res = hicnListener_Punting(listenerOps, prefixStr); - if (!res) { - printf("error while adding the punting rule\n"); - return false; - } - - return true; -#else - return false; -#endif -} - -//============= LIGHT COMMAN =============== - -static bool _addEther(Configuration *config, add_listener_command *control, - unsigned ingressId) { - // Not implemented - return false; -} - -/* - * Create a new IPV4/TCP listener. - * - * @param [in,out] forwarder The hicn-light forwarder instance - * @param [in] listenerName The name of the listener - * @param [in] addr4 The ipv4 address in network byte order - * @param [in] port The port number in network byte order - * @param [in] interfaceName The name of the interface to bind the socket - * - * return true if success, false otherwise - */ -static bool _setupTcpListenerOnInet(Forwarder *forwarder, char *listenerName, ipv4_addr_t *addr4, - uint16_t *port, char *interfaceName) { - parcAssertNotNull(listenerName, "Parameter listenerName must be non-null"); - - bool success = false; - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = *port; - addr.sin_addr.s_addr = *addr4; - - ListenerOps *ops = tcpListener_CreateInet(forwarder, listenerName, addr, interfaceName); - if (ops) { - success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops); -#if 0 - parcAssertTrue(success, "Failed to add TCP listener on %s to ListenerSet", - addressToString(ops->getListenAddress(ops))); -#endif - } - return success; -} - - -/* - * Create a new IPV4/UDP listener. - * - * @param [in,out] forwarder The hicn-light forwarder instance - * @param [in] listenerName The name of the listener - * @param [in] addr4 The ipv4 address in network byte order - * @param [in] port The port number in network byte order - * @param [in] interfaceName The name of the interface to bind the socket - * - * return true if success, false otherwise - */ -static bool _setupUdpListenerOnInet(Forwarder *forwarder, char *listenerName, ipv4_addr_t *addr4, - uint16_t *port, char *interfaceName) { - bool success = false; - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = *port; - addr.sin_addr.s_addr = *addr4; - - ListenerOps *ops = udpListener_CreateInet(forwarder, listenerName, addr, interfaceName); - if (ops) { - success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops); -#if 0 - parcAssertTrue(success, "Failed to add UDP listener on %s to ListenerSet", - addressToString(ops->getListenAddress(ops))); -#endif - } - return success; -} - - -/* - * Create a new IPV6/TCP listener. - * - * @param [in,out] forwarder The hicn-light forwarder instance - * @param [in] addr6 The ipv6 address in network byte order - * @param [in] port The port number in network byte order - * @param [in] interfaceName The name of the interface to bind the socket - * - * return true if success, false otherwise - */ -static bool _setupTcpListenerOnInet6Light(Forwarder *forwarder, char *listenerName, - ipv6_addr_t *addr6, uint16_t *port, char *interfaceName, - uint32_t scopeId) { - bool success = false; - - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = *port; - addr.sin6_addr = *addr6; - addr.sin6_scope_id = scopeId; - - ListenerOps *ops = tcpListener_CreateInet6(forwarder, listenerName, addr, interfaceName); - if (ops) { - success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops); -#if 0 - parcAssertTrue(success, "Failed to add TCP6 listener on %s to ListenerSet", - addressToString(ops->getListenAddress(ops))); -#endif - } - return success; -} - - -/* - * Create a new IPV6/UDP listener. - * - * @param [in,out] forwarder The hicn-light forwarder instance - * @param [in] listenerName The name of the listener - * @param [in] addr6 The ipv6 address in network byte order - * @param [in] port The port number in network byte order - * @param [in] interfaceName The name of the interface to bind the socket - * - * return true if success, false otherwise - */ -static bool _setupUdpListenerOnInet6Light(Forwarder *forwarder, char *listenerName, - ipv6_addr_t *addr6, uint16_t *port, char *interfaceName) { - bool success = false; - - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = *port; - addr.sin6_addr = *addr6; - addr.sin6_scope_id = 0; - - ListenerOps *ops = udpListener_CreateInet6(forwarder, listenerName, addr, interfaceName); - if (ops) { - success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops); -#if 0 - parcAssertTrue(success, "Failed to add UDP6 listener on %s to ListenerSet", - addressToString(ops->getListenAddress(ops))); -#endif - } - return success; -} - -/* - * Create a new HICN listener. - * - * @param [in] config The configuration - * @param [in] control The control command - * @param [in] port The connection id of the command - * - * return true if success, false otherwise - */ -bool _addHicn(Configuration *config, add_listener_command *control, - unsigned ingressId) { - bool success = false; - const char *symbolic = control->symbolic; - Address *localAddress = NULL; - - switch (control->addressType) { - case ADDR_INET: { - localAddress = - addressFromInaddr4Port(&control->address.v4.as_u32, &control->port); - success = _setupHicnListenerOnInet4(configuration_GetForwarder(config), - symbolic, localAddress); - break; - } - - case ADDR_INET6: { - localAddress = - addressFromInaddr6Port(&control->address.v6.as_in6addr, &control->port); - success = _setupHicnListenerOnInet6(configuration_GetForwarder(config), - symbolic, localAddress); - break; - } - - default: - if (logger_IsLoggable(configuration_GetLogger(config), - LoggerFacility_Config, PARCLogLevel_Warning)) { - logger_Log(configuration_GetLogger(config), LoggerFacility_Config, - PARCLogLevel_Warning, __func__, - "Unsupported address type for HICN (ingress id %u): " - "must be either IPV4 or IPV6", - ingressId); - } - break; - } - - if (success == true && localAddress != NULL) { - if (logger_IsLoggable(configuration_GetLogger(config), - LoggerFacility_Config, PARCLogLevel_Info)) { - char * str = addressToString(localAddress); - logger_Log(configuration_GetLogger(config), LoggerFacility_Config, - PARCLogLevel_Info, __func__, - "Setup hicn listener on address %s", - str); - parcMemory_Deallocate((void **)&str); - } - } - - addressDestroy(&localAddress); - - return success; -} - -bool _addIP(Configuration *config, add_listener_command *control, - unsigned ingressId) { - bool success = false; - char *symbolic = control->symbolic; - - switch (control->addressType) { - case ADDR_INET: { - - if (control->connectionType == UDP_CONN) { - success = - _setupUdpListenerOnInet(configuration_GetForwarder(config), symbolic, - &control->address.v4.as_u32, &control->port, control->interfaceName); - } else if (control->connectionType == TCP_CONN) { - success = - _setupTcpListenerOnInet(configuration_GetForwarder(config), symbolic, - &control->address.v4.as_u32, &control->port, control->interfaceName); - } - break; - } - - case ADDR_INET6: { - if (control->connectionType == UDP_CONN) { - success = _setupUdpListenerOnInet6Light( - configuration_GetForwarder(config), symbolic, &control->address.v6.as_in6addr, - &control->port, control->interfaceName); - } else if (control->connectionType == TCP_CONN) { - success = _setupTcpListenerOnInet6Light( - configuration_GetForwarder(config), symbolic, &control->address.v6.as_in6addr, - &control->port, control->interfaceName, 0); - } - break; - } - - default: - if (logger_IsLoggable(configuration_GetLogger(config), - LoggerFacility_Config, PARCLogLevel_Warning)) { - char *addrStr = utils_CommandAddressToString( - control->addressType, &control->address, &control->port); - logger_Log( - configuration_GetLogger(config), LoggerFacility_Config, - PARCLogLevel_Warning, __func__, - "Unsupported address type for IP encapsulation ingress id %u: %s", - ingressId, addrStr); - parcMemory_Deallocate((void **)&addrStr); - } - break; - } - - if (success) { - if (logger_IsLoggable(configuration_GetLogger(config), - LoggerFacility_Config, PARCLogLevel_Info)) { - char *addrStr = utils_CommandAddressToString( - control->addressType, &control->address, &control->port); - logger_Log(configuration_GetLogger(config), LoggerFacility_Config, - PARCLogLevel_Info, __func__, "Setup listener on address %s", - addrStr); - parcMemory_Deallocate((void **)&addrStr); - } - } - - return success; -} - -struct iovec *configurationListeners_Add(Configuration *config, - struct iovec *request, - unsigned ingressId) { - header_control_message *header = request[0].iov_base; - add_listener_command *control = request[1].iov_base; - - bool success = false; - - ListenerSet *listenerSet = forwarder_GetListenerSet(configuration_GetForwarder(config)); - int listenerId = listenerSet_FindIdByListenerName(listenerSet, control->symbolic); - - if (listenerId < 0) { - if (control->listenerMode == ETHER_MODE) { - parcTrapNotImplemented("Add Ethernet Listener is not supported"); - success = _addEther(config, control, ingressId); - // it is a failure - } else if (control->listenerMode == IP_MODE) { - success = _addIP(config, control, ingressId); - } else if (control->listenerMode == HICN_MODE) { - success = _addHicn(config, control, ingressId); - } else { - Logger *logger = configuration_GetLogger(config); - if (logger_IsLoggable(logger, LoggerFacility_Config, - PARCLogLevel_Warning)) { - logger_Log(logger, LoggerFacility_Config, PARCLogLevel_Warning, __func__, - "Unsupported encapsulation mode (ingress id %u)", ingressId); - } - } - } - - // generate ACK/NACK - struct iovec *response; - - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(add_listener_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(add_listener_command)); - } - - return response; -} - -struct iovec *configurationListeners_AddPunting(Configuration *config, - struct iovec *request, - unsigned ingressId) { - header_control_message *header = request[0].iov_base; - add_punting_command *control = request[1].iov_base; - - const char *symbolicOrConnid = control->symbolicOrConnid; - uint32_t len = control->len; - in_port_t port = htons(1234); - bool success = false; - - if (control->addressType == ADDR_INET) { - Address *address = addressFromInaddr4Port(&control->address.v4.as_u32, &port); - Punting *punting = puntingCreate(symbolicOrConnid, address, len); - success = _AddPuntingInet(config, punting, ingressId); - addressDestroy(&address); - } else if (control->addressType == ADDR_INET6) { - Address *address = addressFromInaddr6Port(&control->address.v6.as_in6addr, &port); - Punting *punting = puntingCreate(symbolicOrConnid, address, len); - success = _AddPuntingInet6(config, punting, ingressId); - addressDestroy(&address); - } else { - printf("Invalid IP type.\n"); // will generate a Nack - return utils_CreateNack(header, control, sizeof(add_punting_command)); - } - - // generate ACK/NACK - struct iovec *response; - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(add_punting_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(add_punting_command)); - } - - return response; -} - -//=========================== INITIAL LISTENERS ==================== - -static void _setupListenersOnAddress(Forwarder *forwarder, char *listenerName, - const Address *address, uint16_t port, - char *interfaceName) { - address_type type = addressGetType(address); - switch (type) { - case ADDR_INET: { - struct sockaddr_in tmp; - addressGetInet(address, &tmp); - _setupTcpListenerOnInet(forwarder, listenerName, &tmp.sin_addr.s_addr, &port, interfaceName); - break; - } - - case ADDR_INET6: { - struct sockaddr_in6 tmp; - addressGetInet6(address, &tmp); - _setupTcpListenerOnInet6Light(forwarder, listenerName, &tmp.sin6_addr, &port, interfaceName, - tmp.sin6_scope_id); - break; - } - - case ADDR_LINK: - // not used - break; - - default: - // dont' know how to handle this, so no listeners - break; - } -} - -void configurationListeners_SetupAll(const Configuration *config, uint16_t port, - const char *localPath) { - Forwarder *forwarder = configuration_GetForwarder(config); - InterfaceSet *set = system_Interfaces(forwarder); - - size_t interfaceSetLen = interfaceSetLength(set); - for (size_t i = 0; i < interfaceSetLen; i++) { - Interface *iface = interfaceSetGetByOrdinalIndex(set, i); - - const AddressList *addresses = interfaceGetAddresses(iface); - size_t addressListLen = addressListLength(addresses); - - for (size_t j = 0; j < addressListLen; j++) { - const Address *address = addressListGetItem(addresses, j); - - // Do not start on link address - char listenerName[SYMBOLIC_NAME_LEN]; -#if defined(__ANDROID__) || defined(_WIN32) - snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%zu", i); -#else - snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%ld", i); -#endif - if (addressGetType(address) != ADDR_LINK) { - _setupListenersOnAddress(forwarder, listenerName, address, port, - (char *)interfaceGetName(iface)); - } - } - } - - interfaceSetDestroy(&set); -} - -void configurationListeners_SetutpLocalIPv4(const Configuration *config, - uint16_t port) { - Forwarder *forwarder = configuration_GetForwarder(config); - in_addr_t addr = inet_addr("127.0.0.1"); - uint16_t network_byte_order_port = htons(port); - - char listenerNameUdp[SYMBOLIC_NAME_LEN] = "lo_udp"; - char listenerNameTcp[SYMBOLIC_NAME_LEN] = "lo_tcp"; - char *loopback_interface = "lo"; - _setupUdpListenerOnInet(forwarder, listenerNameUdp,(ipv4_addr_t *)&(addr), - &network_byte_order_port, loopback_interface); - _setupTcpListenerOnInet(forwarder, listenerNameTcp, (ipv4_addr_t *)&(addr), - &network_byte_order_port, loopback_interface); -} diff --git a/hicn-light/src/hicn/config/configurationListeners.h b/hicn-light/src/hicn/config/configurationListeners.h deleted file mode 100644 index b09ad5167..000000000 --- a/hicn-light/src/hicn/config/configurationListeners.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file configurationListeners.h - * @brief Configuration routines related to Listeners - * - * Adding and removing listeners. - * - */ - -#ifndef configurationListeners_h -#define configurationListeners_h - -#include <hicn/config/configuration.h> -#include <hicn/core/forwarder.h> - -#include <hicn/utils/address.h> - -/** - * Setup udp, tcp, and local listeners - * - * Will bind to all available IP protocols on the given port. - * Does not add Ethernet listeners. - * - * @param port is the UPD and TCP port to use - * @param localPath is the AF_UNIX path to use, if NULL no AF_UNIX listener is - * setup - * - * Example: - * @code - * <#example#> - * @endcode - */ -void configurationListeners_SetupAll(const Configuration *config, uint16_t port, - const char *localPath); - -void configurationListeners_SetutpLocalIPv4(const Configuration *config, - uint16_t port); - -bool configurationListeners_Remove(const Configuration *config); - -// light functions - -/** - * Add new listener. - * - * @param request The request coming from hicnLightControl or the - * configuration file. The bytes in the request are - * ordered following the network byte order convention. - * - * @param ingressId The connection id of the incoming request. - */ -struct iovec *configurationListeners_Add(Configuration *config, - struct iovec *request, - unsigned ingressId); - -struct iovec *configurationListeners_AddPunting(Configuration *config, - struct iovec *request, - unsigned ingressId); - -#endif /* defined(configurationListeners_h) */ diff --git a/hicn-light/src/hicn/config/configuration_file.c b/hicn-light/src/hicn/config/configuration_file.c new file mode 100644 index 000000000..2e8e7a6ac --- /dev/null +++ b/hicn-light/src/hicn/config/configuration_file.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021 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 _WIN32 +#include <unistd.h> +#endif +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <hicn/config/configuration_file.h> +#include <hicn/util/sstrncpy.h> + +#include "commands.h" +#include "parse.h" + +#define BUFFERLEN 2048 + +static char *_trim(char *str) { + char *end; + + // Trim leading space + while (isspace((unsigned char)*str)) str++; + + if (*str == 0) // All spaces? + return str; + + // Trim trailing space + end = str + strnlen_s(str, BUFFERLEN) - 1; + while (end > str && isspace((unsigned char)*end)) end--; + + // Write new null terminator character + end[1] = '\0'; + + return str; +} + +bool configuration_file_process(forwarder_t *forwarder, const char *filename) { + assert(forwarder); + assert(filename); + + int linesRead = 0; + FILE *f = fopen(filename, "r"); + if (!f) { + ERROR("Could not open configuration file %s: (%d) %s", filename, errno, + strerror(errno)); + goto ERR_OPEN; + } + DEBUG("Opening configuration file %s", filename); + + char buffer[BUFFERLEN]; + bool success = true; + // TODO(eloparco): We could use a fake socket since we only need the vft + hc_sock_t *s = hc_sock_create_forwarder(HICNLIGHT_NG); + if (!s) { + ERROR("Could not create socket"); + goto ERR_SOCK; + } + + while (success && fgets(buffer, BUFFERLEN, f) != NULL) { + linesRead++; + + char *cmd = _trim(buffer); + if (strnlen_s(cmd, BUFFERLEN) <= 0) continue; + if (cmd[0] == '#') continue; + + INFO("Processing command: %s", cmd); + hc_command_t command = {}; + if (parse(cmd, &command) < 0) { + ERROR("Error parsing command : '%s'", cmd); + continue; + } + + // TODO(eloparco): Handle all commands + hc_result_t *result = NULL; + if (command.action == ACTION_CREATE) { + if (command.object.type == OBJECT_LISTENER) { + result = hc_listener_create_conf(s, &command.object.listener); + } else if (command.object.type == OBJECT_CONNECTION) { + result = hc_connection_create_conf(s, &command.object.connection); + } else if (command.object.type == OBJECT_ROUTE) { + result = hc_route_create_conf(s, &command.object.route); + } else if (command.object.type == OBJECT_LOCAL_PREFIX) { + result = hc_strategy_add_local_prefix_conf(s, &command.object.strategy); + } + } else if (command.action == ACTION_SET) { + if (command.object.type == OBJECT_STRATEGY) { + result = hc_strategy_set_conf(s, &command.object.strategy); + } + } + if (result == NULL) { + ERROR("Command '%s' not supported", cmd); + continue; + } + + size_t _unused; + hc_msg_t *msg = hc_result_get_msg(s, result); + command_type_t cmd_id = hc_result_get_cmd_id(s, result); + bool success = hc_result_get_success(s, result); + if (success == false) { + ERROR("Error serializing command : '%s'", cmd); + continue; + } + + command_process(forwarder, (uint8_t *)msg, cmd_id, CONNECTION_ID_UNDEFINED, + &_unused); + hc_result_free(result); + } + hc_sock_free(s); + + if (ferror(f)) { + ERROR("Error on input file %s line %d: (%d) %s", filename, linesRead, errno, + strerror(errno)); + goto ERR_READ; + } + fclose(f); + return true; + +ERR_SOCK: + hc_sock_free(s); +ERR_READ: + fclose(f); +ERR_OPEN: + return false; +} diff --git a/hicn-light/src/hicn/config/configuration_file.h b/hicn-light/src/hicn/config/configuration_file.h new file mode 100644 index 000000000..4d9535ab7 --- /dev/null +++ b/hicn-light/src/hicn/config/configuration_file.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file configuration_file.h + * @brief Accepts a filename and provides a means to read it into Configuration + * + * Reads a configuration file and converts the lines in to configuration + * commands for use in Configuration. + * + * Accepts '#' lines as comments. Skips blank and whitespace-only lines. + * + */ + +#ifndef configuration_file_h +#define configuration_file_h + +#include <hicn/core/forwarder.h> + +/** + * Configure hicn-light by reading a configuration file line-by-line and + * issueing commands to the forwarder. + * + * The configuration file is a set of lines, just like used in hicnLightControl. + * You need to have "add listener" lines in the file to receive connections. No + * default listeners are configured. + * + * This function reads the file line by line, skipping '#' and blank lines, and + * will stop on the first error. Lines already processed will not be un-done. + * + * @param[in] forwarder An allocated forwarder_t + * @param[in] filename The path to the configuration file + * + * @retval true The entire files was processed without error. + * @retval false There was an error in the file. + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool configuration_file_process(forwarder_t* forwarder, const char* filename); + +#endif /* defined(configuration_file_h) */ diff --git a/hicn-light/src/hicn/config/controlAdd.c b/hicn-light/src/hicn/config/controlAdd.c deleted file mode 100644 index cac8e7913..000000000 --- a/hicn-light/src/hicn/config/controlAdd.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <parc/assert/parc_Assert.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlAdd.h> -#include <hicn/config/controlAddConnection.h> -#include <hicn/config/controlAddListener.h> -#include <hicn/config/controlAddPunting.h> -#include <hicn/config/controlAddRoute.h> -#ifdef WITH_POLICY -#include <hicn/config/controlAddPolicy.h> -#endif /* WITH_POLICY */ - -// =================================================== - -static void _controlAdd_Init(CommandParser *parser, CommandOps *ops); - -static CommandReturn _controlAdd_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static CommandReturn _controlAdd_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -// =================================================== - -static const char *command_add = "add"; -static const char *help_command_add = "help add"; - -CommandOps *webControlAdd_Create(ControlState *state) { - return commandOps_Create(state, command_add, _controlAdd_Init, - _controlAdd_Execute, commandOps_Destroy); -} - -CommandOps *controlAdd_CreateHelp(ControlState *state) { - return commandOps_Create(state, help_command_add, NULL, - _controlAdd_HelpExecute, commandOps_Destroy); -} - -// =================================================== - -static CommandReturn _controlAdd_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - CommandOps *ops_add_connection = controlAddConnection_Create(NULL); - CommandOps *ops_add_route = controlAddRoute_Create(NULL); - CommandOps *ops_add_punting = controlAddPunting_Create(NULL); - CommandOps *ops_add_listener = controlAddListener_Create(NULL); -#ifdef WITH_POLICY - CommandOps *ops_add_policy = controlAddPolicy_Create(NULL); -#endif /* WITH_POLICY */ -#ifdef WITH_POLICY - snprintf(output, output_size, "Available commands:\n %s\n %s\n %s\n %s\n %s\n\n", - ops_add_connection->command, - ops_add_route->command, - ops_add_punting->command, - ops_add_listener->command, - ops_add_policy->command); -#else - snprintf(output, output_size, "Available commands:\n %s\n %s\n %s\n %s\n\n", - ops_add_connection->command, - ops_add_route->command, - ops_add_punting->command, - ops_add_listener->command); - -#endif /* WITH_POLICY */ - - commandOps_Destroy(&ops_add_connection); - commandOps_Destroy(&ops_add_route); - commandOps_Destroy(&ops_add_punting); - commandOps_Destroy(&ops_add_listener); -#ifdef WITH_POLICY - commandOps_Destroy(&ops_add_policy); -#endif /* WITH_POLICY */ - return CommandReturn_Success; -} - -static void _controlAdd_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - controlState_RegisterCommand(state, controlAddListener_HelpCreate(state)); - controlState_RegisterCommand(state, controlAddListener_Create(state)); - controlState_RegisterCommand(state, controlAddConnection_HelpCreate(state)); - controlState_RegisterCommand(state, controlAddRoute_HelpCreate(state)); - controlState_RegisterCommand(state, controlAddConnection_Create(state)); - controlState_RegisterCommand(state, controlAddRoute_Create(state)); - controlState_RegisterCommand(state, controlAddPunting_Create(state)); - controlState_RegisterCommand(state, controlAddPunting_HelpCreate(state)); -#ifdef WITH_POLICY - controlState_RegisterCommand(state, controlAddPolicy_HelpCreate(state)); - controlState_RegisterCommand(state, controlAddPolicy_Create(state)); -#endif /* WITH_POLICY */ -} - -static CommandReturn _controlAdd_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlAdd_HelpExecute(parser, ops, args, output, output_size); -} diff --git a/hicn-light/src/hicn/config/controlAdd.h b/hicn-light/src/hicn/config/controlAdd.h deleted file mode 100644 index 7c160b5f7..000000000 --- a/hicn-light/src/hicn/config/controlAdd.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_Add.h - * @brief Command-line "add" node - * - * Implements the "add" node of the CLI tree - * - * - */ - -#ifndef control_Add_h -#define control_Add_h - -#include <hicn/config/controlState.h> - -CommandOps *webControlAdd_Create(ControlState *state); -CommandOps *controlAdd_CreateHelp(ControlState *state); -#endif // control_Add_h diff --git a/hicn-light/src/hicn/config/controlAddConnection.c b/hicn-light/src/hicn/config/controlAddConnection.c deleted file mode 100644 index eed37f3ad..000000000 --- a/hicn-light/src/hicn/config/controlAddConnection.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <parc/assert/parc_Assert.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> - -#include <hicn/config/controlAddConnection.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -// =================================================== - -static void _controlAddConnection_Init(CommandParser *parser, CommandOps *ops); -static CommandReturn _controlAddConnection_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlAddConnection_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -// =================================================== - -#ifdef __linux__ -static CommandReturn _controlAddConnection_HicnHelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlAddConnection_HicnExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -#endif - -static CommandReturn _controlAddConnection_UdpHelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlAddConnection_UdpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static CommandReturn _controlAddConnection_TcpHelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlAddConnection_TcpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -// =================================================== - -static const char *_commandAddConnection = "add connection"; -#ifdef __linux__ -static const char *_commandAddConnectionHicn = "add connection hicn"; -#endif -static const char *_commandAddConnectionUdp = "add connection udp"; -static const char *_commandAddConnectionTcp = "add connection tcp"; -static const char *_commandAddConnectionHelp = "help add connection"; -#ifdef __linux__ -static const char *_commandAddConnectionHicnHelp = "help add connection hicn"; -#endif -static const char *_commandAddConnectionUdpHelp = "help add connection udp"; -static const char *_commandAddConnectionTcpHelp = "help add connection tcp"; - -// =================================================== - -CommandOps *controlAddConnection_Create(ControlState *state) { - return commandOps_Create(state, _commandAddConnection, - _controlAddConnection_Init, - _controlAddConnection_Execute, commandOps_Destroy); -} - -CommandOps *controlAddConnection_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddConnectionHelp, NULL, - _controlAddConnection_HelpExecute, - commandOps_Destroy); -} - -// =================================================== - -#ifdef __linux__ -static CommandOps *_controlAddConnection_HicnCreate(ControlState *state) { - return commandOps_Create(state, _commandAddConnectionHicn, NULL, - _controlAddConnection_HicnExecute, - commandOps_Destroy); -} -#endif - -static CommandOps *_controlAddConnection_UdpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddConnectionUdp, NULL, - _controlAddConnection_UdpExecute, - commandOps_Destroy); -} - -static CommandOps *_controlAddConnection_TcpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddConnectionTcp, NULL, - _controlAddConnection_TcpExecute, - commandOps_Destroy); -} - -// =================================================== -#ifdef __linux__ -static CommandOps *_controlAddConnection_HicnHelpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddConnectionHicnHelp, NULL, - _controlAddConnection_HicnHelpExecute, - commandOps_Destroy); -} -#endif - -static CommandOps *_controlAddConnection_UdpHelpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddConnectionUdpHelp, NULL, - _controlAddConnection_UdpHelpExecute, - commandOps_Destroy); -} - -static CommandOps *_controlAddConnection_TcpHelpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddConnectionTcpHelp, NULL, - _controlAddConnection_TcpHelpExecute, - commandOps_Destroy); -} - -// =================================================== - -static CommandReturn _controlAddConnection_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { -#ifdef __linux__ - snprintf(output, output_size, "Available commands:\n %s\n %s\n %s\n\n", - _commandAddConnectionHicn, - _commandAddConnectionUdp, - _commandAddConnectionTcp); -#else - snprintf(output, output_size, "Available commands:\n %s\n %s\n\n", - _commandAddConnectionUdp, - _commandAddConnectionTcp); -#endif - return CommandReturn_Success; -} - -static void _controlAddConnection_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; -#ifdef __linux__ - controlState_RegisterCommand(state, - _controlAddConnection_HicnHelpCreate(state)); -#endif - controlState_RegisterCommand(state, - _controlAddConnection_UdpHelpCreate(state)); - controlState_RegisterCommand(state, - _controlAddConnection_TcpHelpCreate(state)); -#ifdef __linux__ - controlState_RegisterCommand(state, _controlAddConnection_HicnCreate(state)); -#endif - controlState_RegisterCommand(state, _controlAddConnection_UdpCreate(state)); - controlState_RegisterCommand(state, _controlAddConnection_TcpCreate(state)); -} - -static CommandReturn _controlAddConnection_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlAddConnection_HelpExecute(parser, ops, args, output, output_size); -} - -// =================================================== -// functions general to all connection types - -/** - * Create a tunnel in the forwarder based on the addresses - * - * Caller retains ownership of memory. - * The symbolic name will be used to refer to this connection. It must be unqiue - * otherwise the forwarder will reject this commend. - * - * @param [in] parser An allocated CommandParser - * @param [in] ops Allocated CommandOps (needed to extract ControlState) - * @param [in] localAddress the local IP and port. The port may be the wildcard - * value. - * @param [in] remoteAddress The remote IP and port (both must be specified) - * @param [in] tunnelType The tunneling protocol - * @param [in] symbolic The symbolic name for the connection (must be unique) - * @param [in] output Output buffer - * @param [in] output_size Output buffer size - * - * @return <#value#> <#explanation#> - * - * Example: - * @code - * { - * struct sockaddr_in *anyAddress = parcNetwork_SockInet4AddressAny(); - * struct sockaddr_in *remote = - * parcNetwork_SockInet4Address("192.168.1.2", 9695); - * - * Address *localAddress = addressCreateFromInet(anyAddress); - * Address *remoteAddress = addressCreateFromInet(remote); - * - * control_CreateTunnel(state, localAddress, remoteAddress, IPTUN_TCP, - * "conn7"); - * - * addressDestroy(&localAddress); - * addressDestroy(&remoteAddress); - * parcMemory_Deallocate((void **)&remote); - * parcMemory_Deallocate((void **)&anyAddress); - * } - * @endcode - */ - -static CommandReturn _controlAddConnection_CreateTunnel(CommandParser *parser, - CommandOps *ops, const char *local_ip, - const char *local_port, - const char *remote_ip, - const char *remote_port, - connection_type tunnelType, - const char *symbolic, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - // a request like this always has an interface index of 0 [FIELD REMOVED] - // unsigned int interfaceIndex = 0; - - // allocate command payload - add_connection_command *addConnectionCommand = - parcMemory_AllocateAndClear(sizeof(add_connection_command)); - - // check and set IP addresses - if (inet_pton(AF_INET, remote_ip, &addConnectionCommand->remoteIp.v4.as_u32) == - 1 && - inet_pton(AF_INET, local_ip, &addConnectionCommand->localIp.v4.as_u32) == 1) { - addConnectionCommand->ipType = ADDR_INET; - - } else if (inet_pton(AF_INET6, remote_ip, - &addConnectionCommand->remoteIp.v6.as_in6addr) == 1 && - inet_pton(AF_INET6, local_ip, - &addConnectionCommand->localIp.v6.as_in6addr) == 1) { - addConnectionCommand->ipType = ADDR_INET6; - - } else { - snprintf(output, output_size, "Error: local address %s not same type as remote address %s\n", - local_ip, remote_ip); - parcMemory_Deallocate(&addConnectionCommand); - return CommandReturn_Failure; - } - - // Fill remaining payload fields - addConnectionCommand->connectionType = tunnelType; - strcpy(addConnectionCommand->symbolic, symbolic); - addConnectionCommand->remotePort = htons((uint16_t)atoi(remote_port)); - addConnectionCommand->localPort = htons((uint16_t)atoi(local_port)); - - // send message and receive response - struct iovec *response = - utils_SendRequest(state, ADD_CONNECTION, addConnectionCommand, - sizeof(add_connection_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} - -static CommandReturn _controlAddConnection_IpHelp(CommandParser *parser, - CommandOps *ops, - PARCList *args, - const char *protocol, - char *output, - size_t output_size) { - snprintf(output, output_size, - #ifdef __linux__ - "add connection hicn <symbolic> <remote_ip> <local_ip>\n" - #endif - "add connection udp <symbolic> <remote_ip> <port> <local_ip> <port>\n" - " <symbolic> : symbolic name, e.g. 'conn1' (must be " - "unique, start with alpha)\n" - " <remote_ip> : the IPv4 or IPv6 or hostname of the remote system\n" - " <local_ip> : optional local IP address to bind to\n" - "\n"); - return CommandReturn_Success; -} - -#ifdef __linux__ -static CommandReturn _controlAddConnection_HicnHelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - _controlAddConnection_IpHelp(parser, ops, args, "hicn", output, output_size); - - return CommandReturn_Success; -} - -static CommandReturn _controlAddConnection_HicnExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - static const int _indexSymbolic = 3; - static const int _indexRemAddr = 4; - static const int _indexLocAddr = 5; - - if (parcList_Size(args) != 6) { - _controlAddConnection_HicnHelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - char *symbolic = parcList_GetAtIndex(args, _indexSymbolic); - - if (!utils_ValidateSymbolicName(symbolic)) { - snprintf(output, output_size, "Invalid symbolic name. Must begin with alpha and contain only " - "alphanum.\n"); - return CommandReturn_Failure; - } - - char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr); - char *local_ip = parcList_GetAtIndex(args, _indexLocAddr); - char *port = "1234"; // this is a random port number that will be ignored - - return _controlAddConnection_CreateTunnel( - parser, ops, local_ip, port, remote_ip, port, HICN_CONN, symbolic, output, output_size); -} -#endif - -static CommandReturn _controlAddConnection_UdpHelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - _controlAddConnection_IpHelp(parser, ops, args, "udp", output, output_size); - - return CommandReturn_Success; -} - -static CommandReturn _controlAddConnection_UdpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - static const int _indexSymbolic = 3; - static const int _indexRemAddr = 4; - static const int _indexRemPort = 5; - static const int _indexLocAddr = 6; - static const int _indexLocPort = 7; - - if (parcList_Size(args) != 8) { - _controlAddConnection_UdpHelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - char *symbolic = parcList_GetAtIndex(args, _indexSymbolic); - size_t offset = 0; - if (!utils_ValidateSymbolicName(symbolic)) { - snprintf(output, output_size, - "Invalid symbolic name. Must begin with alpha and contain only " - "alphanum.\n"); - return CommandReturn_Failure; - } - - char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr); - char *local_ip = parcList_GetAtIndex(args, _indexLocAddr); - - char *remote_port = parcList_GetAtIndex(args, _indexRemPort); - char *local_port = parcList_GetAtIndex(args, _indexLocPort); - - return _controlAddConnection_CreateTunnel(parser, ops, local_ip, local_port, - remote_ip, remote_port, UDP_CONN, - symbolic, - output + offset, output_size - offset); -} - -static CommandReturn _controlAddConnection_TcpHelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - _controlAddConnection_IpHelp(parser, ops, args, "tcp", output, output_size); - - return CommandReturn_Success; -} - -static CommandReturn _controlAddConnection_TcpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - static const int _indexSymbolic = 3; - static const int _indexRemAddr = 4; - static const int _indexRemPort = 5; - static const int _indexLocAddr = 6; - static const int _indexLocPort = 7; - - if (parcList_Size(args) != 8) { - _controlAddConnection_UdpHelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - char *symbolic = parcList_GetAtIndex(args, _indexSymbolic); - if (!utils_ValidateSymbolicName(symbolic)) { - snprintf(output, output_size, "Invalid symbolic name. Must begin with alpha and contain only " - "alphanum.\n"); - return CommandReturn_Failure; - } - - char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr); - char *local_ip = parcList_GetAtIndex(args, _indexLocAddr); - - char *remote_port = parcList_GetAtIndex(args, _indexRemPort); - char *local_port = parcList_GetAtIndex(args, _indexLocPort); - - return _controlAddConnection_CreateTunnel(parser, ops, local_ip, local_port, - remote_ip, remote_port, TCP_CONN, - symbolic, - output, output_size); -} diff --git a/hicn-light/src/hicn/config/controlAddConnection.h b/hicn-light/src/hicn/config/controlAddConnection.h deleted file mode 100644 index 546388efc..000000000 --- a/hicn-light/src/hicn/config/controlAddConnection.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_AddConnection.h - * @brief Command-line "add connection" node - * - * Implements the "add connection" node of the CLI tree - * - * - */ - -#ifndef controlAddConnection_h -#define controlAddConnection_h - -#include <hicn/config/controlState.h> -CommandOps *controlAddConnection_Create(ControlState *state); -CommandOps *controlAddConnection_HelpCreate(ControlState *state); -#endif // controlAddConnection_h diff --git a/hicn-light/src/hicn/config/controlAddListener.c b/hicn-light/src/hicn/config/controlAddListener.c deleted file mode 100644 index df84c4691..000000000 --- a/hicn-light/src/hicn/config/controlAddListener.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <inttypes.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> - -#include <hicn/config/controlAddListener.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlAddListener_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlAddListener_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *command_add_listener = "add listener"; -static const char *command_help_add_listener = "help add listener"; - -CommandOps *controlAddListener_Create(ControlState *state) { - return commandOps_Create(state, command_add_listener, NULL, - _controlAddListener_Execute, commandOps_Destroy); -} - -CommandOps *controlAddListener_HelpCreate(ControlState *state) { - return commandOps_Create(state, command_help_add_listener, NULL, - _controlAddListener_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static const int _indexProtocol = 2; -static const int _indexSymbolic = 3; -static const int _indexAddress = 4; -static const int _indexPort = 5; -static const int _indexInterfaceName = 6; - -static CommandReturn _controlAddListener_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, - "commands:\n" -#ifdef __linux__ - " add listener hicn <symbolic> <localAddress> \n" -#endif - " add listener udp <symbolic> <localAddress> <port> <interface>\n" - " add listener tcp <symbolic> <localAddress> <port> <interface>\n" - "\n" - " symbolic: User defined name for listener, must start with " - "alpha and be alphanum\n" -#ifdef __linux__ - " protocol: hicn | udp\n" -#else - " protocol: udp\n" -#endif - " localAddress: IPv4 or IPv6 address (or prefix protocol = hicn) " - "assigend to the local interface\n" - " port: Udp port\n" - " interface: interface\n" - "\n" - "Notes:\n" - " The symblic name must be unique or the source will reject it.\n" -#ifdef __linux__ - " If protocol = hicn: the address 0::0 indicates the main listern, " - "for which we can set punting rules.\n" -#endif - ); - return CommandReturn_Success; -} - -static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops, - const char *symbolic, const char *addr, - const char *port, char *interfaceName, listener_mode mode, - connection_type type, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - // allocate command payload - add_listener_command *addListenerCommand = - parcMemory_AllocateAndClear(sizeof(add_listener_command)); - - // check and set IP address - if (inet_pton(AF_INET, addr, &addListenerCommand->address.v4.as_u32) == 1) { - addListenerCommand->addressType = ADDR_INET; - - } else if (inet_pton(AF_INET6, addr, &addListenerCommand->address.v6.as_in6addr) == 1) { - addListenerCommand->addressType = ADDR_INET6; - - } else { - snprintf(output, output_size, "Error: %s is not a valid network address \n", addr); - parcMemory_Deallocate(&addListenerCommand); - return CommandReturn_Failure; - } - - // Fill remaining payload fields - size_t name_size = strlen((const char *)interfaceName); - if(name_size > SYMBOLIC_NAME_LEN){ - //cut the string - name_size = SYMBOLIC_NAME_LEN; - } - - memcpy(addListenerCommand->interfaceName, interfaceName, name_size); - addListenerCommand->listenerMode = mode; - addListenerCommand->connectionType = type; - addListenerCommand->port = htons((uint16_t)atoi(port)); - strcpy(addListenerCommand->symbolic, symbolic); - - // send message and receive response - struct iovec *response = utils_SendRequest( - state, ADD_LISTENER, addListenerCommand, sizeof(add_listener_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} - -static CommandReturn _controlAddListener_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 5 && parcList_Size(args) != 7) { - _controlAddListener_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - CommandReturn result = CommandReturn_Failure; - - const char *symbolic = parcList_GetAtIndex(args, _indexSymbolic); - - if (!utils_ValidateSymbolicName(symbolic)) { - snprintf(output, output_size, - "Error: symbolic name must begin with an alpha and be alphanum " - "after\n"); - return result; - } - - const char *protocol = parcList_GetAtIndex(args, _indexProtocol); - const char *host = parcList_GetAtIndex(args, _indexAddress); - char *interfaceName = parcList_GetAtIndex(args, _indexInterfaceName); - if ((strcasecmp("hicn", protocol) == 0)) { - const char *port = - "1234"; // this is a random port number that will be ignored - - // here we discard the prefix len if it exists, since we don't use it in - // code but we let libhicn to find the right ip address. - return _CreateListener(parser, ops, symbolic, host, port, "hicn", HICN_MODE, - HICN_CONN, output, output_size); - } - const char *port = parcList_GetAtIndex(args, _indexPort); - - if ((strcasecmp("udp", protocol) == 0)) { - return _CreateListener(parser, ops, symbolic, host, port, interfaceName, IP_MODE, - UDP_CONN, output, output_size); - } else if ((strcasecmp("tcp", protocol) == 0)) { - return _CreateListener(parser, ops, symbolic, host, port, interfaceName, IP_MODE, - TCP_CONN, output, output_size); - } else { - _controlAddListener_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - if (result == CommandReturn_Failure) snprintf(output, output_size, "creation failed\n"); - - return result; -} diff --git a/hicn-light/src/hicn/config/controlAddListener.h b/hicn-light/src/hicn/config/controlAddListener.h deleted file mode 100644 index 6516d1779..000000000 --- a/hicn-light/src/hicn/config/controlAddListener.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_AddListener.h - * @brief Add a listener to an interface - * - * <#Detailed Description#> - * - */ - -#ifndef Control_AddListener_h -#define Control_AddListener_h - -#include <hicn/config/controlState.h> -CommandOps *controlAddListener_Create(ControlState *state); -CommandOps *controlAddListener_HelpCreate(ControlState *state); -#endif // Control_AddListener_h diff --git a/hicn-light/src/hicn/config/controlAddPolicy.c b/hicn-light/src/hicn/config/controlAddPolicy.c deleted file mode 100644 index 66439d29c..000000000 --- a/hicn-light/src/hicn/config/controlAddPolicy.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#ifdef WITH_POLICY - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> - -#include <hicn/config/controlAddPolicy.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> -#include <hicn/utils/token.h> - -static CommandReturn _controlAddPolicy_Execute(CommandParser *parser, - CommandOps *ops, PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlAddPolicy_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandAddPolicy = "add policy"; -static const char *_commandAddPolicyHelp = "help add policy"; - -CommandOps *controlAddPolicy_Create(ControlState *state) { - return commandOps_Create(state, _commandAddPolicy, NULL, - _controlAddPolicy_Execute, commandOps_Destroy); -} - -CommandOps *controlAddPolicy_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddPolicyHelp, NULL, - _controlAddPolicy_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlAddPolicy_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - size_t output_offset = snprintf(output, output_size, "commands:\n" - " add policy <prefix> <app_name>"); - - #define _(x, y) output_offset += snprintf(output + output_offset, output_size - output_offset, " FLAG:%s", policy_tag_str[POLICY_TAG_ ## x]); - foreach_policy_tag - #undef _ - - output_offset += snprintf(output + output_offset, output_size - output_offset,"\n"); - printf("\n"); - output_offset += snprintf(output + output_offset, output_size - output_offset, - " prefix: The hicn name as IPv4 or IPv6 address (e.g 1234::0/64)\n" - " app_name: The application name associated to this policy\n" - " FLAG:*: A value among [neutral|require|prefer|avoid|prohibit] with an optional '!' character prefix for disabling changes\n" - "\n"); - - return CommandReturn_Success; -} - -static CommandReturn _controlAddPolicy_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - if (parcList_Size(args) != 11) { - _controlAddPolicy_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *prefixStr = parcList_GetAtIndex(args, 2); - char *addr = (char *)malloc((strlen(prefixStr) + 1) * sizeof(char)); - - // separate address and len - char *slash; - uint32_t len = 0; - strcpy(addr, prefixStr); - slash = strrchr(addr, '/'); - if (slash != NULL) { - len = atoi(slash + 1); - *slash = '\0'; - } - - // allocate command payload - add_policy_command *addPolicyCommand = - parcMemory_AllocateAndClear(sizeof(add_policy_command)); - - // check and set IP address - if (inet_pton(AF_INET, addr, &addPolicyCommand->address.v4.as_u32) == 1) { - if (len > 32) { - snprintf(output, output_size, "ERROR: exceeded INET mask length, max=32\n"); - parcMemory_Deallocate(&addPolicyCommand); - free(addr); - return CommandReturn_Failure; - } - addPolicyCommand->addressType = ADDR_INET; - } else if (inet_pton(AF_INET6, addr, &addPolicyCommand->address.v6.as_in6addr) == 1) { - if (len > 128) { - snprintf(output, output_size, "ERROR: exceeded INET6 mask length, max=128\n"); - parcMemory_Deallocate(&addPolicyCommand); - free(addr); - return CommandReturn_Failure; - } - addPolicyCommand->addressType = ADDR_INET6; - } else { - snprintf(output, output_size, "Error: %s is not a valid network address \n", addr); - parcMemory_Deallocate(&addPolicyCommand); - free(addr); - return CommandReturn_Failure; - } - - free(addr); - - addPolicyCommand->len = len; - - hicn_policy_t policy; - snprintf((char*)policy.app_name, APP_NAME_LEN, "%s", (char*)parcList_GetAtIndex(args, 3)); - for (int i=4; i < 11; i++) { - const char *tag = parcList_GetAtIndex(args, i); - policy_tag_state_t tag_state; - tag_state.disabled = (tag[0] == '!') ? 1 : 0; - if (strcmp(&tag[tag_state.disabled], "neutral") == 0) { - tag_state.state = POLICY_STATE_NEUTRAL; - } else if (strcmp(&tag[tag_state.disabled], "require") == 0) { - tag_state.state = POLICY_STATE_REQUIRE; - } else if (strcmp(&tag[tag_state.disabled], "prefer") == 0) { - tag_state.state = POLICY_STATE_PREFER; - } else if (strcmp(&tag[tag_state.disabled], "avoid") == 0) { - tag_state.state = POLICY_STATE_AVOID; - } else if (strcmp(&tag[tag_state.disabled], "prohibit") == 0) { - tag_state.state = POLICY_STATE_PROHIBIT; - } else { - snprintf(output, output_size, "ERROR: invalid tag value '%s'\n", tag); - parcMemory_Deallocate(&addPolicyCommand); - free(addr); - return CommandReturn_Failure; - } - - policy.tags[i-4] = tag_state; - - } - - addPolicyCommand->policy = policy; - - // send message and receive response - struct iovec *response = utils_SendRequest(state, ADD_POLICY, addPolicyCommand, - sizeof(add_policy_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} - -#endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/config/controlAddPunting.c b/hicn-light/src/hicn/config/controlAddPunting.c deleted file mode 100644 index 41d846d55..000000000 --- a/hicn-light/src/hicn/config/controlAddPunting.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <hicn/utils/punting.h> - -#include <hicn/config/controlAddPunting.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlAddPunting_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlAddPunting_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandAddPunting = "add punting"; -static const char *_commandAddPuntingHelp = "help add punting"; - -static const int _indexSymbolic = 2; -static const int _indexPrefix = 3; - -CommandOps *controlAddPunting_Create(ControlState *state) { - return commandOps_Create(state, _commandAddPunting, NULL, - _controlAddPunting_Execute, commandOps_Destroy); -} - -CommandOps *controlAddPunting_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddPuntingHelp, NULL, - _controlAddPunting_HelpExecute, commandOps_Destroy); -} - -// ===================================================== - -static CommandReturn _controlAddPunting_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "add punting <symbolic> <prefix>\n" - " <symbolic> : listener symbolic name\n" - " <address> : prefix to add as a punting rule. (example " - "1234::0/64)\n" - "\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlAddPunting_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - if (parcList_Size(args) != 4) { - _controlAddPunting_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *symbolicOrConnid = parcList_GetAtIndex(args, _indexSymbolic); - - if (!utils_ValidateSymbolicName(symbolicOrConnid) && - !utils_IsNumber(symbolicOrConnid)) { - snprintf(output, output_size, - "ERROR: Invalid symbolic or connid:\n" - "symbolic name must begin with an alpha followed by alphanum;\nconnid " - "must be an integer\n"); - return CommandReturn_Failure; - } - - const char *prefixStr = parcList_GetAtIndex(args, _indexPrefix); - char *addr = (char *)malloc((strlen(prefixStr) + 1) * sizeof(char)); - - // separate address and len - char *slash; - uint32_t len = 0; - strcpy(addr, prefixStr); - slash = strrchr(addr, '/'); - if (slash != NULL) { - len = atoi(slash + 1); - *slash = '\0'; - } - - // allocate command payload - add_punting_command *addPuntingCommand = - parcMemory_AllocateAndClear(sizeof(add_punting_command)); - - // check and set IP address - if (inet_pton(AF_INET, addr, &addPuntingCommand->address.v4.as_u32) == 1) { - if (len > 32) { - snprintf(output, output_size, "ERROR: exceeded INET mask length, max=32\n"); - parcMemory_Deallocate(&addPuntingCommand); - free(addr); - return CommandReturn_Failure; - } - addPuntingCommand->addressType = ADDR_INET; - } else if (inet_pton(AF_INET6, addr, &addPuntingCommand->address.v6.as_in6addr) == 1) { - if (len > 128) { - snprintf(output, output_size, "ERROR: exceeded INET6 mask length, max=128\n"); - parcMemory_Deallocate(&addPuntingCommand); - free(addr); - return CommandReturn_Failure; - } - addPuntingCommand->addressType = ADDR_INET6; - } else { - snprintf(output, output_size, "Error: %s is not a valid network address \n", addr); - parcMemory_Deallocate(&addPuntingCommand); - free(addr); - return CommandReturn_Failure; - } - - free(addr); - - // Fill remaining payload fields - addPuntingCommand->len = len; - strcpy(addPuntingCommand->symbolicOrConnid, symbolicOrConnid); - - // send message and receive response - struct iovec *response = utils_SendRequest( - state, ADD_PUNTING, addPuntingCommand, sizeof(add_punting_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} - -// ====================================================================== diff --git a/hicn-light/src/hicn/config/controlAddPunting.h b/hicn-light/src/hicn/config/controlAddPunting.h deleted file mode 100644 index 9cab76359..000000000 --- a/hicn-light/src/hicn/config/controlAddPunting.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 controlAddPunting_h -#define controlAddPunting_h - -#include <hicn/config/controlState.h> -CommandOps *controlAddPunting_Create(ControlState *state); -CommandOps *controlAddPunting_HelpCreate(ControlState *state); -#endif diff --git a/hicn-light/src/hicn/config/controlAddRoute.c b/hicn-light/src/hicn/config/controlAddRoute.c deleted file mode 100644 index 78c0173ea..000000000 --- a/hicn-light/src/hicn/config/controlAddRoute.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> - -#include <hicn/config/controlAddRoute.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlAddRoute_Execute(CommandParser *parser, - CommandOps *ops, PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlAddRoute_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandAddRoute = "add route"; -static const char *_commandAddRouteHelp = "help add route"; - -CommandOps *controlAddRoute_Create(ControlState *state) { - return commandOps_Create(state, _commandAddRoute, NULL, - _controlAddRoute_Execute, commandOps_Destroy); -} - -CommandOps *controlAddRoute_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandAddRouteHelp, NULL, - _controlAddRoute_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlAddRoute_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "commands:\n" - " add route <symbolic | connid> <prefix> <cost>\n" - "\n" - " symbolic: The symbolic name for an exgress\n" - " connid: The egress connection id (see 'help list connections')\n" - " prefix: The hicn name as IPv4 or IPv6 address (e.g 1234::0/64)\n" - " cost: positive integer representing cost\n" - "\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlAddRoute_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - if (parcList_Size(args) != 5) { - _controlAddRoute_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *symbolicOrConnid = parcList_GetAtIndex(args, 2); - - if (!utils_ValidateSymbolicName(symbolicOrConnid) && - !utils_IsNumber(symbolicOrConnid)) { - snprintf(output, output_size, "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an " - "alpha followed by alphanum;\nconnid must be an integer\n"); - return CommandReturn_Failure; - } - - unsigned cost = atoi(parcList_GetAtIndex(args, 4)); - - if (cost == 0) { - snprintf(output, output_size, "ERROR: cost must be positive integer, got %u from '%s'\n", cost, - (char *)parcList_GetAtIndex(args, 4)); - return CommandReturn_Failure; - } - - const char *prefixStr = parcList_GetAtIndex(args, 3); - char *addr = (char *)malloc((strlen(prefixStr) + 1) * sizeof(char)); - - // separate address and len - char *slash; - uint32_t len = 0; - strcpy(addr, prefixStr); - slash = strrchr(addr, '/'); - if (slash != NULL) { - len = atoi(slash + 1); - *slash = '\0'; - } - - // allocate command payload - add_route_command *addRouteCommand = - parcMemory_AllocateAndClear(sizeof(add_route_command)); - - // check and set IP address - if (inet_pton(AF_INET, addr, &addRouteCommand->address.v4.as_u32) == 1) { - if (len > 32) { - snprintf(output, output_size, "ERROR: exceeded INET mask length, max=32\n"); - parcMemory_Deallocate(&addRouteCommand); - free(addr); - return CommandReturn_Failure; - } - addRouteCommand->addressType = ADDR_INET; - } else if (inet_pton(AF_INET6, addr, &addRouteCommand->address.v6.as_in6addr) == 1) { - if (len > 128) { - snprintf(output, output_size, "ERROR: exceeded INET6 mask length, max=128\n"); - parcMemory_Deallocate(&addRouteCommand); - free(addr); - return CommandReturn_Failure; - } - addRouteCommand->addressType = ADDR_INET6; - } else { - snprintf(output, output_size, "Error: %s is not a valid network address \n", addr); - parcMemory_Deallocate(&addRouteCommand); - free(addr); - return CommandReturn_Failure; - } - - free(addr); - - // Fill remaining payload fields - addRouteCommand->len = len; - addRouteCommand->cost = (uint16_t)cost; - strcpy(addRouteCommand->symbolicOrConnid, symbolicOrConnid); - - // send message and receive response - struct iovec *response = utils_SendRequest(state, ADD_ROUTE, addRouteCommand, - sizeof(add_route_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlAddRoute.h b/hicn-light/src/hicn/config/controlAddRoute.h deleted file mode 100644 index 9588c0f42..000000000 --- a/hicn-light/src/hicn/config/controlAddRoute.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_AddRoute.h - * @brief Add a static route - * - * Implements the "add route" node of the CLI tree - * - */ - -#ifndef Control_AddRoute_h -#define Control_AddRoute_h - -#include <hicn/config/controlState.h> -CommandOps *controlAddRoute_Create(ControlState *state); -CommandOps *controlAddRoute_HelpCreate(ControlState *state); -#endif // Control_AddRoute_h diff --git a/hicn-light/src/hicn/config/controlCache.c b/hicn-light/src/hicn/config/controlCache.c deleted file mode 100644 index b6010fcfd..000000000 --- a/hicn-light/src/hicn/config/controlCache.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/security/parc_Security.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlCache.h> -#include <hicn/config/controlCacheClear.h> -#include <hicn/config/controlCacheServe.h> -#include <hicn/config/controlCacheStore.h> - -static void _controlCache_Init(CommandParser *parser, CommandOps *ops); -static CommandReturn _controlCache_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlCache_HelpExecute(CommandParser *parser, - CommandOps *ops, PARCList *args, - char *output, - size_t output_size); - -static const char *_commandCache = "cache"; -static const char *_commandCacheHelp = "help cache"; - -CommandOps *controlCache_Create(ControlState *state) { - return commandOps_Create(state, _commandCache, _controlCache_Init, - _controlCache_Execute, commandOps_Destroy); -} - -CommandOps *controlCache_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandCacheHelp, NULL, - _controlCache_HelpExecute, commandOps_Destroy); -} - -// ===================================================== - -static CommandReturn _controlCache_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - CommandOps *ops_cache_serve = controlCacheServe_HelpCreate(NULL); - CommandOps *ops_cache_store = controlCacheStore_HelpCreate(NULL); - CommandOps *ops_cache_clear = controlCacheClear_HelpCreate(NULL); - - snprintf(output, output_size, "Available commands:\n" - " %s\n %s\n %s\n\n", - ops_cache_serve->command, - ops_cache_store->command, - ops_cache_clear->command); - commandOps_Destroy(&ops_cache_serve); - commandOps_Destroy(&ops_cache_store); - commandOps_Destroy(&ops_cache_clear); - - return CommandReturn_Success; -} - -static void _controlCache_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - controlState_RegisterCommand(state, controlCacheServe_HelpCreate(state)); - controlState_RegisterCommand(state, controlCacheStore_HelpCreate(state)); - controlState_RegisterCommand(state, controlCacheClear_HelpCreate(state)); - controlState_RegisterCommand(state, controlCacheServe_Create(state)); - controlState_RegisterCommand(state, controlCacheStore_Create(state)); - controlState_RegisterCommand(state, controlCacheClear_Create(state)); -} - -static CommandReturn _controlCache_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlCache_HelpExecute(parser, ops, args, output, output_size); -} - -// ====================================================================== diff --git a/hicn-light/src/hicn/config/controlCache.h b/hicn-light/src/hicn/config/controlCache.h deleted file mode 100644 index c2f2402f1..000000000 --- a/hicn-light/src/hicn/config/controlCache.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 controlCache_h -#define controlCache_h - -#include <hicn/config/controlState.h> -CommandOps *controlCache_Create(ControlState *state); -CommandOps *controlCache_HelpCreate(ControlState *state); -#endif // controlCache_h diff --git a/hicn-light/src/hicn/config/controlCacheClear.c b/hicn-light/src/hicn/config/controlCacheClear.c deleted file mode 100644 index afd8f6fc1..000000000 --- a/hicn-light/src/hicn/config/controlCacheClear.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlCacheClear.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlCacheClear_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlCacheClear_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandCacheClear = "cache clear"; -static const char *_commandCacheClearHelp = "help cache clear"; - -// ==================================================== - -CommandOps *controlCacheClear_Create(ControlState *state) { - return commandOps_Create(state, _commandCacheClear, NULL, - _controlCacheClear_Execute, commandOps_Destroy); -} - -CommandOps *controlCacheClear_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandCacheClearHelp, NULL, - _controlCacheClear_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlCacheClear_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "cache clear\n\n"); - - return CommandReturn_Success; -} - -static CommandReturn _controlCacheClear_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 2) { - _controlCacheClear_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - ControlState *state = ops->closure; - // send message and receive response - struct iovec *response = utils_SendRequest(state, CACHE_CLEAR, NULL, 0); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlCacheClear.h b/hicn-light/src/hicn/config/controlCacheClear.h deleted file mode 100644 index 025758c34..000000000 --- a/hicn-light/src/hicn/config/controlCacheClear.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file controlCacheClear.h - * @brief Clear the cache - * - * Removes all the cached data form the local content store (if available) - * - */ - -#ifndef Control_CacheClear_h -#define Control_CacheClear_h - -#include <hicn/config/controlState.h> -CommandOps *controlCacheClear_Create(ControlState *state); -CommandOps *controlCacheClear_HelpCreate(ControlState *state); -#endif // Control_CacheClear_h diff --git a/hicn-light/src/hicn/config/controlCacheServe.c b/hicn-light/src/hicn/config/controlCacheServe.c deleted file mode 100644 index a4454037d..000000000 --- a/hicn-light/src/hicn/config/controlCacheServe.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlCacheServe.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlCacheServe_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlCacheServe_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandCacheServe = "cache serve"; -static const char *_commandCacheServeHelp = "help cache serve"; - -// ==================================================== - -CommandOps *controlCacheServe_Create(ControlState *state) { - return commandOps_Create(state, _commandCacheServe, NULL, - _controlCacheServe_Execute, commandOps_Destroy); -} - -CommandOps *controlCacheServe_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandCacheServeHelp, NULL, - _controlCacheServe_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlCacheServe_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "cache serve [on|off]\n\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlCacheServe_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 3) { - _controlCacheServe_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - bool active; - if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) { - active = true; - } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) { - active = false; - } else { - _controlCacheServe_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - cache_serve_command *cacheServeCommand = - parcMemory_AllocateAndClear(sizeof(cache_serve_command)); - if (active) { - cacheServeCommand->activate = ACTIVATE_ON; - } else { - cacheServeCommand->activate = ACTIVATE_OFF; - } - - ControlState *state = ops->closure; - // send message and receive response - struct iovec *response = utils_SendRequest( - state, CACHE_SERVE, cacheServeCommand, sizeof(cache_serve_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlCacheServe.h b/hicn-light/src/hicn/config/controlCacheServe.h deleted file mode 100644 index afebc0601..000000000 --- a/hicn-light/src/hicn/config/controlCacheServe.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 Control_CacheServe_h -#define Control_CacheServe_h - -#include <hicn/config/controlState.h> -CommandOps *controlCacheServe_Create(ControlState *state); -CommandOps *controlCacheServe_HelpCreate(ControlState *state); -#endif // Control_CacheServe_h diff --git a/hicn-light/src/hicn/config/controlCacheStore.c b/hicn-light/src/hicn/config/controlCacheStore.c deleted file mode 100644 index 9f2a18146..000000000 --- a/hicn-light/src/hicn/config/controlCacheStore.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlCacheStore.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlCacheStore_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlCacheStore_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandCacheStore = "cache store"; -static const char *_commandCacheStoreHelp = "help cache store"; - -// ==================================================== - -CommandOps *controlCacheStore_Create(ControlState *state) { - return commandOps_Create(state, _commandCacheStore, NULL, - _controlCacheStore_Execute, commandOps_Destroy); -} - -CommandOps *controlCacheStore_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandCacheStoreHelp, NULL, - _controlCacheStore_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlCacheStore_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "cache store [on|off]\n\n"); - - return CommandReturn_Success; -} - -static CommandReturn _controlCacheStore_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 3) { - _controlCacheStore_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - bool active; - if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) { - active = true; - } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) { - active = false; - } else { - _controlCacheStore_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - cache_store_command *cacheStoreCommand = - parcMemory_AllocateAndClear(sizeof(cache_store_command)); - if (active) { - cacheStoreCommand->activate = ACTIVATE_ON; - } else { - cacheStoreCommand->activate = ACTIVATE_OFF; - } - - ControlState *state = ops->closure; - // send message and receive response - struct iovec *response = utils_SendRequest( - state, CACHE_STORE, cacheStoreCommand, sizeof(cache_store_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlCacheStore.h b/hicn-light/src/hicn/config/controlCacheStore.h deleted file mode 100644 index e32bf5663..000000000 --- a/hicn-light/src/hicn/config/controlCacheStore.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 Control_CacheStore_h -#define Control_CacheStore_h - -#include <hicn/config/controlState.h> -CommandOps *controlCacheStore_Create(ControlState *state); -CommandOps *controlCacheStore_HelpCreate(ControlState *state); -#endif // Control_CacheStore_h diff --git a/hicn-light/src/hicn/config/controlList.c b/hicn-light/src/hicn/config/controlList.c deleted file mode 100644 index 353856c43..000000000 --- a/hicn-light/src/hicn/config/controlList.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/security/parc_Security.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlList.h> -#include <hicn/config/controlListConnections.h> -//#include <hicn/config/controlListInterfaces.h> -#include <hicn/config/controlListListeners.h> -#include <hicn/config/controlListRoutes.h> -#ifdef WITH_POLICY -#include <hicn/config/controlListPolicies.h> -#endif /* WITH_POLICY */ - -static void _controlList_Init(CommandParser *parser, CommandOps *ops); -static CommandReturn _controlList_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlList_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandList = "list"; -static const char *_commandListHelp = "help list"; - -CommandOps *controlList_Create(ControlState *state) { - return commandOps_Create(state, _commandList, _controlList_Init, - _controlList_Execute, commandOps_Destroy); -} - -CommandOps *controlList_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandListHelp, NULL, - _controlList_HelpExecute, commandOps_Destroy); -} - -// ===================================================== - -static CommandReturn _controlList_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - CommandOps *ops_list_connections = controlListConnections_HelpCreate(NULL); - // CommandOps *ops_list_interfaces = controlListInterfaces_HelpCreate(NULL); - CommandOps *ops_list_routes = controlListRoutes_HelpCreate(NULL); - CommandOps *ops_list_listeners = controlListListeners_HelpCreate(NULL); -#ifdef WITH_POLICY - CommandOps *ops_list_policies = controlListPolicies_HelpCreate(NULL); -#endif /* WITH_POLICY */ - - snprintf(output, output_size, "Available commands:\n" - " %s\n" - " %s\n" - " %s\n" -#ifdef WITH_POLICY - " %s\n" -#endif /* WITH_POLICY */ - "\n", - ops_list_connections->command, - ops_list_routes->command, - ops_list_listeners->command -#ifdef WITH_POLICY - , ops_list_policies->command -#endif /* WITH_POLICY */ - ); - - commandOps_Destroy(&ops_list_connections); - // commandOps_Destroy(&ops_list_interfaces); - commandOps_Destroy(&ops_list_routes); - commandOps_Destroy(&ops_list_listeners); -#ifdef WITH_POLICY - commandOps_Destroy(&ops_list_policies); -#endif /* WITH_POLICY */ - - return CommandReturn_Success; -} - -static void _controlList_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - controlState_RegisterCommand(state, controlListConnections_HelpCreate(state)); - // controlState_RegisterCommand(state, - // controlListInterfaces_HelpCreate(state)); - controlState_RegisterCommand(state, controlListListeners_HelpCreate(state)); - controlState_RegisterCommand(state, controlListRoutes_HelpCreate(state)); - controlState_RegisterCommand(state, controlListConnections_Create(state)); - // controlState_RegisterCommand(state, controlListInterfaces_Create(state)); - controlState_RegisterCommand(state, controlListRoutes_Create(state)); - controlState_RegisterCommand(state, controlListListeners_Create(state)); -#ifdef WITH_POLICY - controlState_RegisterCommand(state, controlListPolicies_HelpCreate(state)); - controlState_RegisterCommand(state, controlListPolicies_Create(state)); -#endif /* WITH_POLICY */ -} - -static CommandReturn _controlList_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlList_HelpExecute(parser, ops, args, output, output_size); -} - -// ====================================================================== diff --git a/hicn-light/src/hicn/config/controlList.h b/hicn-light/src/hicn/config/controlList.h deleted file mode 100644 index d497e5179..000000000 --- a/hicn-light/src/hicn/config/controlList.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_List.h - * @brief Root node for the "list" commands - * - * Implements the "list" node of the CLI tree. - * - */ - -#ifndef controlList_h -#define controlList_h - -#include <hicn/config/controlState.h> -CommandOps *controlList_Create(ControlState *state); -CommandOps *controlList_HelpCreate(ControlState *state); -#endif // controlList_h diff --git a/hicn-light/src/hicn/config/controlListConnections.c b/hicn-light/src/hicn/config/controlListConnections.c deleted file mode 100644 index 6406ba8c3..000000000 --- a/hicn-light/src/hicn/config/controlListConnections.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlListConnections.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlListConnections_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlListConnections_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandListConnections = "list connections"; -static const char *_commandListConnectionsHelp = "help list connections"; -const char *connTypeString[6] = {"GRE", "TCP", "UDP", "MCAST", "L2", "HICN"}; -const char *stateString[3] = {"UP", "DOWN", "UNKNOWN"}; - -CommandOps *controlListConnections_Create(ControlState *state) { - return commandOps_Create(state, _commandListConnections, NULL, - _controlListConnections_Execute, commandOps_Destroy); -} - -CommandOps *controlListConnections_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandListConnectionsHelp, NULL, - _controlListConnections_HelpExecute, - commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlListConnections_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { -snprintf(output, output_size, "%s", "list connections: displays a 1-line summary of each connection\n" - "\n" - "The columns are:\n" - " connection id : an integer index for the connection\n" - " state : UP or DOWN\n" - " local address : the local network address associated with the " - "connection\n" - " remote address: the remote network address associated with the " - "connection\n" - " protocol : the network protocol (tcp, udp, gre, mcast, " - "ether)\n" - "\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlListConnections_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 2) { - _controlListConnections_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } -#ifdef WITH_POLICY - char flags_str[POLICY_TAG_N+1]; - char *s; -#endif /* WITH_POLICY */ - - ControlState *state = ops->closure; - - // send message and receive response - struct iovec *response = utils_SendRequest(state, LIST_CONNECTIONS, NULL, 0); - if (!response) { // get NULL pointer = FAILURE - return CommandReturn_Failure; - } - - // Process/Print message - header_control_message *receivedHeader = - (header_control_message *)response[0].iov_base; - uint8_t *receivedPayload = (uint8_t *)response[1].iov_base; - - char *sourceString = NULL; - char *destinationString = NULL; - - // Allocate output to pass to the main function if the call is not interactive - char **commandOutputMain = NULL; - if (!controlState_IsInteractive(state) && receivedHeader->length > 0) { - commandOutputMain = - parcMemory_Allocate(sizeof(char *) * receivedHeader->length); - for (size_t j = 0; j < receivedHeader->length; j++) { - commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 256); - } - } -size_t output_offset = 0; - -#ifdef WITH_POLICY - output_offset = snprintf(output, output_size, "%5s %10s %12s %6s %40s %40s %5s %s %s\n", "id", "name", "admin_state", "state", "source", "destination", "type", "priority", "flags"); -#else - output_offset = snprintf(output, output_size, "%5s %10s %12s %6s %40s %40s %5s\n", "id", "name", "admin_state", "state", "source", "destination", "type"); -#endif /* WITH_POLICY */ - - // Process/Print payload - - for (int i = 0; i < receivedHeader->length; i++) { - list_connections_command *listConnectionsCommand = - (list_connections_command *)(receivedPayload + - (i * sizeof(list_connections_command))); - - sourceString = utils_CommandAddressToString( - listConnectionsCommand->connectionData.ipType, - &listConnectionsCommand->connectionData.localIp, - &listConnectionsCommand->connectionData.localPort); - - destinationString = utils_CommandAddressToString( - listConnectionsCommand->connectionData.ipType, - &listConnectionsCommand->connectionData.remoteIp, - &listConnectionsCommand->connectionData.remotePort); - - PARCBufferComposer *composer = parcBufferComposer_Create(); - -#ifdef WITH_POLICY - - s = flags_str; -#define _(x, y) *s++ = policy_tags_has(listConnectionsCommand->connectionData.tags, POLICY_TAG_ ## x) ? y : '.'; -foreach_policy_tag -#undef _ - *s = '\0'; - - parcBufferComposer_Format( - composer, "%5d %10s %12s %6s %40s %40s %5s [%6d] [%s]", listConnectionsCommand->connid, listConnectionsCommand->connectionName, - stateString[listConnectionsCommand->connectionData.admin_state], - stateString[listConnectionsCommand->state], sourceString, - destinationString, - connTypeString[listConnectionsCommand->connectionData.connectionType], - listConnectionsCommand->connectionData.priority, - flags_str); - -#else - parcBufferComposer_Format( - composer, "%5d %10s %12s %6s %40s %40s %5s", listConnectionsCommand->connid, listConnectionsCommand->connectionName, - stateString[listConnectionsCommand->admin_state], - stateString[listConnectionsCommand->state], sourceString, - destinationString, - connTypeString[listConnectionsCommand->connectionData.connectionType]); -#endif /* WITH_POLICY */ - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - - if (!controlState_IsInteractive(state)) { - strcpy(commandOutputMain[i], result); - } - output_offset += snprintf(output + output_offset, output_size - output_offset, "%s\n", result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); - } - - controlState_SetCommandOutput(state, commandOutputMain); - - // DEALLOCATE - parcMemory_Deallocate((void **)&sourceString); - parcMemory_Deallocate((void **)&destinationString); - parcMemory_Deallocate(&receivedHeader); // free response[0].iov_base - parcMemory_Deallocate(&receivedPayload); // free response[1].iov_base - parcMemory_Deallocate(&response); // free iovec pointer - - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlListConnections.h b/hicn-light/src/hicn/config/controlListConnections.h deleted file mode 100644 index cd5c21cec..000000000 --- a/hicn-light/src/hicn/config/controlListConnections.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_ListConnections.h - * @brief List the current connections of hicn-light - * - * Implements the "list connections" node of the CLI tree - * - */ - -#ifndef Control_ListConnections_h -#define Control_ListConnections_h - -#include <hicn/config/controlState.h> -CommandOps *controlListConnections_Create(ControlState *state); -CommandOps *controlListConnections_HelpCreate(ControlState *state); -#endif // Control_ListConnections_h diff --git a/hicn-light/src/hicn/config/controlListInterfaces.c b/hicn-light/src/hicn/config/controlListInterfaces.c deleted file mode 100644 index c632a1d21..000000000 --- a/hicn-light/src/hicn/config/controlListInterfaces.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlListInterfaces.h> - -static CommandReturn _controlListInterfaces_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlListInterfaces_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandListInterfaces = "list interfaces"; -static const char *_commandListInterfacesHelp = "help list interfaces"; - -// ==================================================== - -CommandOps *controlListInterfaces_Create(ControlState *state) { - return commandOps_Create(state, _commandListInterfaces, NULL, - _controlListInterfaces_Execute, commandOps_Destroy); -} - -CommandOps *controlListInterfaces_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandListInterfacesHelp, NULL, - _controlListInterfaces_HelpExecute, - commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlListInterfaces_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "list interfaces\n\n") - return CommandReturn_Success; -} - -static CommandReturn _controlListInterfaces_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 2) { - _controlListInterfaces_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - //========================== NOT IMPLEMENTED - //=========================== - - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlListInterfaces.h b/hicn-light/src/hicn/config/controlListInterfaces.h deleted file mode 100644 index f885835ed..000000000 --- a/hicn-light/src/hicn/config/controlListInterfaces.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_ListInterfaces.h - * @brief List the icn-light interfaces - * - * Implements the "list interfaces" and "help list interfaces" nodes of the - * command tree - * - */ - -#ifndef Control_ListInterfaces_h -#define Control_ListInterfaces_h - -#include <hicn/config/controlState.h> -CommandOps *controlListInterfaces_Create(ControlState *state); -CommandOps *controlListInterfaces_HelpCreate(ControlState *state); -#endif // Control_ListInterfaces_h diff --git a/hicn-light/src/hicn/config/controlListListeners.c b/hicn-light/src/hicn/config/controlListListeners.c deleted file mode 100644 index c189dfc36..000000000 --- a/hicn-light/src/hicn/config/controlListListeners.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> - -#include <hicn/config/controlListListeners.h> -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlListListeners_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlListListeners_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandListListeners = "list listeners"; -static const char *_commandListListenersHelp = "help list listeners"; -static const char *listenerType[5] = {"TCP", "UDP", "ETHER", "LOCAL", "HICN"}; - -// ==================================================== - -CommandOps *controlListListeners_Create(ControlState *state) { - return commandOps_Create(state, _commandListListeners, NULL, - _controlListListeners_Execute, commandOps_Destroy); -} - -CommandOps *controlListListeners_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandListListenersHelp, NULL, - _controlListListeners_HelpExecute, - commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlListListeners_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "list listeners\n\n"); - - return CommandReturn_Success; -} - -static CommandReturn _controlListListeners_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 2) { - _controlListListeners_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - ControlState *state = ops->closure; - - // send message and receive response - struct iovec *response = utils_SendRequest(state, LIST_LISTENERS, NULL, 0); - if (!response) { // get NULL pointer = FAILURE - return CommandReturn_Failure; - } - - // Process/Print message - header_control_message *receivedHeader = - (header_control_message *)response[0].iov_base; - uint8_t *receivedPayload = (uint8_t *)response[1].iov_base; - - // Allocate output to pass to the main function if the call is not interactive - char **commandOutputMain = NULL; - if (!controlState_IsInteractive(state) && receivedHeader->length > 0) { - commandOutputMain = - parcMemory_Allocate(sizeof(char *) * receivedHeader->length); - for (size_t j = 0; j < receivedHeader->length; j++) { - commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128); - } - } - - char *addrString = NULL; - size_t output_offset = 0; - if (receivedHeader->length > 0) { - output_offset = snprintf(output, output_size, "%6.6s %.*s %50.70s %6s %10s\n", "iface", SYMBOLIC_NAME_LEN, "name", "address", "type", "interface"); - - } else { - output_offset = snprintf(output, output_size, " --- No entry in the list \n"); - } - - for (int i = 0; i < receivedHeader->length; i++) { - list_listeners_command *listListenersCommand = - (list_listeners_command *)(receivedPayload + - (i * sizeof(list_listeners_command))); - - addrString = utils_CommandAddressToString(listListenersCommand->addressType, - &listListenersCommand->address, - &listListenersCommand->port); - - PARCBufferComposer *composer = parcBufferComposer_Create(); - - if (strcmp(listenerType[listListenersCommand->encapType], "UDP") == 0 || - strcmp(listenerType[listListenersCommand->encapType], "TCP") == 0) { - parcBufferComposer_Format(composer, "%6u %.*s %50.70s %6s %10s", - listListenersCommand->connid, - SYMBOLIC_NAME_LEN, listListenersCommand->listenerName, - addrString, - listenerType[listListenersCommand->encapType], - listListenersCommand->interfaceName); - } else { - parcBufferComposer_Format(composer, "%6u %.*s %50.70s %6s", - listListenersCommand->connid, - SYMBOLIC_NAME_LEN, listListenersCommand->listenerName, - addrString, - listenerType[listListenersCommand->encapType]); - } - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - - if (!controlState_IsInteractive(state)) { - strncpy(commandOutputMain[i], result, 128); - } - output_offset += snprintf(output + output_offset, output_size - output_offset, "%s\n", result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); - } - - controlState_SetCommandOutput(state, commandOutputMain); - - // DEALLOCATE - parcMemory_Deallocate((void **)&addrString); - parcMemory_Deallocate(&receivedHeader); // free response[0].iov_base - parcMemory_Deallocate(&receivedPayload); // free response[1].iov_base - parcMemory_Deallocate(&response); // free iovec pointer - - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlListListeners.h b/hicn-light/src/hicn/config/controlListListeners.h deleted file mode 100644 index 11ec07579..000000000 --- a/hicn-light/src/hicn/config/controlListListeners.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_ListListeners.h - * @brief List the icn-light listeners - * - * Implements the "list listeners" and "help list listeners" nodes of the - * command tree - * - */ - -#ifndef Control_ListListeners_h -#define Control_ListListeners_h - -#include <hicn/config/controlState.h> -CommandOps *controlListListeners_Create(ControlState *state); -CommandOps *controlListListeners_HelpCreate(ControlState *state); -#endif // Control_ListListeners_h diff --git a/hicn-light/src/hicn/config/controlListPolicies.c b/hicn-light/src/hicn/config/controlListPolicies.c deleted file mode 100644 index 8eae6453b..000000000 --- a/hicn-light/src/hicn/config/controlListPolicies.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#ifdef WITH_POLICY -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Time.h> - -#include <hicn/config/controlListPolicies.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlListPolicies_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlListPolicies_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandListPolicies = "list policies"; -static const char *_commandListPoliciesHelp = "help list policies"; - -// ==================================================== - -CommandOps *controlListPolicies_Create(ControlState *state) { - return commandOps_Create(state, _commandListPolicies, NULL, - _controlListPolicies_Execute, commandOps_Destroy); -} - -CommandOps *controlListPolicies_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandListPoliciesHelp, NULL, - _controlListPolicies_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlListPolicies_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "command: list policies\n\n"); - return CommandReturn_Success; -} - -#define MAX(x,y) (x > y ? x : y) -#define MAXSZ_COLUMN MAX(MAXSZ_POLICY_TAG, MAXSZ_POLICY_TAG_STATE) - -#define MAXSZ_STR_STAT 10 -#define MAXSZ_APP_NAME 25 - -typedef struct { - #define _(x, y) char x[MAXSZ_POLICY_TAG_STATE]; - foreach_policy_tag - #undef _ -} tag_state_str_t; - -static CommandReturn _controlListPolicies_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 2) { - _controlListPolicies_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - ControlState *state = ops->closure; - - // send message and receive response - struct iovec *response = utils_SendRequest(state, LIST_POLICIES, NULL, 0); - if (!response) { // get NULL pointer = FAILURE - return CommandReturn_Failure; - } - - // Process/Print message - header_control_message *receivedHeader = - (header_control_message *)response[0].iov_base; - uint8_t *receivedPayload = (uint8_t *)response[1].iov_base; - if (!receivedPayload) { - snprintf(output, output_size, "No payload!\n"); - return CommandReturn_Failure; - } - - // Allocate output to pass to the main function if the call is not interactive - char **commandOutputMain = NULL; - if (!controlState_IsInteractive(state) && receivedHeader->length > 0) { - commandOutputMain = - parcMemory_Allocate(sizeof(char *) * receivedHeader->length); - for (size_t j = 0; j < receivedHeader->length; j++) { - commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128); - } - } - - char *addrString = NULL; - in_port_t port = htons(1234); // this is a random port number that is ignored - size_t output_offset = 0; - if (receivedHeader->length > 0) { - output_offset += snprintf(output, output_size, "%*s %*s", MAXSZ_PREFIX, "prefix", MAXSZ_APP_NAME /*APP_NAME_LEN*/, "app_name"); - #define _(x, y) output_offset += snprintf(output + output_offset, output_size - output_offset, " %*s",MAXSZ_COLUMN, policy_tag_str[POLICY_TAG_ ## x]); - foreach_policy_tag - #undef _ - output_offset += snprintf(output + output_offset, output_size - output_offset, "\n"); - } else { - output_offset += snprintf(output, output_size, " --- No entry in the list \n"); - } - - tag_state_str_t str; - - for (int i = 0; i < receivedHeader->length; i++) { - list_policies_command *listPoliciesCommand = - (list_policies_command *)(receivedPayload + - (i * sizeof(list_policies_command))); - -#if 0 - char tag_s[MAXSZ_POLICY_TAG_STATE * POLICY_TAG_N]; - - policy_tag_state_snprintf((char*)&tag_s[MAXSZ_POLICY_TAG_STATE * POLICY_TAG_ ## x], \ - MAXSZ_POLICY_TAG_STATE, \ - &listPoliciesCommand->policy.tags[POLICY_TAG_ ## x]); -#endif - - #define _(x, y) policy_tag_state_snprintf(str.x, MAXSZ_POLICY_TAG_STATE, &listPoliciesCommand->policy.tags[POLICY_TAG_ ## x]); - foreach_policy_tag - #undef _ - - addrString = utils_CommandAddressToString( - listPoliciesCommand->addressType, &listPoliciesCommand->address, &port); - -#if 0 - PARCBufferComposer *composer = parcBufferComposer_Create(); - - parcBufferComposer_Format( - composer, "%*s %*s" - #define _(x, y) " %*s" - foreach_policy_tag - #undef _ - "%s", - MAXSZ_PREFIX, addrString, APP_NAME_LEN, listPoliciesCommand->policy.app_name, - #define _(x, y) MAXSZ_COLUMN, str.x, - foreach_policy_tag - #undef _ - ""); - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - - if (!controlState_IsInteractive(state)) { - strcpy(commandOutputMain[i], result); - } - - puts(result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); -#else - - output_offset = snprintf(output + output_offset, output_size - output_offset, "%*s %*s", - MAXSZ_PREFIX, addrString, MAXSZ_APP_NAME /*APP_NAME_LEN*/, listPoliciesCommand->policy.app_name); - #define _(x, y) output_offset += snprintf(output + output_offset, output_size - output_offset, " %*s", MAXSZ_COLUMN, str.x); - foreach_policy_tag - #undef _ - - output_offset = snprintf(output + output_offset, output_size - output_offset, "\n"); - - - /*printf("%*s %*s" - #define _(x, y) " %*s" - foreach_policy_tag - #undef _ - "%s\n", - MAXSZ_PREFIX, addrString, MAXSZ_APP_NAME *//*APP_NAME_LEN*//*, listPoliciesCommand->policy.app_name, - #define _(x, y) MAXSZ_COLUMN, str.x, - foreach_policy_tag - #undef _ - "");*/ - -#endif - } - - output_offset += snprintf(output + output_offset, output_size - output_offset, "\nSTATISTICS\n\n"); - // STATISTICS - output_offset += snprintf(output + output_offset, output_size - output_offset, "%*s %*s %*s | %*s | %*s | %*s\n", - MAXSZ_PREFIX, "", MAXSZ_APP_NAME /*APP_NAME_LEN*/, "", - 3*MAXSZ_STR_STAT+2, "WIRED", 3*MAXSZ_STR_STAT+2, "WIFI", 3*MAXSZ_STR_STAT+2, "CELLULAR", 3*MAXSZ_STR_STAT+2, "ALL"); - output_offset += snprintf(output + output_offset, output_size - output_offset, "%*s %*s %*s %*s %*s | %*s %*s %*s | %*s %*s %*s | %*s %*s %*s\n", - MAXSZ_PREFIX, "prefix", MAXSZ_APP_NAME /*APP_NAME_LEN*/, "app_name", - MAXSZ_STR_STAT, "throughput", MAXSZ_STR_STAT, "latency", MAXSZ_STR_STAT, "loss_rate", - MAXSZ_STR_STAT, "throughput", MAXSZ_STR_STAT, "latency", MAXSZ_STR_STAT, "loss_rate", - MAXSZ_STR_STAT, "throughput", MAXSZ_STR_STAT, "latency", MAXSZ_STR_STAT, "loss_rate", - MAXSZ_STR_STAT, "throughput", MAXSZ_STR_STAT, "latency", MAXSZ_STR_STAT, "loss_rate"); - for (int i = 0; i < receivedHeader->length; i++) { - list_policies_command *listPoliciesCommand = - (list_policies_command *)(receivedPayload + - (i * sizeof(list_policies_command))); - addrString = utils_CommandAddressToString( - listPoliciesCommand->addressType, &listPoliciesCommand->address, &port); - output_offset += snprintf(output + output_offset, output_size - output_offset, "%*s %*s %*.2f %*.2f %*.2f | %*.2f %*.2f %*.2f | %*.2f %*.2f %*.2f | %*.2f %*.2f %*.2f\n", - MAXSZ_PREFIX, addrString, MAXSZ_APP_NAME, listPoliciesCommand->policy.app_name, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.wired.throughput, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.wired.latency, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.wired.loss_rate, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.wifi.throughput, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.wifi.latency, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.wifi.loss_rate, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.cellular.throughput, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.cellular.latency, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.cellular.loss_rate, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.all.throughput, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.all.latency, - MAXSZ_STR_STAT, listPoliciesCommand->policy.stats.all.loss_rate); - } - - controlState_SetCommandOutput(state, commandOutputMain); - - // DEALLOCATE - parcMemory_Deallocate((void **)&addrString); - parcMemory_Deallocate(&receivedHeader); // free response[0].iov_base - parcMemory_Deallocate(&receivedPayload); // free response[1].iov_base - parcMemory_Deallocate(&response); // free iovec pointer - - return CommandReturn_Success; -} - -#endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/config/controlListPolicies.h b/hicn-light/src/hicn/config/controlListPolicies.h deleted file mode 100644 index 7aa0bdd26..000000000 --- a/hicn-light/src/hicn/config/controlListPolicies.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_ListPolicies.h - * @brief List the icn-light policies - * - * Implements the "list policies" and "help list policies" nodes of the command tree - * - */ -#ifndef Control_ListPolicies_h -#define Control_ListPolicies_h - -#ifdef WITH_POLICY - -#include <hicn/config/controlState.h> -CommandOps *controlListPolicies_Create(ControlState *state); -CommandOps *controlListPolicies_HelpCreate(ControlState *state); - -#endif /* WITH_POLICY */ - -#endif // Control_ListPolicies_h diff --git a/hicn-light/src/hicn/config/controlListRoutes.c b/hicn-light/src/hicn/config/controlListRoutes.c deleted file mode 100644 index 395251b94..000000000 --- a/hicn-light/src/hicn/config/controlListRoutes.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Time.h> - -#include <hicn/config/controlListRoutes.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlListRoutes_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlListRoutes_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandListRoutes = "list routes"; -static const char *_commandListRoutesHelp = "help list routes"; - -// ==================================================== - -CommandOps *controlListRoutes_Create(ControlState *state) { - return commandOps_Create(state, _commandListRoutes, NULL, - _controlListRoutes_Execute, commandOps_Destroy); -} - -CommandOps *controlListRoutes_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandListRoutesHelp, NULL, - _controlListRoutes_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlListRoutes_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "command: list routes\n" - "\n" - "This command will fetch the prefix routing table. For each route, it " - "will list:\n" - " iface: interface\n" - " protocol: the routing protocol, such as STATIC, CONNECTED, etc.\n" - " type: LMP or EXACT (longest matching prefix or exact match)\n" - " cost: The route cost, lower being preferred\n" - " next: List of next hops by interface id\n" - " prefix: name prefix\n" - "\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlListRoutes_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 2) { - _controlListRoutes_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - ControlState *state = ops->closure; - - // send message and receive response - struct iovec *response = utils_SendRequest(state, LIST_ROUTES, NULL, 0); - if (!response) { // get NULL pointer = FAILURE - return CommandReturn_Failure; - } - - // Process/Print message - header_control_message *receivedHeader = - (header_control_message *)response[0].iov_base; - uint8_t *receivedPayload = (uint8_t *)response[1].iov_base; - - // Allocate output to pass to the main function if the call is not interactive - char **commandOutputMain = NULL; - if (!controlState_IsInteractive(state) && receivedHeader->length > 0) { - commandOutputMain = - parcMemory_Allocate(sizeof(char *) * receivedHeader->length); - for (size_t j = 0; j < receivedHeader->length; j++) { - commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128); - } - } - - char *addrString = NULL; - in_port_t port = htons(1234); // this is a random port number that is ignored - size_t output_offset = 0; - if (receivedHeader->length > 0) { - output_offset = snprintf(output, output_size, "%6.6s %8.8s %70.70s %s\n", "iface", "cost", "prefix", "len"); - } else { - output_offset = snprintf(output, output_size, " --- No entry in the list \n"); - } - - for (int i = 0; i < receivedHeader->length; i++) { - list_routes_command *listRoutesCommand = - (list_routes_command *)(receivedPayload + - (i * sizeof(list_routes_command))); - - addrString = utils_CommandAddressToString( - listRoutesCommand->addressType, &listRoutesCommand->address, &port); - - PARCBufferComposer *composer = parcBufferComposer_Create(); - - parcBufferComposer_Format( - composer, "%6u %8u %70.70s %3d", listRoutesCommand->connid, - listRoutesCommand->cost, addrString, listRoutesCommand->len); - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - - if (!controlState_IsInteractive(state)) { - strcpy(commandOutputMain[i], result); - } - - output_offset += snprintf(output + output_offset, output_size - output_offset, "%s\n", result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); - } - - controlState_SetCommandOutput(state, commandOutputMain); - - // DEALLOCATE - parcMemory_Deallocate((void **)&addrString); - parcMemory_Deallocate(&receivedHeader); // free response[0].iov_base - parcMemory_Deallocate(&receivedPayload); // free response[1].iov_base - parcMemory_Deallocate(&response); // free iovec pointer - - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlListRoutes.h b/hicn-light/src/hicn/config/controlListRoutes.h deleted file mode 100644 index 341552add..000000000 --- a/hicn-light/src/hicn/config/controlListRoutes.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_ListRoutes.h - * @brief List the icn-light routes - * - * Implements the "list routes" and "help list routes" nodes of the command tree - * - */ -#ifndef Control_ListRoutes_h -#define Control_ListRoutes_h - -#include <hicn/config/controlState.h> -CommandOps *controlListRoutes_Create(ControlState *state); -CommandOps *controlListRoutes_HelpCreate(ControlState *state); -#endif // Control_ListRoutes_h diff --git a/hicn-light/src/hicn/config/controlMapMe.c b/hicn-light/src/hicn/config/controlMapMe.c deleted file mode 100644 index b292ee0f0..000000000 --- a/hicn-light/src/hicn/config/controlMapMe.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> - -#include <hicn/config/controlMapMe.h> -#include <hicn/config/controlMapMeDiscovery.h> -#include <hicn/config/controlMapMeEnable.h> -#include <hicn/config/controlMapMeRetx.h> -#include <hicn/config/controlMapMeTimescale.h> - -static void _controlMapMe_Init(CommandParser *parser, CommandOps *ops); -static CommandReturn _controlMapMe_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlMapMe_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandMapMe = "mapme"; -static const char *_commandMapMeHelp = "help mapme"; - -CommandOps *controlMapMe_Create(ControlState *state) { - return commandOps_Create(state, _commandMapMe, _controlMapMe_Init, - _controlMapMe_Execute, commandOps_Destroy); -} - -CommandOps *controlMapMe_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandMapMeHelp, NULL, - _controlMapMe_HelpExecute, commandOps_Destroy); -} - -// ===================================================== - -static CommandReturn _controlMapMe_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - CommandOps *ops_mapme_enable = controlMapMeEnable_HelpCreate(NULL); - CommandOps *ops_mapme_discovery = controlMapMeDiscovery_HelpCreate(NULL); - CommandOps *ops_mapme_timescale = controlMapMeTimescale_HelpCreate(NULL); - CommandOps *ops_mapme_retx = controlMapMeRetx_HelpCreate(NULL); - - snprintf(output, output_size, "Available commands:\n" - " %s\n %s\n %s\n %s\n\n", - ops_mapme_enable->command, - ops_mapme_discovery->command, - ops_mapme_timescale->command, - ops_mapme_retx->command); - - commandOps_Destroy(&ops_mapme_enable); - commandOps_Destroy(&ops_mapme_discovery); - commandOps_Destroy(&ops_mapme_timescale); - commandOps_Destroy(&ops_mapme_retx); - - return CommandReturn_Success; -} - -static void _controlMapMe_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - controlState_RegisterCommand(state, controlMapMeEnable_HelpCreate(state)); - controlState_RegisterCommand(state, controlMapMeDiscovery_HelpCreate(state)); - controlState_RegisterCommand(state, controlMapMeTimescale_HelpCreate(state)); - controlState_RegisterCommand(state, controlMapMeRetx_HelpCreate(state)); - controlState_RegisterCommand(state, controlMapMeEnable_Create(state)); - controlState_RegisterCommand(state, controlMapMeDiscovery_Create(state)); - controlState_RegisterCommand(state, controlMapMeTimescale_Create(state)); - controlState_RegisterCommand(state, controlMapMeRetx_Create(state)); -} - -static CommandReturn _controlMapMe_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlMapMe_HelpExecute(parser, ops, args, output, output_size); -} - -// ====================================================================== diff --git a/hicn-light/src/hicn/config/controlMapMe.h b/hicn-light/src/hicn/config/controlMapMe.h deleted file mode 100644 index 3edd78989..000000000 --- a/hicn-light/src/hicn/config/controlMapMe.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 controlMapMe_h -#define controlMapMe_h - -#include <hicn/config/controlState.h> -CommandOps *controlMapMe_Create(ControlState *state); -CommandOps *controlMapMe_HelpCreate(ControlState *state); -#endif // controlMapMe_h diff --git a/hicn-light/src/hicn/config/controlMapMeDiscovery.c b/hicn-light/src/hicn/config/controlMapMeDiscovery.c deleted file mode 100644 index 6ec941141..000000000 --- a/hicn-light/src/hicn/config/controlMapMeDiscovery.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/config/controlMapMeDiscovery.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlMapMeDiscovery_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlMapMeDiscovery_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandMapMeDiscovery = "mapme discovery"; -static const char *_commandMapMeDiscoveryHelp = "help mapme discovery"; - -// ==================================================== - -CommandOps *controlMapMeDiscovery_Create(ControlState *state) { - return commandOps_Create(state, _commandMapMeDiscovery, NULL, - _controlMapMeDiscovery_Execute, commandOps_Destroy); -} - -CommandOps *controlMapMeDiscovery_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandMapMeDiscoveryHelp, NULL, - _controlMapMeDiscovery_HelpExecute, - commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlMapMeDiscovery_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "mapme discovery [on|off]\n\n"); - - return CommandReturn_Success; -} - -static CommandReturn _controlMapMeDiscovery_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 3) { - _controlMapMeDiscovery_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - bool active; - if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) { - active = true; - } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) { - active = false; - } else { - _controlMapMeDiscovery_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - mapme_activator_command *mapmeDiscoveryCommand = - parcMemory_AllocateAndClear(sizeof(mapme_activator_command)); - if (active) { - mapmeDiscoveryCommand->activate = ACTIVATE_ON; - } else { - mapmeDiscoveryCommand->activate = ACTIVATE_OFF; - } - - ControlState *state = ops->closure; - // send message and receive response - struct iovec *response = - utils_SendRequest(state, MAPME_DISCOVERY, mapmeDiscoveryCommand, - sizeof(mapme_activator_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlMapMeDiscovery.h b/hicn-light/src/hicn/config/controlMapMeDiscovery.h deleted file mode 100644 index c2832632a..000000000 --- a/hicn-light/src/hicn/config/controlMapMeDiscovery.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 Control_MapMeDiscovery_h -#define Control_MapMeDiscovery_h - -#include <hicn/config/controlState.h> -CommandOps *controlMapMeDiscovery_Create(ControlState *state); -CommandOps *controlMapMeDiscovery_HelpCreate(ControlState *state); -#endif // Control_MapMeDiscovery_h diff --git a/hicn-light/src/hicn/config/controlMapMeEnable.c b/hicn-light/src/hicn/config/controlMapMeEnable.c deleted file mode 100644 index 0595cc346..000000000 --- a/hicn-light/src/hicn/config/controlMapMeEnable.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/config/controlMapMeEnable.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlMapMeEnable_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlMapMeEnable_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandMapMeEnable = "mapme enable"; -static const char *_commandMapMeEnableHelp = "help mapme enable"; - -// ==================================================== - -CommandOps *controlMapMeEnable_Create(ControlState *state) { - return commandOps_Create(state, _commandMapMeEnable, NULL, - _controlMapMeEnable_Execute, commandOps_Destroy); -} - -CommandOps *controlMapMeEnable_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandMapMeEnableHelp, NULL, - _controlMapMeEnable_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlMapMeEnable_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "mapme enable [on|off]\n\n"); - - return CommandReturn_Success; -} - -static CommandReturn _controlMapMeEnable_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 3) { - _controlMapMeEnable_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - bool active; - if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) { - active = true; - } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) { - active = false; - } else { - _controlMapMeEnable_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - mapme_activator_command *mapmeEnableCommand = - parcMemory_AllocateAndClear(sizeof(mapme_activator_command)); - if (active) { - mapmeEnableCommand->activate = ACTIVATE_ON; - } else { - mapmeEnableCommand->activate = ACTIVATE_OFF; - } - - ControlState *state = ops->closure; - // send message and receive response - struct iovec *response = utils_SendRequest( - state, MAPME_ENABLE, mapmeEnableCommand, sizeof(mapme_activator_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlMapMeEnable.h b/hicn-light/src/hicn/config/controlMapMeEnable.h deleted file mode 100644 index 0ce4970f3..000000000 --- a/hicn-light/src/hicn/config/controlMapMeEnable.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 Control_MapMeEnable_h -#define Control_MapMeEnable_h - -#include <hicn/config/controlState.h> -CommandOps *controlMapMeEnable_Create(ControlState *state); -CommandOps *controlMapMeEnable_HelpCreate(ControlState *state); -#endif // Control_MapMeEnable_h diff --git a/hicn-light/src/hicn/config/controlMapMeRetx.c b/hicn-light/src/hicn/config/controlMapMeRetx.c deleted file mode 100644 index 9f37ca6f5..000000000 --- a/hicn-light/src/hicn/config/controlMapMeRetx.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/config/controlMapMeRetx.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlMapMeRetx_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlMapMeRetx_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandMapMeRetx = "mapme retx"; -static const char *_commandMapMeRetxHelp = "help mapme retx"; - -// ==================================================== - -CommandOps *controlMapMeRetx_Create(ControlState *state) { - return commandOps_Create(state, _commandMapMeRetx, NULL, - _controlMapMeRetx_Execute, commandOps_Destroy); -} - -CommandOps *controlMapMeRetx_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandMapMeRetxHelp, NULL, - _controlMapMeRetx_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlMapMeRetx_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "mapme retx <milliseconds>\n\n"); - - return CommandReturn_Success; -} - -static CommandReturn _controlMapMeRetx_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 3) { - _controlMapMeRetx_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *rtx = parcList_GetAtIndex(args, 2); - if (!utils_IsNumber(rtx)) { - snprintf(output, output_size, - "ERROR: retransmission value (expressed in ms) must be a positive " - "integer \n"); - return CommandReturn_Failure; - } - - mapme_timing_command *mapmeRetxCommand = - parcMemory_AllocateAndClear(sizeof(mapme_timing_command)); - mapmeRetxCommand->timePeriod = (unsigned)strtold(rtx, NULL); - - ControlState *state = ops->closure; - // send message and receive response - struct iovec *response = utils_SendRequest( - state, MAPME_RETX, mapmeRetxCommand, sizeof(mapme_timing_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlMapMeRetx.h b/hicn-light/src/hicn/config/controlMapMeRetx.h deleted file mode 100644 index 3e3b2de15..000000000 --- a/hicn-light/src/hicn/config/controlMapMeRetx.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 Control_MapMeRetx_h -#define Control_MapMeRetx_h - -#include <hicn/config/controlState.h> -CommandOps *controlMapMeRetx_Create(ControlState *state); -CommandOps *controlMapMeRetx_HelpCreate(ControlState *state); -#endif // Control_MapMeRetx_h diff --git a/hicn-light/src/hicn/config/controlMapMeTimescale.c b/hicn-light/src/hicn/config/controlMapMeTimescale.c deleted file mode 100644 index 51701aa2f..000000000 --- a/hicn-light/src/hicn/config/controlMapMeTimescale.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/config/controlMapMeTimescale.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlMapMeTimescale_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlMapMeTimescale_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandMapMeTimescale = "mapme timescale"; -static const char *_commandMapMeTimescaleHelp = "help mapme timescale"; - -// ==================================================== - -CommandOps *controlMapMeTimescale_Create(ControlState *state) { - return commandOps_Create(state, _commandMapMeTimescale, NULL, - _controlMapMeTimescale_Execute, commandOps_Destroy); -} - -CommandOps *controlMapMeTimescale_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandMapMeTimescaleHelp, NULL, - _controlMapMeTimescale_HelpExecute, - commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlMapMeTimescale_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "mapme timescale <milliseconds>\n\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlMapMeTimescale_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 3) { - _controlMapMeTimescale_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *ts = parcList_GetAtIndex(args, 2); - if (!utils_IsNumber(ts)) { - snprintf(output, output_size, - "ERROR: timescale value (expressed in ms) must be a positive integer " - "\n"); - return CommandReturn_Failure; - } - - mapme_timing_command *mapmeTimescaleCommand = - parcMemory_AllocateAndClear(sizeof(mapme_timing_command)); - mapmeTimescaleCommand->timePeriod = (unsigned)strtold(ts, NULL); - - ControlState *state = ops->closure; - // send message and receive response - struct iovec *response = - utils_SendRequest(state, MAPME_TIMESCALE, mapmeTimescaleCommand, - sizeof(mapme_timing_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlMapMeTimescale.h b/hicn-light/src/hicn/config/controlMapMeTimescale.h deleted file mode 100644 index 947d00a5d..000000000 --- a/hicn-light/src/hicn/config/controlMapMeTimescale.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 Control_MapMeTimescale_h -#define Control_MapMeTimescale_h - -#include <hicn/config/controlState.h> -CommandOps *controlMapMeTimescale_Create(ControlState *state); -CommandOps *controlMapMeTimescale_HelpCreate(ControlState *state); -#endif // Control_MapMeTimescale_h diff --git a/hicn-light/src/hicn/config/controlQuit.c b/hicn-light/src/hicn/config/controlQuit.c deleted file mode 100644 index 621880d13..000000000 --- a/hicn-light/src/hicn/config/controlQuit.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/security/parc_Security.h> - -#include <hicn/config/controlQuit.h> - -static CommandReturn _controlQuit_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlQuit_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandQuit = "quit"; -static const char *_commandQuitHelp = "help quit"; - -// ==================================================== - -CommandOps *controlQuit_Create(ControlState *state) { - return commandOps_Create(state, _commandQuit, NULL, _controlQuit_Execute, - commandOps_Destroy); -} - -CommandOps *controlQuit_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandQuitHelp, NULL, - _controlQuit_HelpExecute, commandOps_Destroy); -} - -// ============================================== - -static CommandReturn _controlQuit_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "Exits the interactive control program\n\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlQuit_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "exiting interactive shell\n"); - return CommandReturn_Exit; -} diff --git a/hicn-light/src/hicn/config/controlQuit.h b/hicn-light/src/hicn/config/controlQuit.h deleted file mode 100644 index b45d5e215..000000000 --- a/hicn-light/src/hicn/config/controlQuit.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_Quit.h - * @brief The quit command - * - * Implements the "quit" and "help quit" nodes of the command tree - * - */ -#ifndef Control_Quit_h -#define Control_Quit_h - -#include <hicn/config/controlState.h> -CommandOps *controlQuit_Create(ControlState *state); -CommandOps *controlQuit_HelpCreate(ControlState *state); -#endif // Control_Quit_h diff --git a/hicn-light/src/hicn/config/controlRemove.c b/hicn-light/src/hicn/config/controlRemove.c deleted file mode 100644 index b1a88b5c1..000000000 --- a/hicn-light/src/hicn/config/controlRemove.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/security/parc_Security.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlRemove.h> -#include <hicn/config/controlRemoveListener.h> -#include <hicn/config/controlRemoveConnection.h> -#include <hicn/config/controlRemovePunting.h> -#include <hicn/config/controlRemoveRoute.h> -#ifdef WITH_POLICY -#include <hicn/config/controlRemovePolicy.h> -#endif /* WITH_POLICY */ - -static void _controlRemove_Init(CommandParser *parser, CommandOps *ops); -static CommandReturn _controlRemove_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlRemove_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandRemove = "remove"; -static const char *_commandRemoveHelp = "help remove"; - -// ==================================================== - -CommandOps *controlRemove_Create(ControlState *state) { - return commandOps_Create(state, _commandRemove, _controlRemove_Init, - _controlRemove_Execute, commandOps_Destroy); -} - -CommandOps *controlRemove_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandRemoveHelp, NULL, - _controlRemove_HelpExecute, commandOps_Destroy); -} - -// ============================================== - -static CommandReturn _controlRemove_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - CommandOps *ops_remove_connection = controlRemoveConnection_Create(NULL); - CommandOps *ops_remove_listener = controlRemoveListener_Create(NULL); - CommandOps *ops_remove_route = controlRemoveRoute_Create(NULL); - CommandOps *ops_remove_punting = controlRemovePunting_Create(NULL); -#ifdef WITH_POLICY - CommandOps *ops_remove_policy = controlRemovePolicy_Create(NULL); -#endif /* WITH_POLICY */ - - snprintf(output, output_size, "Available commands:\n" - " %s\n" - " %s\n" - " %s\n" - " %s\n" -#ifdef WITH_POLICY - " %s\n" -#endif /* WITH_POLICY */ - "\n", - ops_remove_connection->command, - ops_remove_listener->command, - ops_remove_route->command, - ops_remove_punting->command -#ifdef WITH_POLICY - , ops_remove_policy->command -#endif /* WITH_POLICY */ - ); - - commandOps_Destroy(&ops_remove_connection); - commandOps_Destroy(&ops_remove_listener); - commandOps_Destroy(&ops_remove_route); - commandOps_Destroy(&ops_remove_punting); -#ifdef WITH_POLICY - commandOps_Destroy(&ops_remove_policy); -#endif /* WITH_POLICY */ - return CommandReturn_Success; -} - -static void _controlRemove_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - controlState_RegisterCommand(state, - controlRemoveConnection_HelpCreate(state)); - controlState_RegisterCommand(state, - controlRemoveListener_HelpCreate(state)); - controlState_RegisterCommand(state, controlRemoveRoute_HelpCreate(state)); - controlState_RegisterCommand(state, controlRemoveConnection_Create(state)); - controlState_RegisterCommand(state, controlRemoveListener_Create(state)); - controlState_RegisterCommand(state, controlRemoveRoute_Create(state)); - controlState_RegisterCommand(state, controlRemovePunting_Create(state)); - controlState_RegisterCommand(state, controlRemovePunting_HelpCreate(state)); -#ifdef WITH_POLICY - controlState_RegisterCommand(state, controlRemovePolicy_HelpCreate(state)); - controlState_RegisterCommand(state, controlRemovePolicy_Create(state)); -#endif /* WITH_POLICY */ -} - -static CommandReturn _controlRemove_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlRemove_HelpExecute(parser, ops, args, output, output_size); -} diff --git a/hicn-light/src/hicn/config/controlRemove.h b/hicn-light/src/hicn/config/controlRemove.h deleted file mode 100644 index 863555728..000000000 --- a/hicn-light/src/hicn/config/controlRemove.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_Remove.h - * @brief Implements the remove node of the CLI tree - * - * Implements the "remove" and "help remove" nodes of the command tree - * - */ -#ifndef controlRemove_h -#define controlRemove_h - -#include <hicn/config/controlState.h> -CommandOps *controlRemove_Create(ControlState *state); -CommandOps *controlRemove_HelpCreate(ControlState *state); -#endif // controlRemove_h diff --git a/hicn-light/src/hicn/config/controlRemoveConnection.c b/hicn-light/src/hicn/config/controlRemoveConnection.c deleted file mode 100644 index a6cfae1e5..000000000 --- a/hicn-light/src/hicn/config/controlRemoveConnection.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <hicn/utils/address.h> - -#include <hicn/config/controlRemoveConnection.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlRemoveConnection_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlRemoveConnection_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -// =================================================== - -static const char *_commandRemoveConnection = "remove connection"; -static const char *_commandRemoveConnectionHelp = "help remove connection"; - -// ==================================================== - -CommandOps *controlRemoveConnection_Create(ControlState *state) { - return commandOps_Create(state, _commandRemoveConnection, NULL, - _controlRemoveConnection_Execute, - commandOps_Destroy); -} - -CommandOps *controlRemoveConnection_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandRemoveConnectionHelp, NULL, - _controlRemoveConnection_HelpExecute, - commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlRemoveConnection_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "command:\n" - " remove connection <symbolic|id>\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlRemoveConnection_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - if (parcList_Size(args) != 3) { - _controlRemoveConnection_HelpExecute(parser, ops, args, output, output_size); - return false; - } - - if ((strcmp(parcList_GetAtIndex(args, 0), "remove") != 0) || - (strcmp(parcList_GetAtIndex(args, 1), "connection") != 0)) { - _controlRemoveConnection_HelpExecute(parser, ops, args, output, output_size); - return false; - } - - const char *symbolicOrConnid = parcList_GetAtIndex(args, 2); - - if (!utils_ValidateSymbolicName(symbolicOrConnid) && - !utils_IsNumber(symbolicOrConnid)) { - snprintf(output, output_size, - "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an " - "alpha followed by alphanum;\nconnid must be an integer\n"); - return CommandReturn_Failure; - } - - // allocate command payload - remove_connection_command *removeConnectionCommand = - parcMemory_AllocateAndClear(sizeof(remove_connection_command)); - // fill payload - strcpy(removeConnectionCommand->symbolicOrConnid, symbolicOrConnid); - - // send message and receive response - struct iovec *response = - utils_SendRequest(state, REMOVE_CONNECTION, removeConnectionCommand, - sizeof(remove_connection_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlRemoveConnection.h b/hicn-light/src/hicn/config/controlRemoveConnection.h deleted file mode 100644 index 51d3a52a8..000000000 --- a/hicn-light/src/hicn/config/controlRemoveConnection.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_RemoveConnection.h - * @brief Remove a connection from the connection table - * - * Implements the "remove connection" and "help remove connection" nodes of the - * CLI tree - * - */ - -#ifndef Control_RemoveConnection_h -#define Control_RemoveConnection_h - -#include <hicn/config/controlState.h> -CommandOps *controlRemoveConnection_Create(ControlState *state); -CommandOps *controlRemoveConnection_HelpCreate(ControlState *state); -#endif // Control_RemoveConnection_h diff --git a/hicn-light/src/hicn/config/controlRemoveListener.c b/hicn-light/src/hicn/config/controlRemoveListener.c deleted file mode 100644 index 7525316f1..000000000 --- a/hicn-light/src/hicn/config/controlRemoveListener.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <hicn/utils/address.h> - -#include <hicn/config/controlRemoveListener.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlRemoveListener_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlRemoveListener_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -// =================================================== - -static const char *_commandRemoveListener = "remove listener"; -static const char *_commandRemoveListenerHelp = "help remove listener"; - -// ==================================================== - -CommandOps *controlRemoveListener_Create(ControlState *state) { - return commandOps_Create(state, _commandRemoveListener, NULL, - _controlRemoveListener_Execute, - commandOps_Destroy); -} - -CommandOps *controlRemoveListener_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandRemoveListenerHelp, NULL, - _controlRemoveListener_HelpExecute, - commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlRemoveListener_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "command:\n" - " remove listener <symbolic|id>\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlRemoveListener_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - if (parcList_Size(args) != 3) { - _controlRemoveListener_HelpExecute(parser, ops, args, output, output_size); - return false; - } - - if ((strcmp(parcList_GetAtIndex(args, 0), "remove") != 0) || - (strcmp(parcList_GetAtIndex(args, 1), "listener") != 0)) { - _controlRemoveListener_HelpExecute(parser, ops, args, output, output_size); - return false; - } - - const char *listenerId = parcList_GetAtIndex(args, 2); - -if (!utils_ValidateSymbolicName(listenerId) && - !utils_IsNumber(listenerId)) { - snprintf(output, output_size, - "ERROR: Invalid symbolic or listenerId:\nsymbolic name must begin with an " - "alpha followed by alphanum;\nlistenerId must be an integer\n"); - return CommandReturn_Failure; - } - - // allocate command payload - remove_listener_command *removeListenerCommand = - parcMemory_AllocateAndClear(sizeof(remove_listener_command)); - // fill payload - //removeListenerCommand->listenerId = atoi(listenerId); - snprintf(removeListenerCommand->symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%s", listenerId); - - // send message and receive response - struct iovec *response = - utils_SendRequest(state, REMOVE_LISTENER, removeListenerCommand, - sizeof(remove_listener_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlRemoveListener.h b/hicn-light/src/hicn/config/controlRemoveListener.h deleted file mode 100644 index 794d1e1a9..000000000 --- a/hicn-light/src/hicn/config/controlRemoveListener.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_RemoveConnection.h - * @brief Remove a connection from the connection table - * - * Implements the "remove connection" and "help remove connection" nodes of the - * CLI tree - * - */ - -#ifndef Control_RemoveListener_h -#define Control_RemoveListener_h - -#include <hicn/config/controlState.h> -CommandOps *controlRemoveListener_Create(ControlState *state); -CommandOps *controlRemoveListener_HelpCreate(ControlState *state); -#endif // Control_RemoveListener_h diff --git a/hicn-light/src/hicn/config/controlRemovePolicy.c b/hicn-light/src/hicn/config/controlRemovePolicy.c deleted file mode 100644 index 35741396e..000000000 --- a/hicn-light/src/hicn/config/controlRemovePolicy.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#ifdef WITH_POLICY - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <parc/algol/parc_List.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <hicn/utils/address.h> - -#include <hicn/config/controlRemovePolicy.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlRemovePolicy_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlRemovePolicy_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -// =================================================== - -static const char *_commandRemovePolicy = "remove policy"; -static const char *_commandRemovePolicyHelp = "help remove policy"; - -// ==================================================== - -CommandOps *controlRemovePolicy_Create(ControlState *state) { - return commandOps_Create(state, _commandRemovePolicy, NULL, - _controlRemovePolicy_Execute, commandOps_Destroy); -} - -CommandOps *controlRemovePolicy_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandRemovePolicyHelp, NULL, - _controlRemovePolicy_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlRemovePolicy_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "commands:\n" - " remove policy <prefix>\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlRemovePolicy_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - if (parcList_Size(args) != 3) { - _controlRemovePolicy_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *prefixStr = parcList_GetAtIndex(args, 2); - char *addr = (char *)malloc(sizeof(char) * (strlen(prefixStr) + 1)); - - // separate address and len - char *slash; - uint32_t len = 0; - strcpy(addr, prefixStr); - slash = strrchr(addr, '/'); - if (slash != NULL) { - len = atoi(slash + 1); - *slash = '\0'; - } - - // allocate command payload - remove_policy_command *removePolicyCommand = - parcMemory_AllocateAndClear(sizeof(remove_policy_command)); - - // check and set IP address - if (inet_pton(AF_INET, addr, &removePolicyCommand->address.v4.as_u32) == 1) { - if (len > 32) { - snprintf(output, output_size, "ERROR: exceeded INET mask length, max=32\n"); - parcMemory_Deallocate(&removePolicyCommand); - free(addr); - return CommandReturn_Failure; - } - removePolicyCommand->addressType = ADDR_INET; - } else if (inet_pton(AF_INET6, addr, &removePolicyCommand->address.v6.as_in6addr) == - 1) { - if (len > 128) { - snprintf(output, output_size, "ERROR: exceeded INET6 mask length, max=128\n"); - parcMemory_Deallocate(&removePolicyCommand); - free(addr); - return CommandReturn_Failure; - } - removePolicyCommand->addressType = ADDR_INET6; - } else { - snprintf(output, output_size, "Error: %s is not a valid network address \n", addr); - parcMemory_Deallocate(&removePolicyCommand); - free(addr); - return CommandReturn_Failure; - } - - free(addr); - // Fill remaining payload fields - removePolicyCommand->len = len; - - // send message and receive response - struct iovec *response = utils_SendRequest( - state, REMOVE_POLICY, removePolicyCommand, sizeof(remove_policy_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} - -#endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/config/controlRemovePolicy.h b/hicn-light/src/hicn/config/controlRemovePolicy.h deleted file mode 100644 index ebe098985..000000000 --- a/hicn-light/src/hicn/config/controlRemovePolicy.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_RemovePolicy.h - * @brief Remove a policy from the FIB - * - * Implements the "remove policy" and "help remove policy" nodes of the command - * tree - * - */ - -#ifndef Control_RemovePolicy_h -#define Control_RemovePolicy_h - -#ifdef WITH_POLICY - -#include <hicn/config/controlState.h> -CommandOps *controlRemovePolicy_Create(ControlState *state); -CommandOps *controlRemovePolicy_HelpCreate(ControlState *state); - -#endif /* WITH_POLICY */ - -#endif // Control_RemovePolicy_h diff --git a/hicn-light/src/hicn/config/controlRemovePunting.c b/hicn-light/src/hicn/config/controlRemovePunting.c deleted file mode 100644 index 84d096b81..000000000 --- a/hicn-light/src/hicn/config/controlRemovePunting.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <hicn/utils/address.h> - -#include <hicn/config/controlRemovePunting.h> - -static CommandReturn _controlRemovePunting_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlRemovePunting_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -// =================================================== - -static const char *_commandRemovePunting = "remove punting"; -static const char *_commandRemovePuntingHelp = "help punting connection"; - -// ==================================================== - -CommandOps *controlRemovePunting_Create(ControlState *state) { - return commandOps_Create(state, _commandRemovePunting, NULL, - _controlRemovePunting_Execute, commandOps_Destroy); -} - -CommandOps *controlRemovePunting_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandRemovePuntingHelp, NULL, - _controlRemovePunting_HelpExecute, - commandOps_Destroy); -} - -// ==================================================== - -// ==================================================== - -static CommandReturn _controlRemovePunting_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "remove punting <symbolic> <prefix>\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlRemovePunting_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "command not implemented\n"); - return _controlRemovePunting_HelpExecute(parser, ops, args, output, output_size); -} - -// ================================================== diff --git a/hicn-light/src/hicn/config/controlRemoveRoute.c b/hicn-light/src/hicn/config/controlRemoveRoute.c deleted file mode 100644 index eb5642d98..000000000 --- a/hicn-light/src/hicn/config/controlRemoveRoute.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <parc/algol/parc_List.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <hicn/utils/address.h> - -#include <hicn/config/controlRemoveRoute.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlRemoveRoute_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlRemoveRoute_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -// =================================================== - -static const char *_commandRemoveRoute = "remove route"; -static const char *_commandRemoveRouteHelp = "help remove route"; - -// ==================================================== - -CommandOps *controlRemoveRoute_Create(ControlState *state) { - return commandOps_Create(state, _commandRemoveRoute, NULL, - _controlRemoveRoute_Execute, commandOps_Destroy); -} - -CommandOps *controlRemoveRoute_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandRemoveRouteHelp, NULL, - _controlRemoveRoute_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlRemoveRoute_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "commands:\n" - " remove route <symbolic | connid> <prefix>\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlRemoveRoute_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - if (parcList_Size(args) != 4) { - _controlRemoveRoute_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *symbolicOrConnid = parcList_GetAtIndex(args, 2); - - if (!utils_ValidateSymbolicName(symbolicOrConnid) && - !utils_IsNumber(symbolicOrConnid)) { - snprintf(output, output_size, - "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an " - "alpha followed by alphanum;\nconnid must be an integer\n"); - return CommandReturn_Failure; - } - - const char *prefixStr = parcList_GetAtIndex(args, 3); - char *addr = (char *)malloc(sizeof(char) * (strlen(prefixStr) + 1)); - - // separate address and len - char *slash; - uint32_t len = 0; - strcpy(addr, prefixStr); - slash = strrchr(addr, '/'); - if (slash != NULL) { - len = atoi(slash + 1); - *slash = '\0'; - } - - // allocate command payload - remove_route_command *removeRouteCommand = - parcMemory_AllocateAndClear(sizeof(remove_route_command)); - - // check and set IP address - if (inet_pton(AF_INET, addr, &removeRouteCommand->address.v4.as_u32) == 1) { - if (len > 32) { - snprintf(output, output_size, "ERROR: exceeded INET mask length, max=32\n"); - parcMemory_Deallocate(&removeRouteCommand); - free(addr); - return CommandReturn_Failure; - } - removeRouteCommand->addressType = ADDR_INET; - } else if (inet_pton(AF_INET6, addr, &removeRouteCommand->address.v6.as_in6addr) == - 1) { - if (len > 128) { - snprintf(output, output_size, "ERROR: exceeded INET6 mask length, max=128\n"); - parcMemory_Deallocate(&removeRouteCommand); - free(addr); - return CommandReturn_Failure; - } - removeRouteCommand->addressType = ADDR_INET6; - } else { - snprintf(output, output_size, "Error: %s is not a valid network address \n", addr); - parcMemory_Deallocate(&removeRouteCommand); - free(addr); - return CommandReturn_Failure; - } - - free(addr); - // Fill remaining payload fields - removeRouteCommand->len = len; - strcpy(removeRouteCommand->symbolicOrConnid, symbolicOrConnid); - - // send message and receive response - struct iovec *response = utils_SendRequest( - state, REMOVE_ROUTE, removeRouteCommand, sizeof(remove_route_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlRemoveRoute.h b/hicn-light/src/hicn/config/controlRemoveRoute.h deleted file mode 100644 index 5e152b2fd..000000000 --- a/hicn-light/src/hicn/config/controlRemoveRoute.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_RemoveRoute.h - * @brief Remove a route from the FIB - * - * Implements the "remove route" and "help remove route" nodes of the command - * tree - * - */ - -#ifndef Control_RemoveRoute_h -#define Control_RemoveRoute_h - -#include <hicn/config/controlState.h> -CommandOps *controlRemoveRoute_Create(ControlState *state); -CommandOps *controlRemoveRoute_HelpCreate(ControlState *state); -#endif // Control_RemoveRoute_h diff --git a/hicn-light/src/hicn/config/controlRoot.c b/hicn-light/src/hicn/config/controlRoot.c deleted file mode 100644 index 39a1fa6b5..000000000 --- a/hicn-light/src/hicn/config/controlRoot.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <hicn/config/controlAdd.h> -#include <hicn/config/controlCache.h> -#include <hicn/config/controlList.h> -#include <hicn/config/controlMapMe.h> -#include <hicn/config/controlQuit.h> -#include <hicn/config/controlRemove.h> -#include <hicn/config/controlRoot.h> -#include <hicn/config/controlSet.h> -#include <hicn/config/controlUnset.h> -#ifdef WITH_POLICY -#include <hicn/config/controlUpdate.h> -#endif /* WITH_POLICY */ - -static void _controlRoot_Init(CommandParser *parser, CommandOps *ops); -static CommandReturn _controlRoot_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlRoot_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandRoot = ""; -static const char *_commandRootHelp = "help"; - -// ==================================================== - -CommandOps *controlRoot_Create(ControlState *state) { - return commandOps_Create(state, _commandRoot, _controlRoot_Init, - _controlRoot_Execute, commandOps_Destroy); -} - -CommandOps *controlRoot_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandRootHelp, NULL, - _controlRoot_HelpExecute, commandOps_Destroy); -} - -// =================================================== - -static CommandReturn _controlRoot_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - size_t output_offset = snprintf(output, output_size, "Command-line execution:\n" - " controller [--server <server-ip>] [--port <server-port>] " - "command\n" - "\n" - "Interactive execution:\n" - " controller [--server <server-ip>] [--port <server-port>]\n" - "\n" - "If the keystore is not specified, the default path is used. Keystore " - "must exist prior to running program.\n" - "If the password is not specified, the user will be prompted.\n" - "\n"); - - CommandOps *ops_help_add = controlAdd_CreateHelp(NULL); - CommandOps *ops_help_list = controlList_HelpCreate(NULL); - CommandOps *ops_help_quit = controlQuit_HelpCreate(NULL); - CommandOps *ops_help_remove = controlRemove_HelpCreate(NULL); - CommandOps *ops_help_set = controlSet_HelpCreate(NULL); - CommandOps *ops_help_unset = controlUnset_HelpCreate(NULL); - CommandOps *ops_help_cache = controlCache_HelpCreate(NULL); - CommandOps *ops_help_mapme = controlMapMe_HelpCreate(NULL); -#ifdef WITH_POLICY - CommandOps *ops_help_update = controlUpdate_HelpCreate(NULL); -#endif /* WITH_POLICY */ - - snprintf(output + output_offset, output_size - output_offset,"Available commands:\n" - " %s\n" - " %s\n" - " %s\n" - " %s\n" - " %s\n" - " %s\n" - " %s\n" - " %s\n" -#ifdef WITH_POLICY - " %s\n" -#endif /* WITH_POLICY */ - "\n", - ops_help_add->command, - ops_help_list->command, - ops_help_quit->command, - ops_help_remove->command, - ops_help_set->command, - ops_help_unset->command, - ops_help_cache->command, - ops_help_mapme->command -#ifdef WITH_POLICY - , ops_help_update->command -#endif /* WITH_POLICY */ - ); - - commandOps_Destroy(&ops_help_add); - commandOps_Destroy(&ops_help_list); - commandOps_Destroy(&ops_help_quit); - commandOps_Destroy(&ops_help_remove); - commandOps_Destroy(&ops_help_set); - commandOps_Destroy(&ops_help_unset); - commandOps_Destroy(&ops_help_cache); - commandOps_Destroy(&ops_help_mapme); -#ifdef WITH_POLICY - commandOps_Destroy(&ops_help_update); -#endif /* WITH_POLICY */ - - return CommandReturn_Success; -} - -static void _controlRoot_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - - controlState_RegisterCommand(state, controlAdd_CreateHelp(state)); - controlState_RegisterCommand(state, controlList_HelpCreate(state)); - controlState_RegisterCommand(state, controlQuit_HelpCreate(state)); - controlState_RegisterCommand(state, controlRemove_HelpCreate(state)); - controlState_RegisterCommand(state, controlSet_HelpCreate(state)); - controlState_RegisterCommand(state, controlUnset_HelpCreate(state)); - controlState_RegisterCommand(state, controlCache_HelpCreate(state)); - controlState_RegisterCommand(state, controlMapMe_HelpCreate(state)); -#ifdef WITH_POLICY - controlState_RegisterCommand(state, controlUpdate_HelpCreate(state)); -#endif /* WITH_POLICY */ - - controlState_RegisterCommand(state, webControlAdd_Create(state)); - controlState_RegisterCommand(state, controlList_Create(state)); - controlState_RegisterCommand(state, controlQuit_Create(state)); - controlState_RegisterCommand(state, controlRemove_Create(state)); - controlState_RegisterCommand(state, controlSet_Create(state)); - controlState_RegisterCommand(state, controlUnset_Create(state)); - controlState_RegisterCommand(state, controlCache_Create(state)); - controlState_RegisterCommand(state, controlMapMe_Create(state)); -#ifdef WITH_POLICY - controlState_RegisterCommand(state, controlUpdate_Create(state)); -#endif /* WITH_POLICY */ -} - -static CommandReturn _controlRoot_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return CommandReturn_Success; -} - -// ====================================================================== diff --git a/hicn-light/src/hicn/config/controlRoot.h b/hicn-light/src/hicn/config/controlRoot.h deleted file mode 100644 index 154b81a80..000000000 --- a/hicn-light/src/hicn/config/controlRoot.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_Root.h - * @brief Root of the command tree - * - * Implements the root of the command tree. This is the one module that - * needs to be seeded to the control state to build the whole tree. - * - */ - -#ifndef Control_Root_h -#define Control_Root_h - -#include <hicn/config/controlState.h> -CommandOps *controlRoot_Create(ControlState *state); -CommandOps *controlRoot_HelpCreate(ControlState *state); -#endif // Control_Root_h diff --git a/hicn-light/src/hicn/config/controlSet.c b/hicn-light/src/hicn/config/controlSet.c deleted file mode 100644 index 37d56e593..000000000 --- a/hicn-light/src/hicn/config/controlSet.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/security/parc_Security.h> - -#include <hicn/config/controlSet.h> -#include <hicn/config/controlSetDebug.h> -#include <hicn/config/controlSetStrategy.h> -#include <hicn/config/controlSetWldr.h> - -static void _controlSet_Init(CommandParser *parser, CommandOps *ops); -static CommandReturn _controlSet_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlSet_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandSet = "set"; -static const char *_commandSetHelp = "help set"; - -// =========================================================== - -CommandOps *controlSet_Create(ControlState *state) { - return commandOps_Create(state, _commandSet, _controlSet_Init, - _controlSet_Execute, commandOps_Destroy); -} - -CommandOps *controlSet_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandSetHelp, NULL, - _controlSet_HelpExecute, commandOps_Destroy); -} - -// =========================================================== - -static void _controlSet_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - controlState_RegisterCommand(state, controlSetDebug_Create(state)); - controlState_RegisterCommand(state, controlSetDebug_HelpCreate(state)); - controlState_RegisterCommand(state, controlSetStrategy_Create(state)); - controlState_RegisterCommand(state, controlSetStrategy_HelpCreate(state)); - controlState_RegisterCommand(state, controlSetWldr_Create(state)); - controlState_RegisterCommand(state, controlSetWldr_HelpCreate(state)); -} - -static CommandReturn _controlSet_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - CommandOps *ops_help_set_debug = controlSetDebug_HelpCreate(NULL); - CommandOps *ops_help_set_strategy = controlSetStrategy_HelpCreate(NULL); - CommandOps *ops_help_set_wldr = controlSetWldr_HelpCreate(NULL); - - snprintf(output, output_size, "Available commands:\n %s\n %s\n %s\n\n", - ops_help_set_debug->command, - ops_help_set_strategy->command, - ops_help_set_wldr->command); - - commandOps_Destroy(&ops_help_set_debug); - commandOps_Destroy(&ops_help_set_strategy); - commandOps_Destroy(&ops_help_set_wldr); - return CommandReturn_Success; -} - -static CommandReturn _controlSet_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlSet_HelpExecute(parser, ops, args, output, output_size); -} diff --git a/hicn-light/src/hicn/config/controlSet.h b/hicn-light/src/hicn/config/controlSet.h deleted file mode 100644 index abe2a611d..000000000 --- a/hicn-light/src/hicn/config/controlSet.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_Set.h - * @brief Implements the set node of the CLI tree - * - * Implements the "set" and "help set" nodes of the command tree - * - */ -#ifndef Control_Set_h -#define Control_Set_h - -#include <hicn/config/controlState.h> -CommandOps *controlSet_Create(ControlState *state); -CommandOps *controlSet_HelpCreate(ControlState *state); -#endif // Control_Set_h diff --git a/hicn-light/src/hicn/config/controlSetDebug.c b/hicn-light/src/hicn/config/controlSetDebug.c deleted file mode 100644 index a5dcc89c1..000000000 --- a/hicn-light/src/hicn/config/controlSetDebug.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlSetDebug.h> -#include <hicn/core/dispatcher.h> -#include <hicn/core/forwarder.h> - -static CommandReturn _controlSetDebug_Execute(CommandParser *parser, - CommandOps *ops, PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlSetDebug_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandSetDebug = "set debug"; -static const char *_commandSetDebugHelp = "help set debug"; - -// ==================================================== - -CommandOps *controlSetDebug_Create(ControlState *state) { - return commandOps_Create(state, _commandSetDebug, NULL, - _controlSetDebug_Execute, commandOps_Destroy); -} - -CommandOps *controlSetDebug_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandSetDebugHelp, NULL, - _controlSetDebug_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlSetDebug_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "set debug: will enable the debug flag for more verbose output\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlSetDebug_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 2) { - _controlSetDebug_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - ControlState *state = ops->closure; - controlState_SetDebug(state, true); - snprintf(output, output_size, "Debug flag set\n\n"); - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlSetDebug.h b/hicn-light/src/hicn/config/controlSetDebug.h deleted file mode 100644 index fabeb6952..000000000 --- a/hicn-light/src/hicn/config/controlSetDebug.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_SetDebug.h - * @brief Sets the debug flag for more verbose output - * - * Implements the "set debug" and "help set debug" nodes of the command tree - * - */ - -#ifndef Control_SetDebug_h -#define Control_SetDebug_h - -#include <hicn/config/controlState.h> -CommandOps *controlSetDebug_Create(ControlState *state); -CommandOps *controlSetDebug_HelpCreate(ControlState *state); -#endif // Control_SetDebug_h diff --git a/hicn-light/src/hicn/config/controlSetStrategy.c b/hicn-light/src/hicn/config/controlSetStrategy.c deleted file mode 100644 index fe0ba84a0..000000000 --- a/hicn-light/src/hicn/config/controlSetStrategy.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> - -#include <hicn/config/controlSetDebug.h> -#include <hicn/core/dispatcher.h> -#include <hicn/core/forwarder.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlSetStrategy_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlSetStrategy_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandSetStrategy = "set strategy"; -static const char *_commandSetStrategyHelp = "help set strategy"; - -static const char *_commandSetStrategyOptions[LAST_STRATEGY_VALUE] = { - "loadbalancer", - "random", - "low_latency", -}; - -// ==================================================== - -CommandOps *controlSetStrategy_Create(ControlState *state) { - return commandOps_Create(state, _commandSetStrategy, NULL, - _controlSetStrategy_Execute, commandOps_Destroy); -} - -CommandOps *controlSetStrategy_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandSetStrategyHelp, NULL, - _controlSetStrategy_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -strategy_type _validStrategy(const char *strategy) { - strategy_type validStrategy = LAST_STRATEGY_VALUE; - - for (int i = 0; i < LAST_STRATEGY_VALUE; i++) { - if (strcmp(_commandSetStrategyOptions[i], strategy) == 0) { - validStrategy = i; - break; - } - } - return validStrategy; -} - -static void _getAddressAndLen(const char * prefixStr, char *addr, uint32_t *len){ - char *slash; - strcpy(addr, prefixStr); - slash = strrchr(addr, '/'); - if (slash != NULL) { - *len = atoi(slash + 1); - *slash = '\0'; - } -} - -static bool _checkAndSetIp(set_strategy_command * setStrategyCommand, - int index, - char * addr, - uint32_t len, - char *output, - size_t output_size){ - // check and set IP address - int res; - if(index == -1) - res = inet_pton(AF_INET, addr, &setStrategyCommand->address.v4.as_u32); - else - res = inet_pton(AF_INET, addr, - &setStrategyCommand->addresses[index].v4.as_u32); - - if(res == 1) { - if (len == UINT32_MAX) { - snprintf(output, output_size, "Netmask not specified: set to 32 by default\n"); - len = 32; - } else if (len > 32) { - snprintf(output, output_size, "ERROR: exceeded INET mask length, max=32\n"); - return false; - } - if(index == -1) - setStrategyCommand->addressType = ADDR_INET; - else - setStrategyCommand->addresses_type[index] = ADDR_INET; - - } else { - - if(index == -1) - res = inet_pton(AF_INET6, addr, - &setStrategyCommand->address.v6.as_in6addr); - else - res = inet_pton(AF_INET6, addr, - &setStrategyCommand->addresses[index].v6.as_in6addr); - - if(res == 1) { - if (len == UINT32_MAX) { - snprintf(output, output_size, "Netmask not specified: set to 128 by default\n"); - len = 128; - } else if (len > 128) { - snprintf(output, output_size, "ERROR: exceeded INET6 mask length, max=128\n"); - return false; - } - - if(index == -1) - setStrategyCommand->addressType = ADDR_INET6; - else - setStrategyCommand->addresses_type[index] = ADDR_INET6; - - } else { - snprintf(output, output_size, "Error: %s is not a valid network address \n", addr); - - return false; - } - } - return true; -} - -static CommandReturn _controlSetStrategy_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, - "set strategy <prefix> <strategy> " - "[related_prefix1 related_preifx2 ...]\n" - "prefix: ipv4/ipv6 address (ex: 1234::/64)\n" - "strategy: strategy identifier\n" - "optinal: list of related prefixes (max %u)\n" - "available strategies:\n" - " random\n" - " loadbalancer\n" - " low_latency\n\n", - MAX_FWD_STRATEGY_RELATED_PREFIXES); - return CommandReturn_Success; -} - - -static CommandReturn _controlSetStrategy_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (output) { - output[0] = '\0'; - } - ControlState *state = ops->closure; - - if (parcList_Size(args) < 4 || - parcList_Size(args) > (4 + MAX_FWD_STRATEGY_RELATED_PREFIXES)) { - _controlSetStrategy_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - if (((strcmp(parcList_GetAtIndex(args, 0), "set") != 0) || - (strcmp(parcList_GetAtIndex(args, 1), "strategy") != 0))) { - _controlSetStrategy_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *prefixStr = parcList_GetAtIndex(args, 2); - char *addr = (char *)malloc(sizeof(char) * (strlen(prefixStr) + 1)); - uint32_t len = UINT32_MAX; - _getAddressAndLen(prefixStr, addr, &len); - - // allocate command payload - set_strategy_command *setStrategyCommand = - parcMemory_AllocateAndClear(sizeof(set_strategy_command)); - - bool success = _checkAndSetIp(setStrategyCommand, -1, addr, len, output, output_size); - if(!success){ - parcMemory_Deallocate(&setStrategyCommand); - free(addr); - return CommandReturn_Failure; - } - - const char *strategyStr = parcList_GetAtIndex(args, 3); - // check valid strategy - strategy_type strategy; - if ((strategy = _validStrategy(strategyStr)) == LAST_STRATEGY_VALUE) { - size_t output_offset = strlen(output); - output_offset += snprintf(output + output_offset, output_size - output_offset, "Error: invalid strategy \n"); - - parcMemory_Deallocate(&setStrategyCommand); - _controlSetStrategy_HelpExecute(parser, ops, args, output + output_offset, output_size - output_offset); - free(addr); - return CommandReturn_Failure; - } - - free(addr); - - // Fill remaining payload fields - setStrategyCommand->len = len; - setStrategyCommand->strategyType = strategy; - size_t output_offset = strlen(output); - //check additional prefixes - if(parcList_Size(args) > 4){ - uint32_t index = 4; //first realted prefix - uint32_t addr_index = 0; - setStrategyCommand->related_prefixes = (uint8_t)parcList_Size(args) - 4; - while(index < parcList_Size(args)){ - const char *str = parcList_GetAtIndex(args, index); - char *rel_addr = (char *)malloc(sizeof(char) * (strlen(str) + 1)); - uint32_t rel_len = UINT32_MAX; - _getAddressAndLen(str, rel_addr, &rel_len); - bool success = _checkAndSetIp(setStrategyCommand, addr_index, - rel_addr, rel_len, output + output_offset, output_size - output_offset); - if(!success){ - parcMemory_Deallocate(&setStrategyCommand); - free(rel_addr); - return CommandReturn_Failure; - } - output_offset = strlen(output); - setStrategyCommand->lens[addr_index] = rel_len; - free(rel_addr); - index++; - addr_index++; - } - }else{ - setStrategyCommand->related_prefixes = 0; - } - - // send message and receive response - struct iovec *response = utils_SendRequest( - state, SET_STRATEGY, setStrategyCommand, sizeof(set_strategy_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlSetStrategy.h b/hicn-light/src/hicn/config/controlSetStrategy.h deleted file mode 100644 index 7ad56ccba..000000000 --- a/hicn-light/src/hicn/config/controlSetStrategy.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 Control_SetStrategy_h -#define Control_SetStrategy_h - -#include <hicn/config/controlState.h> -CommandOps *controlSetStrategy_Create(ControlState *state); -CommandOps *controlSetStrategy_HelpCreate(ControlState *state); -#endif // Control_SetStrategy_h diff --git a/hicn-light/src/hicn/config/controlSetWldr.c b/hicn-light/src/hicn/config/controlSetWldr.c deleted file mode 100644 index 0d4a7eca2..000000000 --- a/hicn-light/src/hicn/config/controlSetWldr.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlSetDebug.h> -#include <hicn/core/dispatcher.h> -#include <hicn/core/forwarder.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlSetWldr_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlSetWldr_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandSetWldr = "set wldr"; -static const char *_commandSetWldrHelp = "help set wldr"; - -// ==================================================== - -CommandOps *controlSetWldr_Create(ControlState *state) { - return commandOps_Create(state, _commandSetWldr, NULL, - _controlSetWldr_Execute, commandOps_Destroy); -} - -CommandOps *controlSetWldr_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandSetWldrHelp, NULL, - _controlSetWldr_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlSetWldr_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "set wldr <on|off> <connection_id>\n\n"); - - return CommandReturn_Success; -} - -static CommandReturn _controlSetWldr_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - ControlState *state = ops->closure; - - if (parcList_Size(args) != 4) { - _controlSetWldr_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - if (((strcmp(parcList_GetAtIndex(args, 0), "set") != 0) || - (strcmp(parcList_GetAtIndex(args, 1), "wldr") != 0))) { - _controlSetWldr_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - bool active; - if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) { - active = true; - } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) { - active = false; - } else { - _controlSetWldr_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - // check if valid connid - const char *symbolicOrConnid = parcList_GetAtIndex(args, 3); - - if (!utils_ValidateSymbolicName(symbolicOrConnid) && - !utils_IsNumber(symbolicOrConnid)) { - snprintf(output, output_size, - "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an " - "alpha followed by alphanum;\nconnid must be an integer\n"); - return CommandReturn_Failure; - } - - // allocate command payload - set_wldr_command *setWldrCommand = - parcMemory_AllocateAndClear(sizeof(set_wldr_command)); - strcpy(setWldrCommand->symbolicOrConnid, symbolicOrConnid); - if (active) { - setWldrCommand->activate = ACTIVATE_ON; - } else { - setWldrCommand->activate = ACTIVATE_OFF; - } - - // send message and receive response - struct iovec *response = utils_SendRequest(state, SET_WLDR, setWldrCommand, - sizeof(set_wldr_command)); - - if (!response) { // get NULL pointer - return CommandReturn_Failure; - } - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlSetWldr.h b/hicn-light/src/hicn/config/controlSetWldr.h deleted file mode 100644 index 3c01110e4..000000000 --- a/hicn-light/src/hicn/config/controlSetWldr.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 Control_SetWldr_h -#define Control_SetWldr_h - -#include <hicn/config/controlState.h> -CommandOps *controlSetWldr_Create(ControlState *state); -CommandOps *controlSetWldr_HelpCreate(ControlState *state); -#endif // Control_SetWldr_h diff --git a/hicn-light/src/hicn/config/controlState.c b/hicn-light/src/hicn/config/controlState.c deleted file mode 100644 index acdae9e52..000000000 --- a/hicn-light/src/hicn/config/controlState.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> -#include <string.h> - -#include <parc/security/parc_Security.h> - -#include <parc/algol/parc_List.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/algol/parc_Time.h> -#include <parc/algol/parc_TreeRedBlack.h> - -#include <hicn/config/commandParser.h> -#include <hicn/config/controlRoot.h> -#include <hicn/config/controlState.h> - -#include <hicn/utils/commands.h> - -struct controller_state { - CommandParser *parser; - bool debugFlag; - - void *userdata; - struct iovec *(*writeRead)(ControlState *state, struct iovec *msg); - int sockfd; - char **commandOutput; - bool isInteractive; -}; - -int controlState_connectToFwdDeamon(char *server_ip, uint16_t port) { - int sockfd; - struct sockaddr_in servaddr; - - if ((sockfd = (int)socket(AF_INET, SOCK_STREAM, 0)) < 0) { - printf("\nSocket Creation Failed \n"); - return EXIT_FAILURE; - } - - memset(&servaddr, 0, sizeof(servaddr)); - - // Filling server information - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(port); - inet_pton(AF_INET, server_ip, &(servaddr.sin_addr.s_addr)); - - // Establish connection - if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { - printf("\nConnection Failed: hicn-light Daemon is not running \n"); - return -1; - } - - return sockfd; -} - -ControlState *controlState_Create( - void *userdata, - struct iovec *(*writeRead)(ControlState *state, struct iovec *msg), - bool openControllerConnetion, - char *server_ip, uint16_t port) { - ControlState *state = parcMemory_AllocateAndClear(sizeof(ControlState)); - parcAssertNotNull(state, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ControlState)); - state->parser = commandParser_Create(); - - state->userdata = userdata; - state->writeRead = writeRead; - state->debugFlag = false; - state->commandOutput = NULL; - state->isInteractive = true; - - if (openControllerConnetion) { - state->sockfd = controlState_connectToFwdDeamon(server_ip, port); - if (state->sockfd == -1) { - return NULL; - } - } else { - state->sockfd = 2; // stderr - } - - return state; -} - -void controlState_Destroy(ControlState **statePtr) { - parcAssertNotNull(statePtr, "Parameter statePtr must be non-null"); - parcAssertNotNull(*statePtr, - "Parameter statePtr must dereference t non-null"); - ControlState *state = *statePtr; - // printf("sockid destroyed: %d\n", state->sockfd); - // close the connection with the fwd deamon - shutdown(state->sockfd, 2); - - commandParser_Destroy(&state->parser); - parcMemory_Deallocate((void **)&state); - *statePtr = NULL; -} - -void controlState_SetDebug(ControlState *state, bool debugFlag) { - parcAssertNotNull(state, "Parameter state must be non-null"); - state->debugFlag = debugFlag; - commandParser_SetDebug(state->parser, debugFlag); -} - -bool controlState_GetDebug(ControlState *state) { - parcAssertNotNull(state, "Parameter state must be non-null"); - return state->debugFlag; -} - -void controlState_RegisterCommand(ControlState *state, CommandOps *ops) { - parcAssertNotNull(state, "Parameter state must be non-null"); - commandParser_RegisterCommand(state->parser, ops); -} - -struct iovec *controlState_WriteRead(ControlState *state, struct iovec *msg) { - parcAssertNotNull(state, "Parameter state must be non-null"); - parcAssertNotNull(msg, "Parameter msg must be non-null"); - - return state->writeRead(state, msg); -} - -static PARCList *_controlState_ParseStringIntoTokens( - const char *originalString) { - PARCList *list = - parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), - PARCArrayListAsPARCList); - - char *token; - - char *tofree = - parcMemory_StringDuplicate(originalString, strlen(originalString) + 1); - char *string = tofree; - - token = strtok(string, " \t\n"); - while (token != NULL) { - if (strlen(token) > 0) { - parcList_Add(list, strdup(token)); - } - token = strtok(NULL, " \t\n"); - } - - parcMemory_Deallocate((void **)&tofree); - - return list; -} - -CommandReturn controlState_DispatchCommand(ControlState *state, - PARCList *args, - char *output, - size_t output_size) { - parcAssertNotNull(state, "Parameter state must be non-null"); - return commandParser_DispatchCommand(state->parser, args, output, output_size); -} - -int controlState_Interactive(ControlState *state) { - parcAssertNotNull(state, "Parameter state must be non-null"); - char *line = NULL; - size_t linecap = 0; - CommandReturn controlReturn = CommandReturn_Success; - char output[8192]; - while (controlReturn != CommandReturn_Exit && !feof(stdin)) { - fputs("> ", stdout); - fflush(stdout); - ssize_t failure = getline(&line, &linecap, stdin); - parcAssertTrue(failure > -1, "Error getline"); - - PARCList *args = _controlState_ParseStringIntoTokens(line); - - controlReturn = controlState_DispatchCommand(state, args, output, sizeof(output)); - printf("%s", output); - // release and get command - parcList_Release(&args); - } - return 0; -} - -void controlState_SetCommandOutput(ControlState *state, char **commandData) { - state->commandOutput = commandData; -} - -void controlState_ReleaseCommandOutput(ControlState *state, char **commandData, - size_t commandLenght) { - for (size_t i = 0; i < commandLenght; i++) { - parcMemory_Deallocate(&commandData[i]); - } - parcMemory_Deallocate(&commandData); - state->commandOutput = NULL; -} - -char **controlState_GetCommandOutput(ControlState *state) { - return state->commandOutput; -} - -// size_t -// controlState_GetCommandLen(ControlState *state){ - -// } - -void controlState_SetInteractiveFlag(ControlState *state, bool interactive) { - state->isInteractive = interactive; -} - -bool controlState_IsInteractive(ControlState *state) { - return state->isInteractive; -} - -int controlState_GetSockfd(ControlState *state) { - parcAssertNotNull(state, "Parameter state must be non-null"); - return state->sockfd; -} - -void *controlState_GetUserdata(ControlState *state) { - parcAssertNotNull(state, "Parameter state must be non-null"); - return state->userdata; -} - -bool controlState_isConfigFile(ControlState *state) { - parcAssertNotNull(state, "Parameter state must be non-null"); - if (state->sockfd != 2) { - return false; - } else { - return true; - } -} diff --git a/hicn-light/src/hicn/config/controlState.h b/hicn-light/src/hicn/config/controlState.h deleted file mode 100644 index 52b1f6655..000000000 --- a/hicn-light/src/hicn/config/controlState.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file controlState.h - * @brief A control program for hicn-light using CLI commands - * - * Implements the state machine for the control program. It takes a "writeRead" - * function as part of the constructor. This abstracts out the backend. It - * could be a Portal from hicnLightControl program down to the forwarder or it - * could be an internal function within hicn-light. - * - */ - -#ifndef control_h -#define control_h - -#include <parc/algol/parc_List.h> -#include <hicn/config/commandParser.h> - -#include <hicn/utils/commands.h> - -#define SRV_CTRL_IP "127.0.0.1" -#define SRV_CTRL_PORT 9695 - -struct controller_state; -typedef struct controller_state ControlState; - -/** - * controlState_Create - * - * Creates the global state for the Control program. The user provides the - * writeRead function for sending and receiving the message wrapping command - * arguments. For configuration file inside hicn-light, it would make direct - * calls to Configuration -> Dispatcher. - * - * @param [in] userdata A closure passed back to the user when calling - * writeRead. - * @param [in] writeRead The function to write then read configuration messages - * to hicn-light - * - * @return non-null The control state - * - * Example: - * @code - * <#example#> - * @endcode - */ - -ControlState *controlState_Create( - void *userdata, - struct iovec *(*writeRead)(ControlState *state, struct iovec *msg), - bool openControllerConnetion, - char * server_ip, uint16_t port); - -/** - * Destroys the control state, closing all network connections - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @return <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -void controlState_Destroy(ControlState **statePtr); - -/** - * Registers a CommandOps with the system. - * - * Each command has its complete command prefix in the "command" field. - * RegisterCommand will put these command prefixes in to a tree and then match - * what a user types against the longest-matching prefix in the tree. If - * there's a match, it will call the "execute" function. - * - * @param [in] state An allocated ControlState - * @param [in] command The command to register with the system - * - * Example: - * @code - * static CommandReturn - * control_Root_Execute(CommandParser *parser, CommandOps *ops, PARCList - * *args) - * { - * printf("Root Command\n"); - * return CommandReturn_Success; - * } - * - * static CommandReturn - * control_FooBar_Execute(CommandParser *parser, CommandOps *ops, PARCList - * *args) - * { - * printf("Foo Bar Command\n"); - * return CommandReturn_Success; - * } - * - * const CommandOps control_Root = { - * .command = "", // empty string for root - * .init = NULL, - * .execute = control_Root_Execute - * }; - * - * const CommandOps control_FooBar = { - * .command = "foo bar", // empty string for root - * .init = NULL, - * .execute = control_FooBar_Execute - * }; - * - * void startup(void) - * { - * ControlState *state = controlState_Create("happy", "day"); - * controlState_RegisterCommand(state, control_FooBar); - * controlState_RegisterCommand(state, control_Root); - * - * // this executes "root" - * controlState_DispatchCommand(state, "foo"); - * controlState_Destroy(&state); - * } - * @endcode - */ -void controlState_RegisterCommand(ControlState *state, CommandOps *command); - -/** - * Performs a longest-matching prefix of the args to the command tree - * - * The command tree is created with controlState_RegisterCommand. - * - * @param [in] state The allocated ControlState - * @param [in] args Each command_line word parsed to the ordered list - * @param [in] output Output string - * @param [in] output_length output string max length - * - * @return CommandReturn_Success the command was successful - * @return CommandReturn_Failure the command failed or was not found - * @return CommandReturn_Exit the command indicates that the interactive mode - * should exit - * - * Example: - * @code - * <#example#> - * @endcode - */ -CommandReturn controlState_DispatchCommand(ControlState *state, - PARCList *args, - char *output, - size_t output_length); - -/** - * Begin an interactive shell - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @return <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -int controlState_Interactive(ControlState *state); - -/** - * Write then Read a command - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @return <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -struct iovec *controlState_WriteRead(ControlState *state, struct iovec *msg); - -/** - * Sets the Debug mode, which will print out much more information. - * - * Prints out much more diagnostic information about what hicn-light controller - * is doing. yes, you would make a CommandOps to set and unset this :) - * - * @param [in] debugFlag true means to print debug info, false means to turn it - * off - * - * Example: - * @code - * <#example#> - * @endcode - */ -void controlState_SetDebug(ControlState *state, bool debugFlag); - -/** - * Returns the debug state of ControlState - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @return <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -bool controlState_GetDebug(ControlState *state); -#endif // control_h - -void controlState_SetCommandOutput(ControlState *state, char **commandData); - -void controlState_ReleaseCommandOutput(ControlState *state, char **commandData, - size_t commandLenght); - -char **controlState_GetCommandOutput(ControlState *state); - -void controlState_SetInteractiveFlag(ControlState *state, bool interactive); - -bool controlState_IsInteractive(ControlState *state); - -void *controlState_GetUserdata(ControlState *state); - -bool controlState_isConfigFile(ControlState *state); - -int controlState_GetSockfd(ControlState *state); diff --git a/hicn-light/src/hicn/config/controlUnset.c b/hicn-light/src/hicn/config/controlUnset.c deleted file mode 100644 index e05ba2286..000000000 --- a/hicn-light/src/hicn/config/controlUnset.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/security/parc_Security.h> - -#include <hicn/config/controlUnset.h> -#include <hicn/config/controlUnsetDebug.h> - -static void _controlUnset_Init(CommandParser *parser, CommandOps *ops); - -static CommandReturn _controlUnset_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlUnset_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandUnset = "unset"; -static const char *_commandUnsetHelp = "help unset"; - -// =========================================================== - -CommandOps *controlUnset_Create(ControlState *state) { - return commandOps_Create(state, _commandUnset, _controlUnset_Init, - _controlUnset_Execute, commandOps_Destroy); -} - -CommandOps *controlUnset_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandUnsetHelp, NULL, - _controlUnset_HelpExecute, commandOps_Destroy); -} - -// =========================================================== - -static void _controlUnset_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - controlState_RegisterCommand(state, controlUnsetDebug_Create(state)); - controlState_RegisterCommand(state, controlUnsetDebug_HelpCreate(state)); -} - -static CommandReturn _controlUnset_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - CommandOps *ops_help_unset_debug = controlUnsetDebug_HelpCreate(NULL); - snprintf(output, output_size, "Available commands:\n %s\n\n", ops_help_unset_debug->command); - - commandOps_Destroy(&ops_help_unset_debug); - return CommandReturn_Success; -} - -static CommandReturn _controlUnset_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlUnset_HelpExecute(parser, ops, args, output, output_size); -} diff --git a/hicn-light/src/hicn/config/controlUnset.h b/hicn-light/src/hicn/config/controlUnset.h deleted file mode 100644 index 9d9cb5c44..000000000 --- a/hicn-light/src/hicn/config/controlUnset.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_Unset.h - * @brief Implements the unset node of the CLI tree - * - * Implements the "unset" and "help unset" nodes of the command tree - * - */ -#ifndef Control_Unset_h -#define Control_Unset_h - -#include <hicn/config/controlState.h> -CommandOps *controlUnset_Create(ControlState *state); -CommandOps *controlUnset_HelpCreate(ControlState *state); -#endif // Control_Unset_h diff --git a/hicn-light/src/hicn/config/controlUnsetDebug.c b/hicn-light/src/hicn/config/controlUnsetDebug.c deleted file mode 100644 index ac2a4e028..000000000 --- a/hicn-light/src/hicn/config/controlUnsetDebug.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlUnsetDebug.h> -#include <hicn/core/dispatcher.h> -#include <hicn/core/forwarder.h> - -static CommandReturn _controlUnsetDebug_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlUnsetDebug_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandUnsetDebug = "unset debug"; -static const char *_commandUnsetDebugHelp = "help unset debug"; - -// ==================================================== - -CommandOps *controlUnsetDebug_Create(ControlState *state) { - return commandOps_Create(state, _commandUnsetDebug, NULL, - _controlUnsetDebug_Execute, commandOps_Destroy); -} - -CommandOps *controlUnsetDebug_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandUnsetDebugHelp, NULL, - _controlUnsetDebug_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static CommandReturn _controlUnsetDebug_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - snprintf(output, output_size, "unset debug: will disable the debug flag\n\n"); - return CommandReturn_Success; -} - -static CommandReturn _controlUnsetDebug_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if (parcList_Size(args) != 2) { - _controlUnsetDebug_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - ControlState *state = ops->closure; - controlState_SetDebug(state, false); - snprintf(output, output_size, "Debug flag cleared\n\n"); - - return CommandReturn_Success; -} diff --git a/hicn-light/src/hicn/config/controlUnsetDebug.h b/hicn-light/src/hicn/config/controlUnsetDebug.h deleted file mode 100644 index c76ba8c98..000000000 --- a/hicn-light/src/hicn/config/controlUnsetDebug.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file control_UnsetDebug.h - * @brief Unsets the debug flag for more verbose output - * - * Implements the "unset debug" and "help unset debug" nodes of the CLI tree - * - */ - -#ifndef Control_UnsetDebug_h -#define Control_UnsetDebug_h - -#include <hicn/config/controlState.h> -CommandOps *controlUnsetDebug_Create(ControlState *state); -CommandOps *controlUnsetDebug_HelpCreate(ControlState *state); -#endif // Control_UnsetDebug_h diff --git a/hicn-light/src/hicn/config/controlUpdate.c b/hicn-light/src/hicn/config/controlUpdate.c deleted file mode 100644 index 095bbf01e..000000000 --- a/hicn-light/src/hicn/config/controlUpdate.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#ifdef WITH_POLICY - -#include <hicn/hicn-light/config.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/security/parc_Security.h> - -#include <parc/algol/parc_Memory.h> - -#include <hicn/config/controlUpdate.h> -#include <hicn/config/controlUpdateConnection.h> - -static void _controlUpdate_Init(CommandParser *parser, CommandOps *ops); -static CommandReturn _controlUpdate_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlUpdate_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *_commandUpdate = "update"; -static const char *_commandUpdateHelp = "help update"; - -CommandOps *controlUpdate_Create(ControlState *state) { - return commandOps_Create(state, _commandUpdate, _controlUpdate_Init, - _controlUpdate_Execute, commandOps_Destroy); -} - -CommandOps *controlUpdate_HelpCreate(ControlState *state) { - return commandOps_Create(state, _commandUpdateHelp, NULL, - _controlUpdate_HelpExecute, commandOps_Destroy); -} - -// ===================================================== - -static CommandReturn _controlUpdate_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - //CommandOps *ops_update_connections = controlUpdateConnections_HelpCreate(NULL); - // CommandOps *ops_update_interfaces = controlUpdateInterfaces_HelpCreate(NULL); - //CommandOps *ops_update_routes = controlUpdateRoutes_HelpCreate(NULL); - CommandOps *ops_update_listeners = controlUpdateConnection_HelpCreate(NULL); - snprintf(output, output_size, - "Available commands:\n %s\n\n", - ops_update_listeners->command); - - - - // commandOps_Destroy(&ops_update_connections); - // commandOps_Destroy(&ops_update_interfaces); - //commandOps_Destroy(&ops_update_routes); - commandOps_Destroy(&ops_update_listeners); - - return CommandReturn_Success; -} - -static void _controlUpdate_Init(CommandParser *parser, CommandOps *ops) { - ControlState *state = ops->closure; - //controlState_RegisterCommand(state, controlUpdateConnections_HelpCreate(state)); - // controlState_RegisterCommand(state, - // controlUpdateInterfaces_HelpCreate(state)); - controlState_RegisterCommand(state, controlUpdateConnection_HelpCreate(state)); - //controlState_RegisterCommand(state, controlUpdateRoutes_HelpCreate(state)); - //controlState_RegisterCommand(state, controlUpdateConnections_Create(state)); - // controlState_RegisterCommand(state, controlUpdateInterfaces_Create(state)); - //controlState_RegisterCommand(state, controlUpdateRoutes_Create(state)); - controlState_RegisterCommand(state, controlUpdateConnection_Create(state)); -} - -static CommandReturn _controlUpdate_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - return _controlUpdate_HelpExecute(parser, ops, args, output, output_size); -} - -#endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/config/controlUpdateConnection.c b/hicn-light/src/hicn/config/controlUpdateConnection.c deleted file mode 100644 index 70a017d4f..000000000 --- a/hicn-light/src/hicn/config/controlUpdateConnection.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#ifdef WITH_POLICY - -#include <hicn/hicn-light/config.h> - -#include <ctype.h> -#include <inttypes.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> - -#include <hicn/config/controlUpdateConnection.h> - -#include <hicn/policy.h> -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -static CommandReturn _controlUpdateConnection_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); -static CommandReturn _controlUpdateConnection_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size); - -static const char *command_update_connection = "update connection"; -static const char *command_help_update_connection = "help update connection"; - -CommandOps *controlUpdateConnection_Create(ControlState *state) { - return commandOps_Create(state, command_update_connection, NULL, - _controlUpdateConnection_Execute, commandOps_Destroy); -} - -CommandOps *controlUpdateConnection_HelpCreate(ControlState *state) { - return commandOps_Create(state, command_help_update_connection, NULL, - _controlUpdateConnection_HelpExecute, commandOps_Destroy); -} - -// ==================================================== - -static const int _indexSymbolic = 2; -static const int _indexTags = 3; - -static CommandReturn _controlUpdateConnection_HelpExecute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - - snprintf(output, output_size, - "commands:\n" - " update connection <symbolic | id> <tags> \n" - "\n" - " symbolic: User defined name for connection, must start with " - "alpha and be alphanum\n" - " id: Identifier for the connection\n" - " tags: A string representing tags\n"); - return CommandReturn_Success; -} - - -static CommandReturn _controlUpdateConnection_Execute(CommandParser *parser, - CommandOps *ops, - PARCList *args, - char *output, - size_t output_size) { - if ((parcList_Size(args) != 3) && (parcList_Size(args) != 4)) { - _controlUpdateConnection_HelpExecute(parser, ops, args, output, output_size); - return CommandReturn_Failure; - } - - const char *symbolicOrConnid = parcList_GetAtIndex(args, _indexSymbolic); - - if (!utils_ValidateSymbolicName(symbolicOrConnid) && - !utils_IsNumber(symbolicOrConnid)) { - snprintf(output, output_size, - "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an " - "alpha followed by alphanum;\nconnid must be an integer\n"); - return CommandReturn_Failure; - } - - policy_tags_t tags = POLICY_TAGS_EMPTY; - if (parcList_Size(args) == 4) { - const char *str_tags = parcList_GetAtIndex(args, _indexTags); - - for (unsigned i = 0; str_tags[i] != 0; i++) { - switch(tolower(str_tags[i])) { - case 'e': - policy_tags_add(&tags, POLICY_TAG_WIRED); - break; - case 'w': - policy_tags_add(&tags, POLICY_TAG_WIFI); - break; - case 'c': - policy_tags_add(&tags, POLICY_TAG_CELLULAR); - break; - case 'b': - policy_tags_add(&tags, POLICY_TAG_BEST_EFFORT); - break; - case 'r': - policy_tags_add(&tags, POLICY_TAG_REALTIME); - break; - case 'm': - policy_tags_add(&tags, POLICY_TAG_MULTIPATH); - break; - case 't': - policy_tags_add(&tags, POLICY_TAG_TRUSTED); - break; - } - } - } - ControlState *state = ops->closure; - - // allocate command payload - update_connection_command *updateConnectionCommand = - parcMemory_AllocateAndClear(sizeof(update_connection_command)); - updateConnectionCommand->tags = tags; - strcpy(updateConnectionCommand->symbolicOrConnid, symbolicOrConnid); - - // send message and receive response - struct iovec *response = utils_SendRequest( - state, UPDATE_CONNECTION, updateConnectionCommand, sizeof(update_connection_command)); - - if (!response) // get NULL pointer - return CommandReturn_Failure; - - parcMemory_Deallocate(&response); // free iovec pointer - return CommandReturn_Success; -} - -#endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/config/parse.c b/hicn-light/src/hicn/config/parse.c new file mode 100644 index 000000000..ba9c0b348 --- /dev/null +++ b/hicn-light/src/hicn/config/parse.c @@ -0,0 +1,402 @@ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +//#include <hicn/ctrl/cli.h> +#include <hicn/util/log.h> +#include <hicn/util/sstrncpy.h> +#include "parse.h" + +/* + * As there is no portable way to generate a va_list to use with sscanf to + * support a variable number of arguments, and no way to use a variable array + * initialize in a nested struct, we use a fixed maximum number of parameters + * + * NOTE: update sscanf accordingly + */ + +#include "command.h" + +const char *action_str[] = { +#define _(x) [ACTION_##x] = #x, + foreach_action +#undef _ +}; + +#define action_str(x) action_str[x] + +hc_action_t action_from_str(const char *action_str) { +#define _(x) \ + if (strcasecmp(action_str, #x) == 0) \ + return ACTION_##x; \ + else + foreach_action +#undef _ + if (strcasecmp(action_str, "add") == 0) return ACTION_CREATE; + else if (strcasecmp(action_str, "remove") == 0) return ACTION_DELETE; + else return ACTION_UNDEFINED; +} + +const char *object_str[] = { +#define _(x) [OBJECT_##x] = #x, + foreach_object +#undef _ +}; + +#define object_str(x) object_str[x] + +hc_object_type_t object_from_str(const char *object_str) { +#define _(x) \ + if (strcasecmp(object_str, #x) == 0) \ + return OBJECT_##x; \ + else + foreach_object +#undef _ + return OBJECT_UNDEFINED; +} + +const char *action_to_cmd_action(hc_action_t action) { + switch (action) { + case ACTION_CREATE: + return "add"; + case ACTION_UPDATE: + return "update"; + case ACTION_DELETE: + return "remove"; + case ACTION_LIST: + return "list"; + case ACTION_SET: + return "set"; + case ACTION_SERVE: + return "serve"; + case ACTION_STORE: + return "store"; + case ACTION_CLEAR: + return "clear"; + default: + return "UNDEFINED"; + } +} + +const char *parser_type_fmt(const parser_type_t *type) { + switch (type->name) { + case TYPENAME_INT: + return TYPE_FMT_INT; + case TYPENAME_UINT: + return TYPE_FMT_UINT; + case TYPENAME_STR: + return TYPE_FMT_STRN(type->str.max_size); + case TYPENAME_SYMBOLIC_OR_ID: + return TYPE_FMT_SYMBOLIC_OR_ID; + case TYPENAME_INTERFACE_NAME: + return TYPE_FMT_INTERFACE_NAME; + case TYPENAME_IP_ADDRESS: + return TYPE_FMT_IP_ADDRESS; + case TYPENAME_IP_PREFIX: + return TYPE_FMT_IP_PREFIX; + case TYPENAME_ON_OFF: + return TYPE_FMT_ON_OFF; + case TYPENAME_ENUM: + return TYPE_FMT_ENUM; + case TYPENAME_POLICY_STATE: + return TYPE_FMT_POLICY_STATE; + case TYPENAME_UNDEFINED: + default: + return NULL; + } +} + +int parser_type_func(const parser_type_t *type, void *src, void *dst, + void *dst2, void *dst3) { + ip_address_t addr; + char *addr_str; + char *len_str; + int len, tmp, rc; + + switch (type->name) { + case TYPENAME_INT: + tmp = *(int *)src; + if (tmp < type->sint.min || tmp > type->sint.max) { + ERROR("Input number (%d) not inside range [%d, %d]", tmp, + type->sint.min, type->sint.max); + return -1; + } + *(int *)dst = *(int *)src; + break; + case TYPENAME_UINT: + tmp = *(int *)src; + if (tmp < type->uint.min || tmp > type->uint.max) { + ERROR("Input number (%d) not inside range [%d, %d]", tmp, + type->uint.min, type->uint.max); + return -1; + } + *(unsigned *)dst = *(unsigned *)src; + break; + case TYPENAME_STR: + rc = strcpy_s(dst, type->str.max_size, src); + if (rc != EOK) { + ERROR("Input string is too long"); + return -1; + } + break; + case TYPENAME_IP_ADDRESS: + rc = ip_address_pton((char *)src, &addr); + if (rc < 0) { + ERROR("Wrong IP address format"); + return -1; + } + + *(ip_address_t *)dst = addr; + *(int *)dst2 = ip_address_get_family((char *)src); + break; + case TYPENAME_ON_OFF: + if (strcmp((char *)src, "off") == 0) { + *(unsigned *)dst = 0; + } else if (strcmp((char *)src, "on") == 0) { + *(unsigned *)dst = 1; + } else { + ERROR("on/off are the only possible values"); + return -1; + } + break; + case TYPENAME_IP_PREFIX: + addr_str = strtok((char *)src, "/"); + len_str = strtok(NULL, " "); + rc = ip_address_pton((char *)src, &addr); + if (rc < 0) { + ERROR("Wrong IP address format"); + return -1; + } + len = atoi(len_str); + + *(ip_address_t *)dst = addr; + *(int *)dst2 = len; + *(int *)dst3 = ip_address_get_family(addr_str); + break; + case TYPENAME_ENUM: + /* Enum index from string */ + assert(type->enum_.from_str); + *(int *)dst = type->enum_.from_str((char *)src); + break; + case TYPENAME_POLICY_STATE: { + assert(IS_VALID_POLICY_TAG(type->policy_state.tag)); + policy_tag_t tag = type->policy_state.tag; + /* Format string is "%ms" */ + const char *str = *(const char **)src; + policy_tag_state_t *pts = ((policy_tag_state_t *)dst); + pts[tag].disabled = (str[0] == '!') ? 1 : 0; + pts[tag].state = policy_state_from_str(str + pts[tag].disabled); + break; + } + case TYPENAME_UNDEFINED: + default: + ERROR("Unknown format"); + return -1; + } + return 0; +} + +int parse_params(const command_parser_t *parser, const char *params_s, + hc_command_t *command) { + char fmt[1024]; + int n; + size_t size = 0; + char *pos = fmt; + /* Update MAX_PARAMETERS accordingly in command.h */ + char sscanf_params[MAX_PARAMETERS][MAX_SCANF_PARAM_LEN]; + + unsigned count = 0; + for (unsigned i = 0; i < parser->nparams; i++) { + const command_parameter_t *p = &parser->parameters[i]; + const char *_fmt = parser_type_fmt(&p->type); + // printf(" _fmt=%s\n", _fmt); + if (!_fmt) { + WARN("Ignored parameter %s with unknown type formatter", p->name); + continue; + } + n = snprintf(pos, 1024 - size, "%s", _fmt); + pos += n; + + *pos = ' '; + pos++; + + size += n + 1; + count++; + } + *pos = '\0'; + DEBUG("parser format: %s", fmt); + + int ret = sscanf(params_s, fmt, sscanf_params[0], sscanf_params[1], + sscanf_params[2], sscanf_params[3], sscanf_params[4], + sscanf_params[5], sscanf_params[6], sscanf_params[7], + sscanf_params[8], sscanf_params[9]); + if (ret != parser->nparams) { + ERROR("Parsing failed: check for string used where integer was expected"); + goto ERR; + } + + for (unsigned i = 0; i < count; i++) { + const command_parameter_t *p = &parser->parameters[i]; + if (parser_type_func(&p->type, sscanf_params[i], + &command->object.as_uint8 + p->offset, + &command->object.as_uint8 + p->offset2, + &command->object.as_uint8 + p->offset3) < 0) { + ERROR("Error during parsing of parameter '%s' value", p->name); + goto ERR; + } + } + return 0; + +ERR: + return -1; +} + +int parse(const char *cmd, hc_command_t *command) { + int nparams = 0; + char action_s[MAX_SCANF_PARAM_LEN]; + char object_s[MAX_SCANF_PARAM_LEN]; + char params_s[MAX_SCANF_PARAM_LEN]; + + // if n = 2 later, params_s is uninitialized + memset(params_s, 0, MAX_SCANF_PARAM_LEN * sizeof(char)); + + errno = 0; + int n = sscanf(cmd, "%s %s%[^\n]s", action_s, object_s, params_s); + if ((n < 2) || (n > 3)) { + if (errno != 0) perror("scanf"); + return -1; + } + + command->action = action_from_str(action_s); + command->object.type = object_from_str(object_s); + + if (strnlen_s(params_s, MAX_SCANF_PARAM_LEN) > 0) { + for (char *ptr = params_s; (ptr = strchr(ptr, ' ')) != NULL; ptr++) + nparams++; + } + + /* + * This checks is important even with 0 parameters as it checks whether the + * command exists. + */ + const command_parser_t *parser = + command_search(command->action, command->object.type, nparams); + if (!parser) { + ERROR("Could not find parser for command '%s %s'", action_s, object_s); + return -1; + } + + if (strnlen_s(params_s, MAX_SCANF_PARAM_LEN) > 0) { + if (parse_params(parser, params_s, command) < 0) return -1; + } + + if (parser->post_hook) parser->post_hook(&command->object.as_uint8); + return 0; +} + +int help(const char *cmd) { + int nparams = 1; + char action_s[MAX_SCANF_PARAM_LEN]; + char object_s[MAX_SCANF_PARAM_LEN]; + char params_s[MAX_SCANF_PARAM_LEN]; + hc_object_type_t object = OBJECT_UNDEFINED; + hc_action_t action = ACTION_UNDEFINED; + + int n = sscanf(cmd, "help %[^\n]s", params_s); + + // No arguments provided to the help command: just list available objects + if (n != 1) goto CMD_LIST; + + // Count number of provided parameters + for (char *ptr = params_s; (ptr = strchr(ptr, ' ')) != NULL; ptr++) nparams++; + if (nparams > 2) { + fprintf(stderr, "Error: too many arguments.\n"); + return -1; + } + + // Object specified: list actions available for that object + if (nparams == 1) { + object = object_from_str(params_s); + if (object == OBJECT_UNDEFINED) { + fprintf(stderr, "Error: undefined object.\n"); + return -1; + } + + goto CMD_LIST; + } + + // Object and action specified: list detailed commands + n = sscanf(params_s, "%s %[^\n]s", object_s, action_s); + assert(n == 2); + object = object_from_str(object_s); + action = action_from_str(action_s); + if (object == OBJECT_UNDEFINED || action == ACTION_UNDEFINED) { + fprintf(stderr, "Error: undefined object and/or action.\n"); + return -1; + } + +CMD_LIST: + printf("Available commands:\n"); + command_list(object, action); + return 0; +} + +#if 0 // tests +/* For the tests, we will need to test all non-compliant inputs */ +const char * cmds[] = { + "add connection hicn conn1 8.8.8.8 127.0.0.1 eth0", + "add connection udp <symbolic> <remote_ip> <port> <local_ip> <port> eth0", + "add listener udp lst1 127.0.0.1 9695 eth0", + //"add face", + "add route 3 b001::/16 1", + //"add punting", + //"add strategy", + "add policy b001::/16 webex require avoid prohibit !prohibit neutral !require prefer", + "list connection", // need pluralize + "list listener", + "list face", + "list route", + "list punting", + "list strategy", + "list policy", + "remove connection 1", + "remove listener 1", + //"remove face", + "remove route 1 b001::/16", + //"remove punting", + //"remove policy", + "set debug", + "unset debug", + "set strategy b001::/16 random", // related prefixes (10 max) ? + "set strategy b001::/16 load_balancer", + "set strategy b001::/16 low_latency", + "set strategy b001::/16 replication", + "set strategy b001::/16 bestpath", + "set wldr <on|off> <connection_id>", // on-off vs unset + "cache clear", + "cache store on/off", // set/unset + "cache serve on/off", + "mapme enable on/off", + "mapme discovery on/off", + "mapme timescale 500ms", + "mapme retx 500ms", + "update connection conn1 WT", +}; + +#define array_size(x) sizeof(x) / sizeof(typeof(x[0])) +int main() +{ + for (unsigned i = 0; i < array_size(cmds); i++) { + printf("PARSING [%d] %s\n", i, cmds[i]); + if (parse(cmds[i]) < 0) { + ERROR("Could not parse command: %s\n", cmds[i]); + continue; + } + } + exit(EXIT_SUCCESS); + +ERR: + exit(EXIT_FAILURE); +} +#endif diff --git a/hicn-light/src/hicn/config/parse.h b/hicn-light/src/hicn/config/parse.h new file mode 100644 index 000000000..06269208a --- /dev/null +++ b/hicn-light/src/hicn/config/parse.h @@ -0,0 +1,15 @@ +#ifndef HICNLIGHT_PARSE_CMD +#define HICNLIGHT_PARSE_CMD + +#include <hicn/ctrl/api.h> + +int parse(const char* cmd, hc_command_t* command); +int help(const char* cmd); + +/** + * @brief Convert the action enum to the action name used in the commands (e.g. + * from ACTION_CREATE to "add"). + */ +const char* action_to_cmd_action(hc_action_t action); + +#endif /* HICNLIGHT_PARSE_CMD */ diff --git a/hicn-light/src/hicn/config/symbolicNameTable.c b/hicn-light/src/hicn/config/symbolicNameTable.c deleted file mode 100644 index e5ae81d3e..000000000 --- a/hicn-light/src/hicn/config/symbolicNameTable.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <ctype.h> -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_HashCodeTable.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/config/symbolicNameTable.h> - -struct symblic_name_table { - PARCHashCodeTable *symbolicNameTable; - PARCHashCodeTable *indexToNameTable; -}; - -// ======================================================================================== -// symbolic name table functions - -static bool _symbolicNameEquals(const void *keyA, const void *keyB) { - return (strcasecmp((const char *)keyA, (const char *)keyB) == 0); -} - -static HashCodeType _symbolicNameHash(const void *keyA) { - const char *str = (const char *)keyA; - size_t length = strlen(str); - return parcHash32_Data(str, length); -} - -static bool _connectionIdEquals(const void *keyA, const void *keyB) { - unsigned idA = *((unsigned *)keyA); - unsigned idB = *((unsigned *)keyB); - return (idA == idB); -} - -static HashCodeType _connectionIdHash(const void *keyA) { - unsigned idA = *((unsigned *)keyA); - return parcHash32_Int32(idA); -} - -// ======================================================================================== - -SymbolicNameTable *symbolicNameTable_Create(void) { - SymbolicNameTable *table = parcMemory_Allocate(sizeof(SymbolicNameTable)); - - if (table) { - // key = char * - // value = uint32_t * - table->symbolicNameTable = parcHashCodeTable_Create( - _symbolicNameEquals, _symbolicNameHash, parcMemory_DeallocateImpl, - parcMemory_DeallocateImpl); - table->indexToNameTable = parcHashCodeTable_Create( - _connectionIdEquals, _connectionIdHash, parcMemory_DeallocateImpl, - parcMemory_DeallocateImpl); - } - - return table; -} - -void symbolicNameTable_Destroy(SymbolicNameTable **tablePtr) { - SymbolicNameTable *table = *tablePtr; - parcHashCodeTable_Destroy(&table->symbolicNameTable); - parcHashCodeTable_Destroy(&table->indexToNameTable); - parcMemory_Deallocate((void **)&table); - *tablePtr = NULL; -} - -static char *_createKey(const char *symbolicName) { - char *key = parcMemory_StringDuplicate(symbolicName, strlen(symbolicName)); - - // convert key to upper case - char *p = key; - - // keeps looping until the first null - while ((*p = toupper(*p))) { - p++; - } - return key; -} - -bool symbolicNameTable_Exists(SymbolicNameTable *table, - const char *symbolicName) { - parcAssertNotNull(table, "Parameter table must be non-null"); - parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null"); - - char *key = _createKey(symbolicName); - bool found = (parcHashCodeTable_Get(table->symbolicNameTable, key) != NULL); - parcMemory_Deallocate((void **)&key); - return found; -} - -void symbolicNameTable_Remove(SymbolicNameTable *table, - const char *symbolicName) { - parcAssertNotNull(table, "Parameter table must be non-null"); - parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null"); - - char *key = _createKey(symbolicName); - - unsigned id = symbolicNameTable_Get(table, symbolicName); - uint32_t *value = parcMemory_Allocate(sizeof(uint32_t)); - *value = id; - - parcHashCodeTable_Del(table->symbolicNameTable, key); - parcHashCodeTable_Del(table->indexToNameTable, value); - parcMemory_Deallocate((void **)&key); - parcMemory_Deallocate((void **)&value); -} - -bool symbolicNameTable_Add(SymbolicNameTable *table, const char *symbolicName, - unsigned connid) { - parcAssertNotNull(table, "Parameter table must be non-null"); - parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null"); - parcAssertTrue(connid < UINT32_MAX, "Parameter connid must be less than %u", - UINT32_MAX); - - char *key1 = _createKey(symbolicName); - - uint32_t *value1 = parcMemory_Allocate(sizeof(uint32_t)); - *value1 = connid; - - bool success = parcHashCodeTable_Add(table->symbolicNameTable, key1, value1); - if (!success) - goto ERR_NAME; - - char *key2 = _createKey(symbolicName); - - uint32_t *value2 = parcMemory_Allocate(sizeof(uint32_t)); - *value2 = connid; - - success = parcHashCodeTable_Add(table->indexToNameTable, value2, key2); - if (!success) - goto ERR_INDEX; - - goto END; - -ERR_INDEX: - parcMemory_Deallocate((void **)&key2); - parcMemory_Deallocate((void **)&value2); - parcHashCodeTable_Del(table->symbolicNameTable, key1); -ERR_NAME: - parcMemory_Deallocate((void **)&key1); - parcMemory_Deallocate((void **)&value1); -END: - return success; - -} - -unsigned symbolicNameTable_Get(SymbolicNameTable *table, - const char *symbolicName) { - parcAssertNotNull(table, "Parameter table must be non-null"); - parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null"); - - unsigned connid = UINT32_MAX; - - char *key = _createKey(symbolicName); - - uint32_t *value = parcHashCodeTable_Get(table->symbolicNameTable, key); - if (value) - connid = *value; - - parcMemory_Deallocate((void **)&key); - return connid; -} - -const char *symbolicNameTable_GetNameByIndex(SymbolicNameTable *table, - unsigned id) { - parcAssertNotNull(table, "Parameter table must be non-null"); - - uint32_t *value = parcMemory_Allocate(sizeof(uint32_t)); - *value = id; - - const char *name = parcHashCodeTable_Get(table->indexToNameTable, value); - if (name == NULL) name = ""; - - parcMemory_Deallocate((void **)&value); - return name; -} diff --git a/hicn-light/src/hicn/config/symbolicNameTable.h b/hicn-light/src/hicn/config/symbolicNameTable.h deleted file mode 100644 index 69919cf00..000000000 --- a/hicn-light/src/hicn/config/symbolicNameTable.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file symbolicNameTable.h - * @brief The symbolic name table maps a string name to a connection id - * - * When configuring tunnels/connections, the user provides a string name - * (symbolic name) that they will use to refer to that connection. The symblic - * name table translates that symbolic name to a connection id. - * - */ - -#ifndef symbolicNameTable_h -#define symbolicNameTable_h - -struct symblic_name_table; -typedef struct symblic_name_table SymbolicNameTable; - -#include <stdbool.h> - -/** - * Creates a symbolic name table - * - * Allocates a SymbolicNameTable, which will store the symbolic names - * in a hash table. - * - * @retval non-null An allocated SymbolicNameTable - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -SymbolicNameTable *symbolicNameTable_Create(void); - -/** - * Destroys a name table - * - * All keys and data are released. - * - * @param [in,out] tablePtr A pointer to a SymbolicNameTable, which will be - * NULL'd - * - * Example: - * @code - * <#example#> - * @endcode - */ -void symbolicNameTable_Destroy(SymbolicNameTable **tablePtr); - -/** - * Checks if the name (case insensitive) is in the table - * - * Does a case-insensitive match to see if the name is in the table - * - * @param [in] table An allocated SymbolicNameTable - * @param [in] symbolicName The name to check for - * - * @retval true The name is in the table - * @retval false The name is not in the talbe - * - * Example: - * @code - * <#example#> - * @endcode - */ -bool symbolicNameTable_Exists(SymbolicNameTable *table, - const char *symbolicName); - -/** - * Adds a (name, connid) pair to the table. - * - * The name is stored case insensitive. The value UINT_MAX is used to indicate - * a non-existent key, so it should not be stored as a value in the table. - * - * @param [in] table An allocated SymbolicNameTable - * @param [in] symbolicName The name to save (will make a copy) - * @param [in] connid The connection id to associate with the name - * - * @retval true The pair was added - * @retval false The pair was not added (likely duplicate key) - * - * Example: - * @code - * <#example#> - * @endcode - */ -bool symbolicNameTable_Add(SymbolicNameTable *table, const char *symbolicName, - unsigned connid); - -/** - * Returns the connection id associated with the symbolic name - * - * This function will look for the given name (case insensitive) and return the - * corresponding connid. If the name is not in the table, the function will - * return UINT_MAX. - * - * @param [in] table An allocated SymbolicNameTable - * @param [in] symbolicName The name to retrieve - * - * @retval UINT_MAX symbolicName not found - * @retval number the corresponding connid. - * - * Example: - * @code - * <#example#> - * @endcode - */ -unsigned symbolicNameTable_Get(SymbolicNameTable *table, - const char *symbolicName); - -void symbolicNameTable_Remove(SymbolicNameTable *table, - const char *symbolicName); -const char *symbolicNameTable_GetNameByIndex(SymbolicNameTable *table, - unsigned id); - -#endif /* defined(symbolicNameTable_h) */ diff --git a/hicn-light/src/hicn/content_store/CMakeLists.txt b/hicn-light/src/hicn/content_store/CMakeLists.txt index aaf256118..f7cfc26b6 100644 --- a/hicn-light/src/hicn/content_store/CMakeLists.txt +++ b/hicn-light/src/hicn/content_store/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -12,20 +12,12 @@ # limitations under the License. list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreEntry.h - ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreInterface.h - ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreLRU.h - ${CMAKE_CURRENT_SOURCE_DIR}/listTimeOrdered.h - ${CMAKE_CURRENT_SOURCE_DIR}/listLRU.h + ${CMAKE_CURRENT_SOURCE_DIR}/lru.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreInterface.c - ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreLRU.c - ${CMAKE_CURRENT_SOURCE_DIR}/listLRU.c - ${CMAKE_CURRENT_SOURCE_DIR}/listTimeOrdered.c - ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreEntry.c + ${CMAKE_CURRENT_SOURCE_DIR}/lru.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/content_store/contentStoreEntry.c b/hicn-light/src/hicn/content_store/contentStoreEntry.c deleted file mode 100644 index 45f98881e..000000000 --- a/hicn-light/src/hicn/content_store/contentStoreEntry.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_Memory.h> -#include <hicn/content_store/contentStoreEntry.h> - -#include <parc/assert/parc_Assert.h> - -const uint64_t contentStoreEntry_MaxExpiryTime = UINT64_MAX; - -struct contentstore_entry { - Message *message; - ListLruEntry *lruEntry; - unsigned refcount; - bool hasExpiryTimeTicks; - uint64_t expiryTimeTicks; -}; - -ContentStoreEntry *contentStoreEntry_Create(Message *contentMessage, - ListLru *listLRU) { - parcAssertNotNull(contentMessage, "Parameter objectMessage must be non-null"); - - ContentStoreEntry *entry = - parcMemory_AllocateAndClear(sizeof(ContentStoreEntry)); - parcAssertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ContentStoreEntry)); - entry->message = message_Acquire(contentMessage); - entry->refcount = 1; - - if (listLRU != NULL) { - entry->lruEntry = listLRU_NewHeadEntry(listLRU, entry); - } - - entry->hasExpiryTimeTicks = message_HasContentExpiryTime(contentMessage); - - if (entry->hasExpiryTimeTicks) { - entry->expiryTimeTicks = message_GetContentExpiryTimeTicks(contentMessage); - } - - return entry; -} - -ContentStoreEntry *contentStoreEntry_Acquire( - const ContentStoreEntry *original) { - parcAssertNotNull(original, "Parameter must be non-null"); - ((ContentStoreEntry *)original)->refcount++; - return (ContentStoreEntry *)original; -} - -void contentStoreEntry_Release(ContentStoreEntry **entryPtr) { - parcAssertNotNull(entryPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*entryPtr, - "Parameter must dereference to non-null pointer"); - - ContentStoreEntry *entry = *entryPtr; - parcAssertTrue(entry->refcount > 0, "Illegal state: has refcount of 0"); - - entry->refcount--; - if (entry->refcount == 0) { - if (entry->lruEntry) { - listLRU_EntryDestroy(&entry->lruEntry); - } - message_Release(&entry->message); - parcMemory_Deallocate((void **)&entry); - } - *entryPtr = NULL; -} - -Message *contentStoreEntry_GetMessage(const ContentStoreEntry *storeEntry) { - parcAssertNotNull(storeEntry, "Parameter must be non-null"); - return storeEntry->message; -} - -bool contentStoreEntry_HasExpiryTimeTicks(const ContentStoreEntry *storeEntry) { - parcAssertNotNull(storeEntry, "Parameter must be non-null"); - return storeEntry->hasExpiryTimeTicks; -} - -uint64_t contentStoreEntry_GetExpiryTimeTicks( - const ContentStoreEntry *storeEntry) { - parcAssertNotNull(storeEntry, "Parameter must be non-null"); - parcAssertTrue(storeEntry->hasExpiryTimeTicks, - "storeEntry has no ExpiryTimeTicks. Did you call " - "contentStoreEntry_HasExpiryTimeTicks() first?"); - return storeEntry->expiryTimeTicks; -} - -int contentStoreEntry_CompareExpiryTime(const ContentStoreEntry *value1, - const ContentStoreEntry *value2) { - // A signum comparison. negative if key 1 is smaller, 0 if key1 == key2, - // greater than 0 if key1 is bigger. - - ContentStoreEntry *v1 = (ContentStoreEntry *)value1; - ContentStoreEntry *v2 = (ContentStoreEntry *)value2; - - if (v1->expiryTimeTicks < v2->expiryTimeTicks) { - return -1; - } else if (v1->expiryTimeTicks > v2->expiryTimeTicks) { - return +1; - } else { - // At this point, the times are the same. Use the address of the message as - // the decider. This allows us to store multiple messages with the same - // expiry/cache time. - if (v1->message < v2->message) { - return -1; - } else if (v1->message > v2->message) { - return +1; - } - } - - return 0; // The same message has been encountered. -} - -void contentStoreEntry_MoveToHead(ContentStoreEntry *storeEntry) { - parcAssertNotNull(storeEntry, "Parameter must be non-null"); - parcAssertNotNull(storeEntry->lruEntry, - "ContentStoreEntry is not attached to an ListLru"); - if (storeEntry->lruEntry) { - listLRU_EntryMoveToHead(storeEntry->lruEntry); - } -} diff --git a/hicn-light/src/hicn/content_store/contentStoreEntry.h b/hicn-light/src/hicn/content_store/contentStoreEntry.h deleted file mode 100644 index 4f0fd19c1..000000000 --- a/hicn-light/src/hicn/content_store/contentStoreEntry.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 contentStoreEntry_h -#define contentStoreEntry_h - -#include <hicn/content_store/listLRU.h> -#include <hicn/core/message.h> - -struct contentstore_entry; -typedef struct contentstore_entry ContentStoreEntry; - -/** - * The max time allowed for an ExpiryTime. Will never be exceeded. - */ -extern const uint64_t contentStoreEntry_MaxExpiryTime; - -/** - * Creates a new `ContentStoreEntry` instance, acquiring a reference to the - * supplied `Message`. - * - * @param message the message to store - * @param listLRU the LRU list that this entry will be stored in. - * @return A newly created `ContentStoreEntry` instance that must eventually be - * released by calling - * {@link contentStoreEntry_Release}. - * - * @see contentStoreEntry_Release - */ -ContentStoreEntry *contentStoreEntry_Create(Message *objectMessage, - ListLru *listLRU); - -/** - * Returns a reference counted copy of the supplied `ContentStoreEntry`. - * - * @param original the ContentStoreEntry to return a reference to. - * @return Reference counted copy, must call - * <code>contentStoreEntry_Destroy()</code> on it. - */ -ContentStoreEntry *contentStoreEntry_Acquire(const ContentStoreEntry *original); - -/** - * Releases one reference count and destroys object when reaches zero - * - * @param [in,out] entryPtr A pointer to an allocated ContentStoreEntry - * - */ -void contentStoreEntry_Release(ContentStoreEntry **entryPtr); - -/** - * Returns a pointer to the contained {@link Message}. - * The caller must called {@link message_Acquire()} if they want to keep a - * reference to the returned message. - * - * @param storeEntry the ContentStoreEntry from which to retrieve the `Message` - * pointer. - * @return the address of the `Message` contained in the storeEntry. - * @see message_Acquire - */ -Message *contentStoreEntry_GetMessage(const ContentStoreEntry *storeEntry); - -/** - * Return true if the message stored in this `ContentStoreEntry` has an - * ExpiryTime. - * - * @param storeEntry the ContentStoreEntry containing the message. - * @return true if the referenced message has an ExpiryTime. False, otherwise. - */ -bool contentStoreEntry_HasExpiryTimeTicks(const ContentStoreEntry *storeEntry); - -/** - * Return the ExpiryTime stored in this `ContentStoreEntry`. - * - * @param storeEntry the ContentStoreEntry from which to retrieve the `Message` - * pointer. - * @return the address of the `Message` contained in the storeEntry. - */ -uint64_t contentStoreEntry_GetExpiryTimeTicks( - const ContentStoreEntry *storeEntry); - -/** - * A signum function comparing two `ContentStoreEntry` instances, using their - * ExpiryTime and, if necessary, the addresses of the referenced Message. In - * other words, if two ContentStoreEntries have the same ExpiryTime, the - * comparison will then be made on the memory addresses of the Messages - * referenced by the ContentStoreEntrys. So, the only way two ContentStoreEntrys - * will compare equally (0) is if they both have the same ExpiryTime and - * reference the same Message. - * - * Used to determine the ordering relationship of two `ContentStoreEntry` - * instances. This is used by the {@link ListTimeOrdered} to keep a list of - * ContentStoreEntrys, sorted by ExpiryTime. - * - * @param [in] storeEntry1 A pointer to a `ContentStoreEntry` instance. - * @param [in] storeEntry2 A pointer to a `ContentStoreEntry` instance to be - * compared to `storeEntry1`. - * - * @return 0 if `storeEntry1` and `storeEntry2` are equivalent - * @return < 0 if `storeEntry1` < `storeEntry2` - * @return > 0 if `storeEntry1` > `storeEntry2` - * - * Example: - * @code - * { - * ContentStoreEntry *entry1 = contentStoreEntry_Create(...); - * ContentStoreEntry *entry2 = contentStoreEntry_Create(...); - * - * int val = contentStoreEntry_CompareExpiryTime(entry1, entry2); - * if (val < 0) { - * // entry1 has a lower ExpiryTime, or the same ExpiryTime as entry2 - * and a different message. } else if (val > 0) { - * // entry2 has a lower ExpiryTime, or the same ExpiryTime as entry1 - * and a different message. } else { - * // entry1 and entry2 have the same ExpiryTime AND the same message. - * } - * - * contentStoreEntry_Release(&entry1); - * contentStoreEntry_Release(&entry2); - * - * } - * @endcode - */ -int contentStoreEntry_CompareExpiryTime(const ContentStoreEntry *storeEntry1, - const ContentStoreEntry *storeEntry2); - -/** - * Move this entry to the head of the LRU list - * - * Moves the entry to the head of the LRU list it was created with - * - * @param [in] storeEntry An allocated ContenstoreEntry - */ -void contentStoreEntry_MoveToHead(ContentStoreEntry *storeEntry); -#endif // contentStoreEntry_h diff --git a/hicn-light/src/hicn/content_store/contentStoreInterface.c b/hicn-light/src/hicn/content_store/contentStoreInterface.c deleted file mode 100644 index 2f5ddb8c2..000000000 --- a/hicn-light/src/hicn/content_store/contentStoreInterface.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/content_store/contentStoreInterface.h> - -void contentStoreInterface_Release(ContentStoreInterface **storeImplPtr) { - (*storeImplPtr)->release(storeImplPtr); -} - -bool contentStoreInterface_PutContent(ContentStoreInterface *storeImpl, - Message *content, - uint64_t currentTimeTicks) { - return storeImpl->putContent(storeImpl, content, currentTimeTicks); -} - -bool contentStoreInterface_RemoveContent(ContentStoreInterface *storeImpl, - Message *content) { - return storeImpl->removeContent(storeImpl, content); -} - -Message *contentStoreInterface_MatchInterest(ContentStoreInterface *storeImpl, - Message *interest, - uint64_t currentTimeTicks) { - return storeImpl->matchInterest(storeImpl, interest, currentTimeTicks); -} - -size_t contentStoreInterface_GetObjectCapacity( - ContentStoreInterface *storeImpl) { - return storeImpl->getObjectCapacity(storeImpl); -} - -size_t contentStoreInterface_GetObjectCount(ContentStoreInterface *storeImpl) { - return storeImpl->getObjectCount(storeImpl); -} - -void contentStoreInterface_Log(ContentStoreInterface *storeImpl) { - storeImpl->log(storeImpl); -} - -void *contentStoreInterface_GetPrivateData(ContentStoreInterface *storeImpl) { - return storeImpl->_privateData; -} diff --git a/hicn-light/src/hicn/content_store/contentStoreInterface.h b/hicn-light/src/hicn/content_store/contentStoreInterface.h deleted file mode 100644 index b2bc3f919..000000000 --- a/hicn-light/src/hicn/content_store/contentStoreInterface.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 contentStoreInterface_h -#define contentStoreInterface_h - -#include <stdio.h> - -#include <hicn/core/message.h> - -typedef struct contentstore_config { - size_t objectCapacity; -} ContentStoreConfig; - -typedef struct contentstore_interface ContentStoreInterface; - -struct contentstore_interface { - /** - * Place a Message representing a ContentObject into the ContentStore. If - * necessary to make room, remove expired content or content that has exceeded - * the Recommended Cache Time. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * @param content - a pointer to a `Message` to place in the store. - * @param currentTimeTicks - the current time, in hicn-light ticks, since the - * UTC epoch. - */ - bool (*putContent)(ContentStoreInterface *storeImpl, Message *content, - uint64_t currentTimeTicks); - - /** - * The function to call to remove content from the ContentStore. - * It will Release any references that were created when the content was - * placed into the ContentStore. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * @param content - a pointer to a `Message` to remove from the store. - */ - bool (*removeContent)(ContentStoreInterface *storeImpl, Message *content); - - /** - * Given a Message that represents and Interest, try to find a matching - * ContentObject. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * @param interest - a pointer to a `Message` representing the Interest to - * match. - * - * @return a pointer to a Message containing the matching ContentObject - * @return NULL if no matching ContentObject was found - */ - Message *(*matchInterest)(ContentStoreInterface *storeImpl, Message *interest, - uint64_t currentTimeTicks); - - /** - * Return the maximum number of ContentObjects that can be stored in this - * ContentStore. This is a raw count, not based on memory size. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * - * @return the maximum number of ContentObjects that can be stored - */ - size_t (*getObjectCapacity)(ContentStoreInterface *storeImpl); - - /** - * Return the number of ContentObjects currently stored in the ContentStore. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * - * @return the current number of ContentObjects in the ContentStore - */ - size_t (*getObjectCount)(ContentStoreInterface *storeImpl); - - /** - * Log a ContentStore implementation specific version of store-related - * information. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - */ - void (*log)(ContentStoreInterface *storeImpl); - - /** - * Acquire a new reference to the specified ContentStore instance. This - * reference will eventually need to be released by calling {@link - * contentStoreInterface_Release}. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - */ - ContentStoreInterface *(*acquire)(const ContentStoreInterface *storeImpl); - - /** - * Release the ContentStore, which will also Release any references held by - * it. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - */ - void (*release)(ContentStoreInterface **storeImpl); - - /** - * A pointer to opaque private data used by the ContentStore instance - * represented by this instance of ContentStoreInterface. - */ - void *_privateData; -}; - -/** - * Place a Message representing a ContentObject into the ContentStore. If - * necessary to make room, remove expired content or content that has exceeded - * the Recommended Cache Time. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * @param content - a pointer to a `Message` to place in the store. - * - * @param currentTimeTicks - the current time, in hicn-light ticks, since the - * UTC epoch. - */ -bool contentStoreInterface_PutContent(ContentStoreInterface *storeImpl, - Message *content, - uint64_t currentTimeTicks); - -/** - * The function to call to remove content from the ContentStore. - * It will Release any references that were created when the content was placed - * into the ContentStore. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * @param content - a pointer to a `Message` to remove from the store. - */ -bool contentStoreInterface_RemoveContent(ContentStoreInterface *storeImpl, - Message *content); - -/** - * Given a Message that represents and Interest, try to find a matching - * ContentObject. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * @param interest - a pointer to a `Message` representing the Interest to - * match. - * - * @return a pointer to a Message containing the matching ContentObject - * @return NULL if no matching ContentObject was found - */ -Message *contentStoreInterface_MatchInterest(ContentStoreInterface *storeImpl, - Message *interest, - uint64_t currentTimeTicks); - -/** - * Return the maximum number of ContentObjects that can be stored in this - * ContentStore. This is a raw count, not based on memory size. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * - * @return the maximum number of ContentObjects that can be stored - */ -size_t contentStoreInterface_GetObjectCapacity( - ContentStoreInterface *storeImpl); - -/** - * Return the number of ContentObjects currently stored in the ContentStore. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - * - * @return the current number of ContentObjects in the ContentStore - */ -size_t contentStoreInterface_GetObjectCount(ContentStoreInterface *storeImpl); - -/** - * Loga ContentStore implementation specific version of store-related - * information. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - */ -void contentStoreInterface_Log(ContentStoreInterface *storeImpl); - -/** - * Acquire a new reference to the specified ContentStore instance. This - * reference will eventually need to be released by calling {@link - * contentStoreInterface_Release}. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - */ -ContentStoreInterface *contentStoreInterface_Aquire( - const ContentStoreInterface *storeImpl); - -/** - * Release the ContentStore, which will also Release any references held by it. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - */ -void contentStoreInterface_Release(ContentStoreInterface **storeImplPtr); - -/** - * Return a pointer to the data private to this implementation of the - * ContentStore interface. - * - * @param storeImpl - a pointer to this ContentStoreInterface instance. - */ -void *contentStoreInterface_GetPrivateData(ContentStoreInterface *storeImpl); -#endif // contentStoreInterface_h diff --git a/hicn-light/src/hicn/content_store/contentStoreLRU.c b/hicn-light/src/hicn/content_store/contentStoreLRU.c deleted file mode 100644 index 76a2c8659..000000000 --- a/hicn-light/src/hicn/content_store/contentStoreLRU.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 _WIN32 -#include <sys/queue.h> -#endif -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_DisplayIndented.h> -#include <parc/algol/parc_HashCodeTable.h> -#include <parc/algol/parc_Object.h> - -#include <hicn/core/logger.h> - -#include <hicn/content_store/contentStoreLRU.h> - -#include <hicn/content_store/contentStoreEntry.h> -#include <hicn/content_store/contentStoreInterface.h> -#include <hicn/content_store/listLRU.h> -#include <hicn/content_store/listTimeOrdered.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/processor/hashTableFunction.h> - -typedef struct contentstore_stats { - uint64_t countExpiryEvictions; - uint64_t countRCTEvictions; - uint64_t countLruEvictions; - uint64_t countAdds; - uint64_t countHits; - uint64_t countMisses; -} _ContentStoreLRUStats; - -typedef struct contentstore_lru_data { - size_t objectCapacity; - size_t objectCount; - - Logger *logger; - - // This LRU is just for keeping track of insertion and access order. - ListLru *lru; - - ListTimeOrdered *indexByExpirationTime; - - PARCHashCodeTable *storageByName; - - _ContentStoreLRUStats stats; -} _ContentStoreLRU; - -static void _destroyIndexes(_ContentStoreLRU *store) { - if (store->indexByExpirationTime != NULL) { - listTimeOrdered_Release(&(store->indexByExpirationTime)); - } - - if (store->storageByName != NULL) { - parcHashCodeTable_Destroy(&(store->storageByName)); - } - - if (store->lru != NULL) { - listLRU_Destroy(&(store->lru)); - } -} - -static void _contentStoreInterface_Destroy( - ContentStoreInterface **storeImplPtr) { - _ContentStoreLRU *store = contentStoreInterface_GetPrivateData(*storeImplPtr); - - parcObject_Release((PARCObject **)&store); -} - -static bool _contentStoreLRU_Destructor(_ContentStoreLRU **storePtr) { - _ContentStoreLRU *store = *storePtr; - - _destroyIndexes(store); - logger_Release(&store->logger); - - return true; -} - -parcObject_Override(_ContentStoreLRU, PARCObject, - .destructor = (PARCObjectDestructor *) - _contentStoreLRU_Destructor); - -parcObject_ExtendPARCObject(ContentStoreInterface, - _contentStoreInterface_Destroy, NULL, NULL, NULL, - NULL, NULL, NULL); - -static parcObject_ImplementAcquire(_contentStoreLRU, ContentStoreInterface); -static parcObject_ImplementRelease(_contentStoreLRU, ContentStoreInterface); - -static void _hashTableFunction_ContentStoreEntryDestroyer(void **dataPtr) { - contentStoreEntry_Release((ContentStoreEntry **)dataPtr); -} - -static bool _contentStoreLRU_Init(_ContentStoreLRU *store, - ContentStoreConfig *config, Logger *logger) { - bool result = false; - - store->logger = logger_Acquire(logger); - - size_t initialSize = config->objectCapacity * 2; - memset(&store->stats, 0, sizeof(_ContentStoreLRUStats)); - - store->objectCapacity = config->objectCapacity; - store->objectCount = 0; - - // initial size must be at least 1 or else the data structures break. - initialSize = (initialSize == 0) ? 1 : initialSize; - - store->indexByExpirationTime = listTimeOrdered_Create( - (TimeOrderList_KeyCompare *)contentStoreEntry_CompareExpiryTime); - - store->storageByName = parcHashCodeTable_Create_Size( - hashTableFunction_MessageNameEquals, - hashTableFunction_MessageNameHashCode, NULL, - _hashTableFunction_ContentStoreEntryDestroyer, initialSize); - - store->lru = listLRU_Create(); - - // If any of the index tables couldn't be allocated, we can't continue. - if ((store->indexByExpirationTime == NULL) || - (store->storageByName == NULL) || (store->lru == NULL)) { - if (logger_IsLoggable(store->logger, LoggerFacility_Processor, - PARCLogLevel_Error)) { - logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Error, - __func__, - "ContentStoreLRU could not be created. Could not allocate all " - "index tables.", - (void *)store, store->objectCapacity); - } - - _destroyIndexes(store); - result = false; - } else { - result = true; - } - return result; -} - -/** - * Remove a ContentStoreEntry from all tables and indices. - */ -static void _contentStoreLRU_PurgeStoreEntry(_ContentStoreLRU *store, - ContentStoreEntry *entryToPurge) { - if (contentStoreEntry_HasExpiryTimeTicks(entryToPurge)) { - listTimeOrdered_Remove(store->indexByExpirationTime, entryToPurge); - } - - Message *content = contentStoreEntry_GetMessage(entryToPurge); - - // This _Del call will call the Release/Destroy on the ContentStoreEntry, - // which will remove it from the LRU as well. - parcHashCodeTable_Del(store->storageByName, content); - - store->objectCount--; -} - -static bool _contentStoreLRU_RemoveLeastUsed(_ContentStoreLRU *store) { - bool result = false; - - if (store->objectCount > 0) { - ListLruEntry *lruEntry = listLRU_PopTail(store->lru); - ContentStoreEntry *storeEntry = - (ContentStoreEntry *)listLRU_EntryGetData(lruEntry); - - if (logger_IsLoggable(store->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log( - store->logger, LoggerFacility_Processor, PARCLogLevel_Debug, __func__, - "ContentStore %p evict message %p by LRU (LRU evictions %" PRIu64 ")", - (void *)store, (void *)contentStoreEntry_GetMessage(storeEntry), - store->stats.countLruEvictions); - } - - _contentStoreLRU_PurgeStoreEntry(store, storeEntry); - - result = true; - } - return result; -} - -static void _evictByStorePolicy(_ContentStoreLRU *store, - uint64_t currentTimeInTicks) { - // We need to make room. Here's the plan: - // 1) Check to see if anything has expired. If so, remove it and we're done. - // If not, 2) Remove the least recently used item. - - ContentStoreEntry *entry = - listTimeOrdered_GetOldest(store->indexByExpirationTime); - if (entry && contentStoreEntry_HasExpiryTimeTicks(entry) && - (currentTimeInTicks > contentStoreEntry_GetExpiryTimeTicks(entry))) { - // Found an expired entry. Remove it, and we're done. - - store->stats.countExpiryEvictions++; - if (logger_IsLoggable(store->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, - "ContentStore %p evict message %p by ExpiryTime (ExpiryTime " - "evictions %" PRIu64 ")", - (void *)store, (void *)contentStoreEntry_GetMessage(entry), - store->stats.countExpiryEvictions); - } - - _contentStoreLRU_PurgeStoreEntry(store, entry); - } else { - store->stats.countLruEvictions++; - _contentStoreLRU_RemoveLeastUsed(store); - } -} - -static bool _contentStoreLRU_PutContent(ContentStoreInterface *storeImpl, - Message *content, - uint64_t currentTimeTicks) - -{ - bool result = false; - _ContentStoreLRU *store = - (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl); - parcAssertNotNull(store, "Parameter store must be non-null"); - parcAssertNotNull(content, "Parameter objectMessage must be non-null"); - - parcAssertTrue(message_GetType(content) == MessagePacketType_ContentObject, - "Parameter objectMessage must be a Content Object"); - - if (store->objectCapacity == 0) { - return false; - } - - ContentStoreEntry *storeEntry = parcHashCodeTable_Get(store->storageByName, content); - if(storeEntry){ - _contentStoreLRU_PurgeStoreEntry(store, storeEntry); - } - - uint64_t expiryTimeTicks = contentStoreEntry_MaxExpiryTime; - - if (message_HasContentExpiryTime(content)) { - expiryTimeTicks = message_GetContentExpiryTimeTicks(content); - } - // Don't add anything that's already expired or has exceeded RCT. - if (currentTimeTicks >= expiryTimeTicks) { - return false; - } - - if (store->objectCount >= store->objectCapacity) { - // Store is full. Need to make room. - _evictByStorePolicy(store, currentTimeTicks); - } - - // And now add a new entry to the head of the LRU. - - ContentStoreEntry *entry = contentStoreEntry_Create(content, store->lru); - - if (entry != NULL) { - if (parcHashCodeTable_Add(store->storageByName, content, entry)) { - if (contentStoreEntry_HasExpiryTimeTicks(entry)) { - listTimeOrdered_Add(store->indexByExpirationTime, entry); - } - - store->objectCount++; - store->stats.countAdds++; - - if (logger_IsLoggable(store->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, - "ContentStoreLRU %p saved message %p (object count %" PRIu64 - ")", - (void *)store, (void *)content, store->objectCount); - } - - result = true; - } else { - // Free what we just created, but did not add. 'entry' has ownership of - // 'copy', and so will call _Release() on it - contentStoreEntry_Release(&entry); - - if (logger_IsLoggable(store->logger, LoggerFacility_Processor, - PARCLogLevel_Warning)) { - logger_Log(store->logger, LoggerFacility_Processor, - PARCLogLevel_Warning, __func__, - "ContentStoreLRU %p failed to add message %p to hash table", - (void *)store, (void *)content); - } - } - } - - return result; -} - -static Message *_contentStoreLRU_MatchInterest(ContentStoreInterface *storeImpl, - Message *interest, - uint64_t currentTimeTicks) { - Message *result = NULL; - - _ContentStoreLRU *store = - (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl); - - parcAssertNotNull(store, "Parameter store must be non-null"); - parcAssertNotNull(interest, "Parameter interestMessage must be non-null"); - parcAssertTrue(message_GetType(interest) == MessagePacketType_Interest, - "Parameter interestMessage must be an Interest"); - - PARCHashCodeTable *table; - table = store->storageByName; - - ContentStoreEntry *storeEntry = parcHashCodeTable_Get(table, interest); - - bool foundEntry = false; - - if (storeEntry) { - if (contentStoreEntry_HasExpiryTimeTicks(storeEntry) && - contentStoreEntry_GetExpiryTimeTicks(storeEntry) < currentTimeTicks) { - // the entry is expired, we can remove it - _contentStoreLRU_PurgeStoreEntry(store, storeEntry); - } else { - foundEntry = true; - } - } - - if (foundEntry) { - contentStoreEntry_MoveToHead(storeEntry); - result = contentStoreEntry_GetMessage(storeEntry); - - store->stats.countHits++; - - if (logger_IsLoggable(store->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, - "ContentStoreLRU %p matched interest %p (hits %" PRIu64 - ", misses %" PRIu64 ")", - (void *)store, (void *)interest, store->stats.countHits, - store->stats.countMisses); - } - } else { - store->stats.countMisses++; - - if (logger_IsLoggable(store->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, - "ContentStoreLRU %p missed interest %p (hits %" PRIu64 - ", misses %" PRIu64 ")", - (void *)store, (void *)interest, store->stats.countHits, - store->stats.countMisses); - } - } - - return result; -} - -static bool _contentStoreLRU_RemoveContent(ContentStoreInterface *storeImpl, - Message *content) { - bool result = false; - _ContentStoreLRU *store = - (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl); - - ContentStoreEntry *storeEntry = - parcHashCodeTable_Get(store->storageByName, content); - - if (storeEntry != NULL) { - _contentStoreLRU_PurgeStoreEntry(store, storeEntry); - result = true; - } - - return result; -} - -static void _contentStoreLRU_Log(ContentStoreInterface *storeImpl) { - _ContentStoreLRU *store = - (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl); - - logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_All, - __func__, - "ContentStoreLRU @%p {count = %zu, capacity = %zu {" - "stats = @%p {adds = %" PRIu64 ", hits = %" PRIu64 - ", misses = %" PRIu64 ", LRUEvictons = %" PRIu64 - ", ExpiryEvictions = %" PRIu64 ", RCTEvictions = %" PRIu64 "} }", - store, store->objectCount, store->objectCapacity, &store->stats, - store->stats.countAdds, store->stats.countHits, - store->stats.countMisses, store->stats.countLruEvictions, - store->stats.countExpiryEvictions, store->stats.countRCTEvictions); -} - -static size_t _contentStoreLRU_GetObjectCapacity( - ContentStoreInterface *storeImpl) { - _ContentStoreLRU *store = - (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl); - return store->objectCapacity; -} - -static size_t _contentStoreLRU_GetObjectCount( - ContentStoreInterface *storeImpl) { - _ContentStoreLRU *store = - (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl); - return store->objectCount; -} - -static size_t _contentStoreLRU_SetObjectCapacity( - ContentStoreInterface *storeImpl, size_t newCapacity) { - _ContentStoreLRU *store = - (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl); - return store->objectCapacity = newCapacity; -} - -ContentStoreInterface *contentStoreLRU_Create(ContentStoreConfig *config, - Logger *logger) { - ContentStoreInterface *storeImpl = NULL; - - parcAssertNotNull(logger, "ContentStoreLRU requires a non-NULL logger"); - - storeImpl = parcObject_CreateAndClearInstance(ContentStoreInterface); - - if (storeImpl != NULL) { - storeImpl->_privateData = - parcObject_CreateAndClearInstance(_ContentStoreLRU); - - if (_contentStoreLRU_Init(storeImpl->_privateData, config, logger)) { - storeImpl->putContent = &_contentStoreLRU_PutContent; - storeImpl->removeContent = &_contentStoreLRU_RemoveContent; - - storeImpl->matchInterest = &_contentStoreLRU_MatchInterest; - - storeImpl->getObjectCount = &_contentStoreLRU_GetObjectCount; - storeImpl->getObjectCapacity = &_contentStoreLRU_GetObjectCapacity; - - storeImpl->log = &_contentStoreLRU_Log; - - storeImpl->acquire = &_contentStoreLRU_Acquire; - storeImpl->release = &_contentStoreLRU_Release; - - // Initialize from the config passed to us. - _contentStoreLRU_SetObjectCapacity(storeImpl, config->objectCapacity); - - if (logger_IsLoggable(logger, LoggerFacility_Processor, - PARCLogLevel_Info)) { - logger_Log(logger, LoggerFacility_Processor, PARCLogLevel_Info, - __func__, "ContentStoreLRU %p created with capacity %zu", - (void *)storeImpl, - contentStoreInterface_GetObjectCapacity(storeImpl)); - } - } - } else { - parcObject_Release((void **)&storeImpl); - } - - return storeImpl; -} diff --git a/hicn-light/src/hicn/content_store/contentStoreLRU.h b/hicn-light/src/hicn/content_store/contentStoreLRU.h deleted file mode 100644 index 94ec4d6b2..000000000 --- a/hicn-light/src/hicn/content_store/contentStoreLRU.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 contentStoreLRU_h -#define contentStoreLRU_h - -#include <hicn/content_store/contentStoreInterface.h> -#include <hicn/core/logger.h> -#include <stdio.h> - -/** - * Create and Initialize an instance of contentStoreLRU. A newly allocated - * {@link ContentStoreInterface} object is initialized and returned. It must - * eventually be released by calling {@link contentStoreInterface_Release}. - * - * - * @param config An instance of `ContentStoreConfig`, specifying options to be - * applied by the underlying contentStoreLRU instance. - * @param logger An instance of a {@link Logger} to use for logging content - * store events. - * - * @return a newly created contentStoreLRU instance. - * - */ -ContentStoreInterface *contentStoreLRU_Create(ContentStoreConfig *config, - Logger *logger); -#endif // contentStoreLRU_h diff --git a/hicn-light/src/hicn/content_store/listLRU.c b/hicn-light/src/hicn/content_store/listLRU.c deleted file mode 100644 index 242af4078..000000000 --- a/hicn-light/src/hicn/content_store/listLRU.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 _WIN32 -#include <sys/queue.h> -#endif -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/content_store/listLRU.h> - -struct list_lru_entry { - void *userData; - - // always set to the list - ListLru *parentList; - - // indicates if the Entry is currently in the list - bool inList; - - TAILQ_ENTRY(list_lru_entry) list; -}; - -// this defines the TAILQ structure so we can access the tail pointer -TAILQ_HEAD(lru_s, list_lru_entry); - -struct list_lru { - struct lru_s head; - size_t itemsInList; -}; - -void listLRU_EntryDestroy(ListLruEntry **entryPtr) { - parcAssertNotNull(entryPtr, - "Parameter entryPtr must be non-null double pointer"); - - ListLruEntry *entry = *entryPtr; - if (entry->inList) { - TAILQ_REMOVE(&entry->parentList->head, entry, list); - parcAssertTrue( - entry->parentList->itemsInList > 0, - "Invalid state, removed entry from list, but itemsInList is 0"); - entry->parentList->itemsInList--; - } - - parcMemory_Deallocate((void **)&entry); - *entryPtr = NULL; -} - -void listLRU_EntryMoveToHead(ListLruEntry *entry) { - parcAssertNotNull(entry, "Parameter entry must be non-null"); - - TAILQ_REMOVE(&entry->parentList->head, entry, list); - TAILQ_INSERT_HEAD(&entry->parentList->head, entry, list); -} - -void *listLRU_EntryGetData(ListLruEntry *entry) { return entry->userData; } - -ListLru *listLRU_Create() { - ListLru *list = parcMemory_AllocateAndClear(sizeof(ListLru)); - parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListLru)); - list->itemsInList = 0; - TAILQ_INIT(&list->head); - return list; -} - -void listLRU_Destroy(ListLru **lruPtr) { - parcAssertNotNull(lruPtr, "Parameter lruPtr must be non-null double pointer"); - - ListLru *lru = *lruPtr; - - ListLruEntry *entry = TAILQ_FIRST(&lru->head); - while (entry != NULL) { - ListLruEntry *next = TAILQ_NEXT(entry, list); - listLRU_EntryDestroy(&entry); - entry = next; - } - - parcMemory_Deallocate((void **)&lru); - *lruPtr = NULL; -} - -ListLruEntry *listLRU_NewHeadEntry(ListLru *lru, void *data) { - parcAssertNotNull(lru, "Parameter lru must be non-null"); - parcAssertNotNull(data, "Parameter data must be non-null"); - - ListLruEntry *entry = parcMemory_AllocateAndClear(sizeof(ListLruEntry)); - parcAssertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListLruEntry)); - entry->userData = data; - entry->parentList = lru; - entry->inList = true; - - TAILQ_INSERT_HEAD(&lru->head, entry, list); - lru->itemsInList++; - - return entry; -} - -ListLruEntry *listLRU_PopTail(ListLru *lru) { - parcAssertNotNull(lru, "Parameter lru must be non-null"); - - ListLruEntry *entry = TAILQ_LAST(&lru->head, lru_s); - - if (entry) { - parcAssertTrue( - lru->itemsInList > 0, - "Invalid state, removed entry from list, but itemsInList is 0"); - lru->itemsInList--; - TAILQ_REMOVE(&lru->head, entry, list); - entry->inList = false; - } - - return entry; -} - -size_t listLRU_Length(const ListLru *lru) { - parcAssertNotNull(lru, "Parameter lru must be non-null"); - return lru->itemsInList; -} diff --git a/hicn-light/src/hicn/content_store/listLRU.h b/hicn-light/src/hicn/content_store/listLRU.h deleted file mode 100644 index 75f698b61..000000000 --- a/hicn-light/src/hicn/content_store/listLRU.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file listLRU.h - * @brief Maintains an LRU for the content store - * - * An LRU list is make up of LRU entries. The entries are bound to the list. - * The user of the list is reponsible for knowing when there's too many things - * and wants to remove one. The LRU list will grow without bound otherwise. - * - * The LRU list is meant to be used as an auxiliary data structure, not the - * primary storage of data elements. - * - */ - -#ifndef listLRU_h -#define listLRU_h - -struct list_lru_entry; -typedef struct list_lru_entry ListLruEntry; - -struct list_lru; -typedef struct list_lru ListLru; - -/** - * @function lruEntry_Destroy - * @abstract Destroys and element. This will also remove it from the list. - */ -void listLRU_EntryDestroy(ListLruEntry **entryPtr); - -/** - * @function listLRU_EntryMoveToHead - * @abstract move an element to head - */ -void listLRU_EntryMoveToHead(ListLruEntry *entry); - -/** - * @function lruEntry_GetData - * @abstract Returns the user-supplied opaque data when the entry was created - */ -void *listLRU_EntryGetData(ListLruEntry *entry); - -/** - * @function listLRU_Create - * @abstract Creates a new Least-Recently-Used list - */ -ListLru *listLRU_Create(); - -/** - * @function listLRU_Destroy - * @abstract Destroys a list and frees all the elements in it - */ -void listLRU_Destroy(ListLru **listPtr); - -/** - * Returns the number of items in the list - * - * @param [in] lru An allocated ListLru - * @retval number The number of items in the LRU list - */ -size_t listLRU_Length(const ListLru *lru); - -/** - * @function listLRU_NewHeadEntry - * @abstract Creates a new entry for the list. It is inserted at the head of - * the list. - */ -ListLruEntry *listLRU_NewHeadEntry(ListLru *lru, void *data); - -/** - * @function listLRU_PopTail - * @abstract Removes the tail element from the list and returns it to the user - * @discussion - * Pops the tail element. The user should examine its data to destroy their - * tail object, then call <code>LruEntry_Destroy()</code> to free the - * LRU entry. - * - * @return The tail element, or NULL for an empty list - */ -ListLruEntry *listLRU_PopTail(ListLru *list); -#endif // listLRU_h diff --git a/hicn-light/src/hicn/content_store/listTimeOrdered.c b/hicn-light/src/hicn/content_store/listTimeOrdered.c deleted file mode 100644 index 690c6e412..000000000 --- a/hicn-light/src/hicn/content_store/listTimeOrdered.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <hicn/content_store/listTimeOrdered.h> - -#include <parc/algol/parc_Object.h> -#include <parc/algol/parc_TreeRedBlack.h> - -/** - * A list of ContentStoreEntrys, kept in sorted order by time. The ordering is - * calculated by a key compare function (e.g. {@link TimeOrderList_KeyCompare}), - * passed in. - * - * This container does not hold references to the objects that it contains. In - * other words, it does not Acquire() the Messages that are placed in it. That - * reference count is managed by the owning ContentStore. This is purely an - * index, and provides an easy to way index Messages based on a specified time - * value. Typically, that would be the Expiration Time. - * - * It maintains a tree, sorted by the time values passed in to the Add() - * function. It does not manage capacity, and can grow uncontrollably if the - * owning ContentStore does not manage it. Items are indexed first by time, then - * address of the Message (just as a distringuishing attribute). This allows us - * to store multiple items with the same expiration time. - */ - -struct list_timeordered { - PARCTreeRedBlack *timeOrderedTree; -}; - -static void _finalRelease(ListTimeOrdered **listP) { - ListTimeOrdered *list = *listP; - parcTreeRedBlack_Destroy(&list->timeOrderedTree); -} - -parcObject_ExtendPARCObject(ListTimeOrdered, _finalRelease, NULL, NULL, NULL, - NULL, NULL, NULL); - -parcObject_ImplementAcquire(listTimeOrdered, ListTimeOrdered); - -parcObject_ImplementRelease(listTimeOrdered, ListTimeOrdered); - -ListTimeOrdered *listTimeOrdered_Create( - TimeOrderList_KeyCompare *keyCompareFunction) { - ListTimeOrdered *result = parcObject_CreateInstance(ListTimeOrdered); - if (NULL != result) { - result->timeOrderedTree = - parcTreeRedBlack_Create(keyCompareFunction, // keyCompare - NULL, // keyFree - NULL, // keyCopy - NULL, // valueEquals - NULL, // valueFree - NULL); // valueCopy - } - return result; -} - -void listTimeOrdered_Add(ListTimeOrdered *list, ContentStoreEntry *entry) { - parcTreeRedBlack_Insert(list->timeOrderedTree, entry, entry); -} - -ContentStoreEntry *listTimeOrdered_GetOldest(ListTimeOrdered *list) { - return parcTreeRedBlack_FirstKey(list->timeOrderedTree); -} - -bool listTimeOrdered_Remove(ListTimeOrdered *list, - ContentStoreEntry *storeEntry) { - bool result = false; - - ContentStoreEntry *entry = (ContentStoreEntry *)parcTreeRedBlack_Remove( - list->timeOrderedTree, storeEntry); - if (entry != NULL) { - result = true; - } - return result; -} - -size_t listTimeOrdered_Length(ListTimeOrdered *list) { - return (size_t)parcTreeRedBlack_Size(list->timeOrderedTree); -} diff --git a/hicn-light/src/hicn/content_store/listTimeOrdered.h b/hicn-light/src/hicn/content_store/listTimeOrdered.h deleted file mode 100644 index 325e7c0d4..000000000 --- a/hicn-light/src/hicn/content_store/listTimeOrdered.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 listTimeOrdered_h -#define listTimeOrdered_h - -#include <parc/algol/parc_TreeRedBlack.h> -#include <hicn/content_store/contentStoreEntry.h> -#include <hicn/core/message.h> -#include <stdio.h> - -struct list_timeordered; -typedef struct list_timeordered ListTimeOrdered; - -/** - * A signum function that takes two instances of ContentStoreEntrys and - * returns a value based on their relative values. - */ -typedef PARCTreeRedBlack_KeyCompare TimeOrderList_KeyCompare; - -/** - * Create a new instance of `ListTimeOrdered` that will maintain the order of - * its list items using the supplied `keyCompareFunction`. - * - * The newly created `ListTimeOrdered` must eventually be released by calling - * {@link listTimeOrdered_Release}. - * - * @param keyCompareFunction the signum comparison function to use to sort - * stored items. - * @return a new instance of `TimeOrderList`. - * @return NULL if the new instance couldn't be created. - * - */ -ListTimeOrdered *listTimeOrdered_Create( - TimeOrderList_KeyCompare *keyCompareFunction); - -/** - * Release a previously acquired reference to the specified instance, - * decrementing the reference count for the instance. - * - * The pointer to the instance is set to NULL as a side-effect of this function. - * - * If the invocation causes the last reference to the instance to be released, - * the instance is deallocated and the instance's implementation will perform - * additional cleanup and release other privately held references. - * - */ -void listTimeOrdered_Release(ListTimeOrdered **listP); - -/** - * Add a {@link ContentStoreEntry} instance to the specified list. Note that a - * new refernece to the specified `storeEntry` is not acquired. - * - * @param list the list instance into which to add the specified storeEntry. - * @param storeEntry the storeEntry instance to add. - * - */ -void listTimeOrdered_Add(ListTimeOrdered *list, ContentStoreEntry *storeEntry); - -/** - * Remove a {@link ContentStoreEntry} instance from the specified list. - * - * @param list the list instance from which to remove the specified storeEntry. - * @param storeEntry the storeEntry instance to remove. - * @return true if the removal was succesful. - * @return false if the removal was not succesful. - * - */ -bool listTimeOrdered_Remove(ListTimeOrdered *list, - ContentStoreEntry *storeEntry); - -/** - * Return the oldest {@link ContentStoreEntry} instance in this list. That is, - * the one with the smallest time value. - * - * @param list the list instance from which to retrieve the oldest storeEntry. - * @param the oldest `ContentStoreEntry` in the list - * @param NULL if no `ContentStoreEntry` was available. - * - */ -ContentStoreEntry *listTimeOrdered_GetOldest(ListTimeOrdered *list); - -/** - * Return the number of items currently stored in the list. - * - * @param list the `ListTimeOrdered` instance from which to retrieve the count. - * @return the number of items in the list. - * - */ -size_t listTimeOrdered_Length(ListTimeOrdered *list); -#endif /* defined(listTimeOrdered_h) */ diff --git a/hicn-light/src/hicn/content_store/lru.c b/hicn-light/src/hicn/content_store/lru.c new file mode 100644 index 000000000..2f1fb9427 --- /dev/null +++ b/hicn-light/src/hicn/content_store/lru.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2021 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 _WIN32 +#include <sys/queue.h> +#endif + +#include <hicn/util/log.h> + +#include <hicn/hicn-light/config.h> +#include <stdio.h> + +#include <hicn/core/packet_cache.h> +#include "lru.h" + +void cs_lru_initialize(cs_t *cs) { + /* We start with an empty double-linked list */ + cs->lru.head = INVALID_ENTRY_ID; + cs->lru.tail = INVALID_ENTRY_ID; +} + +void cs_lru_finalize(cs_t *cs) { + // Nothing to do +} + +cs_entry_t *_cs_entry_at(pkt_cache_t *pkt_cache, off_t entry_id) { + pkt_cache_entry_t *entry = pkt_cache_entry_at(pkt_cache, entry_id); + assert(entry->entry_type == PKT_CACHE_CS_TYPE); + return &entry->u.cs_entry; +} + +/** + * Remove a cs_entry_t from all tables and indices. + */ +static int cs_lru_remove_entry(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *entry) { + assert(pkt_cache); + assert(entry); + + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + cs_t *cs = pkt_cache_get_cs(pkt_cache); + cs_entry_t *cs_entry = &entry->u.cs_entry; + + // If node to be deleted is head node + if (cs->lru.head == entry_id) cs->lru.head = cs_entry->lru.next; + + // If node to be deleted is tail node + if (cs->lru.tail == entry_id) cs->lru.tail = cs_entry->lru.prev; + + // If node to be deleted is not the last node + if (cs_entry->lru.next != INVALID_ENTRY_ID) { + cs_entry_t *next_cs_entry = _cs_entry_at(pkt_cache, cs_entry->lru.next); + assert(next_cs_entry); + next_cs_entry->lru.prev = cs_entry->lru.prev; + } + + // If node to be deleted is not the first node + if (cs_entry->lru.prev != INVALID_ENTRY_ID) { + cs_entry_t *prev_entry = _cs_entry_at(pkt_cache, cs_entry->lru.prev); + assert(prev_entry); + prev_entry->lru.next = cs_entry->lru.next; + } + + cs->stats.lru.countLruDeletions++; + return LRU_SUCCESS; +} + +/** + * @brief LRU processing related to the insertion of a new entry in the content + * store (helper). + * @param[in] cs Content store. + * @param[in] entry_id Identifier of the entry in the content store entry pool. + * @param[in] is_update Boolean value to distinguish update from add operations + * since an update involves removing an entry and adding it again + * + * @return int Error code : 0 if succesful, a negative value otherwise. + * + * NOTE: + * - We insert the new element at the head of the double-linked list. + */ +int _cs_lru_add_entry(pkt_cache_t *pkt_cache, off_t entry_id, bool is_update) { + assert(pkt_cache); + + cs_t *cs = pkt_cache_get_cs(pkt_cache); + cs_entry_t *entry = _cs_entry_at(pkt_cache, entry_id); + assert(entry); + + // Add at the front of the LRU doubly linked list + if (cs->lru.head != INVALID_ENTRY_ID) { + cs_entry_t *head_entry = _cs_entry_at(pkt_cache, cs->lru.head); + assert(head_entry->lru.prev == INVALID_ENTRY_ID); + head_entry->lru.prev = entry_id; + + entry->lru.next = cs->lru.head; + entry->lru.prev = INVALID_ENTRY_ID; + + cs->lru.head = entry_id; + } else { /* The list is empty */ + assert(cs->lru.tail == INVALID_ENTRY_ID); + + entry->lru.next = INVALID_ENTRY_ID; + entry->lru.prev = INVALID_ENTRY_ID; + cs->lru.head = cs->lru.tail = entry_id; + } + if (!is_update) cs->stats.lru.countAdds++; + + // Handle LRU eviction + if (cs->num_entries > cs->max_size) { + DEBUG("LRU eviction"); + cs->stats.lru.countLruEvictions++; + + // Remove from LRU tail + pkt_cache_entry_t *tail = pkt_cache_entry_at(pkt_cache, cs->lru.tail); + cs_lru_remove_entry(pkt_cache, tail); + return LRU_EVICTION; + } + + return LRU_SUCCESS; +} + +/** + * @brief LRU processing related to the insertion of a new entry in the content + * store. + * @param[in] cs Content store. + * @param[in] entry_id Identifier of the entry in the content store entry pool. + * + * @return int Error code : 0 if succesful, a negative value otherwise. + * + * NOTE: + * - We insert the new element at the head of the double-linked list. + */ +static int cs_lru_add_entry(pkt_cache_t *pkt_cache, off_t entry_id) { + return _cs_lru_add_entry(pkt_cache, entry_id, false); +} + +/** + * Move a cs_entry_t to the LRU head. + */ +static void cs_lru_update_entry(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *entry) { + assert(pkt_cache); + assert(entry); + + cs_t *cs = pkt_cache_get_cs(pkt_cache); + cs->stats.lru.countUpdates++; + + // Remove from LRU + cs_lru_remove_entry(pkt_cache, entry); + + // Attach at the LRU head + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + _cs_lru_add_entry(pkt_cache, entry_id, true); +} + +DECLARE_CS(lru); diff --git a/hicn-light/src/hicn/content_store/lru.h b/hicn-light/src/hicn/content_store/lru.h new file mode 100644 index 000000000..9e78ce327 --- /dev/null +++ b/hicn-light/src/hicn/content_store/lru.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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 HICNLIGHT_CS_LRU_H +#define HICNLIGHT_CS_LRU_H + +#define LRU_FAILURE 0 +#define LRU_SUCCESS 1 +#define LRU_EVICTION 2 + +typedef struct { + off_t prev; + off_t next; +} cs_entry_lru_state_t; + +typedef struct { + off_t head; + off_t tail; +} cs_lru_state_t; + +/** + * @brief Count the number of: + * - CS matches + * - CS misses + * - entries added to CS/LRU (upon receiving a data packet) + * - entries updated in the LRU + * (because an already-existing CS entry has been updated) + * - LRU evictions + * + * 'countExpiryEvictions' is not collected since an entry is never evicted + * because of expiration. An expired CS entry is only detected when + * a data packet with the same name is received, causing an update + * (NOT an actual eviction). + */ +typedef struct { + uint64_t countHits; + uint64_t countMisses; + uint64_t countAdds; + uint64_t countUpdates; + uint64_t countLruDeletions; + uint64_t countLruEvictions; +} cs_lru_stats_t; + +#endif /* HICNLIGHT_CS_LRU_H */ diff --git a/hicn-light/src/hicn/core/CMakeLists.txt b/hicn-light/src/hicn/core/CMakeLists.txt index 1b13be91f..57ffb780f 100644 --- a/hicn-light/src/hicn/core/CMakeLists.txt +++ b/hicn-light/src/hicn/core/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -12,49 +12,63 @@ # limitations under the License. list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.h - ${CMAKE_CURRENT_SOURCE_DIR}/connectionState.h - ${CMAKE_CURRENT_SOURCE_DIR}/ticks.h - ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.h - ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.h + ${CMAKE_CURRENT_SOURCE_DIR}/address.h + ${CMAKE_CURRENT_SOURCE_DIR}/address_pair.h ${CMAKE_CURRENT_SOURCE_DIR}/connection.h + ${CMAKE_CURRENT_SOURCE_DIR}/connection_vft.h + ${CMAKE_CURRENT_SOURCE_DIR}/connection_table.h + ${CMAKE_CURRENT_SOURCE_DIR}/content_store.h + ${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.h + ${CMAKE_CURRENT_SOURCE_DIR}/fib.h ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h - ${CMAKE_CURRENT_SOURCE_DIR}/logger.h - ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.h - ${CMAKE_CURRENT_SOURCE_DIR}/message.h - ${CMAKE_CURRENT_SOURCE_DIR}/messagePacketType.h - ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.h - ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/system.h + ${CMAKE_CURRENT_SOURCE_DIR}/listener.h + ${CMAKE_CURRENT_SOURCE_DIR}/listener_table.h + ${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.h + ${CMAKE_CURRENT_SOURCE_DIR}/msgbuf.h + ${CMAKE_CURRENT_SOURCE_DIR}/msgbuf_pool.h + ${CMAKE_CURRENT_SOURCE_DIR}/packet_cache.h + ${CMAKE_CURRENT_SOURCE_DIR}/pit.h + ${CMAKE_CURRENT_SOURCE_DIR}/policy_stats.h + ${CMAKE_CURRENT_SOURCE_DIR}/strategy.h + ${CMAKE_CURRENT_SOURCE_DIR}/strategy_vft.h + ${CMAKE_CURRENT_SOURCE_DIR}/subscription.h + ${CMAKE_CURRENT_SOURCE_DIR}/ticks.h +# ${CMAKE_CURRENT_SOURCE_DIR}/system.h ${CMAKE_CURRENT_SOURCE_DIR}/mapme.h ${CMAKE_CURRENT_SOURCE_DIR}/wldr.h ${CMAKE_CURRENT_SOURCE_DIR}/messageHandler.h ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.h + ${CMAKE_CURRENT_SOURCE_DIR}/nexthops.h ${CMAKE_CURRENT_SOURCE_DIR}/name.h ) list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/address.c + ${CMAKE_CURRENT_SOURCE_DIR}/address_pair.c ${CMAKE_CURRENT_SOURCE_DIR}/connection.c - ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.c - ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.c - ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.c - ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.c + ${CMAKE_CURRENT_SOURCE_DIR}/connection_table.c + ${CMAKE_CURRENT_SOURCE_DIR}/connection_vft.c + ${CMAKE_CURRENT_SOURCE_DIR}/content_store.c + ${CMAKE_CURRENT_SOURCE_DIR}/fib.c + ${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.c ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.c - ${CMAKE_CURRENT_SOURCE_DIR}/logger.c - ${CMAKE_CURRENT_SOURCE_DIR}/message.c - ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.c - ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.c + ${CMAKE_CURRENT_SOURCE_DIR}/listener.c + ${CMAKE_CURRENT_SOURCE_DIR}/listener_table.c + ${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.c ${CMAKE_CURRENT_SOURCE_DIR}/mapme.c - ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c + ${CMAKE_CURRENT_SOURCE_DIR}/msgbuf.c + ${CMAKE_CURRENT_SOURCE_DIR}/msgbuf_pool.c ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.c ${CMAKE_CURRENT_SOURCE_DIR}/name.c + ${CMAKE_CURRENT_SOURCE_DIR}/nexthops.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet_cache.c + ${CMAKE_CURRENT_SOURCE_DIR}/pit.c + ${CMAKE_CURRENT_SOURCE_DIR}/policy_stats.c + ${CMAKE_CURRENT_SOURCE_DIR}/strategy.c + ${CMAKE_CURRENT_SOURCE_DIR}/strategy_vft.c + ${CMAKE_CURRENT_SOURCE_DIR}/subscription.c + ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) - -set(TO_INSTALL_HEADER_FILES - ${TO_INSTALL_HEADER_FILES} - ${HEADER_FILES} - PARENT_SCOPE -) diff --git a/hicn-light/src/hicn/core/address.c b/hicn-light/src/hicn/core/address.c new file mode 100644 index 000000000..a4b41c8b5 --- /dev/null +++ b/hicn-light/src/hicn/core/address.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file address.c + * \brief Implementation of Address + */ + +#include <hicn/core/address.h> +#include <hicn/util/sstrncpy.h> + +int address_from_ip_port(address_t *address, int family, ip_address_t *addr, + uint16_t port) { + switch (family) { + case AF_INET: + *address = ADDRESS4(ntohl(addr->v4.as_inaddr.s_addr), ntohs(port)); + break; + case AF_INET6: + *address = ADDRESS6(addr->v6.as_in6addr, ntohs(port)); + break; + default: + return -1; + } + return 0; +} + +const char *_address_family_str[] = { + [AF_INET] = "AF_INET", + [AF_INET6] = "AF_INET6", +}; + +int address_to_string(const address_t *address, char *addr_str, int *port) { + const int SUCCESS = 0; + char port_str[NI_MAXSERV]; + struct sockaddr_storage addr = address->as_ss; + socklen_t addr_len = sizeof(addr); + + int result = + getnameinfo((struct sockaddr *)&addr, addr_len, addr_str, NI_MAXHOST, + port_str, sizeof(port_str), NI_NUMERICHOST | NI_NUMERICSERV); + + if (result != SUCCESS) { + strcpy_s(addr_str, NI_MAXHOST, "N/A"); + if (port != NULL) *port = -1; + return result; + } + + if (port != NULL) *port = atoi(port_str); + return SUCCESS; +} + +address_t _ADDRESS4_LOCALHOST(uint16_t port) { + return ADDRESS4_LOCALHOST(port); +} diff --git a/hicn-light/src/hicn/core/address.h b/hicn-light/src/hicn/core/address.h new file mode 100644 index 000000000..7958bd063 --- /dev/null +++ b/hicn-light/src/hicn/core/address.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file address.h + * \brief Address + */ + +#ifndef HICNLIGHT_ADDRESS_H +#define HICNLIGHT_ADDRESS_H + +#include <netinet/in.h> + +#include <string.h> // memcmp +#include <hicn/util/ip_address.h> +#include <netinet/in.h> + +typedef union { + struct sockaddr_in as_sin; + struct sockaddr_in6 as_sin6; + struct sockaddr as_sa; + struct sockaddr_storage as_ss; +} address_t; + +#define address_equals(a, b) (memcmp(a, b, sizeof(address_t)) == 0) + +#define address_family(address) ((address)->as_ss.ss_family) + +#define address4(address) ((struct sockaddr_in *)(address)) +#define address6(address) ((struct sockaddr_in6 *)(address)) +#define address_sa(address) ((struct sockaddr *)(address)) + +#define address4_ip(address) (address4(address)->sin_addr) +#define address6_ip(address) (address6(address)->sin6_addr) +#define address6_scope_id(address) (address4_ptr(address)->sin6_scope_id) + +#define address_socklen(address) \ + (((address)->as_ss.ss_family == AF_INET) ? sizeof(struct sockaddr_in) \ + : sizeof(struct sockaddr_in6)) + +#define address4_is_local(address) \ + ((htonl((address4_ip(address)).s_addr) & 0xFF000000) == 0x7F000000) + +static inline bool _address6_is_local(struct sockaddr_in6 *sin6) { + return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr); +} + +#define address6_is_local(address) (_address6_is_local(address6(address))) + +#define address_is_local(address) \ + ((address)->as_ss.ss_family == AF_INET) ? address4_is_local(address) \ + : address6_is_local(address) + +int address_from_ip_port(address_t *address, int family, ip_address_t *addr, + uint16_t port); + +static inline address_t ADDRESS4(in_addr_t in_addr, int port) { + address_t address = { + .as_sin = + { + .sin_family = AF_INET, + .sin_port = htons(port), + .sin_addr = {.s_addr = htonl(in_addr)}, + }, + }; + + return address; +} + +#define ADDRESS4_LOCALHOST(port) ADDRESS4(INADDR_LOOPBACK, (port)) + +/** + * @brief Helper function to avoid macro expansion in c++ tests. Wrapper around + * 'ADDRESS4_LOCALHOST()'. + * + * @param port + * @return address_t + */ +address_t _ADDRESS4_LOCALHOST(uint16_t port); + +#define ADDRESS4_ANY(port) ADDRESS4(INADDR_ANY, (port)) + +static inline address_t ADDRESS6(struct in6_addr in_addr, int port) { + address_t address = { + .as_sin6 = + { + .sin6_family = AF_INET6, + .sin6_port = htons(port), + .sin6_addr = in_addr, + }, + }; + + return address; +} + +#define ADDRESS6_LOCALHOST(port) ADDRESS6(in6addr_loopback, (port)) +#define ADDRESS6_ANY(port) ADDRESS6((struct in6_addr)IN6ADDR_ANY_INIT, port) + +#define ADDRESS_ANY(family, port) \ + ((family == AF_INET) ? ADDRESS4_ANY(port) : ADDRESS6_ANY(port)) + +extern const char *_address_family_str[]; + +#define address_family_str(address) \ + (_address_family_str[address_family(address)]) + +#define address4_empty(address) (address4_ip(address).s_addr == 0) +#define address6_empty(address) \ + (memcmp(address6_ip(address).s6_addr, &in6addr_any, \ + sizeof(struct in6_addr)) == 0) +#define address_empty(address) \ + (address_family(address) == AF_INET ? address4_empty(address) \ + : address6_empty(address)) + +/** + * @brief Return the string representation and the port of the IP address + * provided. + * + * @param[in] address Address to obtain the string representation from. + * @param[in, out] buffer String to store the string representation of the + * address. It contains "N/A" in case of failure (see return value). + * @param[in, out] port Integer to store the the port. It contains -1 in case of + * failure (see return value). If NULL, it will not be used to store the port. + * @return int 0 if success, failure otherwise. + */ + +int address_to_string(const address_t *address, char *buffer, int *port); + +#endif /* HICNLIGHT_ADDRESS_H */ diff --git a/hicn-light/src/hicn/core/address_pair.c b/hicn-light/src/hicn/core/address_pair.c new file mode 100644 index 000000000..facbb8dc4 --- /dev/null +++ b/hicn-light/src/hicn/core/address_pair.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file address_pair.c + * \brief Implementation of Address pair + */ + +#include "address_pair.h" + +address_pair_t address_pair_factory(address_t local, address_t remote) { + address_pair_t pair; + memset(&pair, 0, sizeof(address_pair_t)); + + pair.local = local; + pair.remote = remote; + return pair; +} + +int address_pair_from_ip_port(address_pair_t* pair, int family, + ip_address_t* local_addr, uint16_t local_port, + ip_address_t* remote_addr, uint16_t remote_port) { + memset(pair, 0, sizeof(*pair)); + if (address_from_ip_port(&pair->local, family, local_addr, local_port) < 0) + return -1; + if (address_from_ip_port(&pair->remote, family, remote_addr, remote_port) < 0) + return -1; + return 0; +} diff --git a/hicn-light/src/hicn/core/address_pair.h b/hicn-light/src/hicn/core/address_pair.h new file mode 100644 index 000000000..72b92d6b5 --- /dev/null +++ b/hicn-light/src/hicn/core/address_pair.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file address_pair.h + * \brief Address pair + */ + +#ifndef HICNLIGHT_ADDRESS_PAIR_H +#define HICNLIGHT_ADDRESS_PAIR_H + +#include <hicn/util/ip_address.h> + +#include "address.h" + +typedef struct { + address_t local; + address_t remote; +} address_pair_t; + +/** + * @brief Create an address pair starting from local and remote addresses. + * + * @param local The local address to use in the pair + * @param remote The remote address to use in the pair + * @return address_pair_t The address pair created + */ +address_pair_t address_pair_factory(address_t local, address_t remote); + +int address_pair_from_ip_port(address_pair_t* pair, int family, + ip_address_t* local_addr, uint16_t local_port, + ip_address_t* remote_addr, uint16_t remote_port); + +#define address_pair_get_local(pair) (&(pair)->local) +#define address_pair_get_remote(pair) (&(pair)->remote) + +#define address_pair_get_local_family(pair) \ + (address_family(address_pair_get_local(pair))) +#define address_pair_get_remote_family(pair) \ + (address_family(address_pair_get_remote(pair))) +#define address_pair_get_family(pair) address_pair_get_local_family(pair) + +#define address_pair_is_valid(pair) \ + (address_pair_get_local_family(pair) == address_pair_get_remote_family(pair)) + +#endif /* HICNLIGHT_ADDRESS_PAIR_H */ diff --git a/hicn-light/src/hicn/core/connection.c b/hicn-light/src/hicn/core/connection.c index c2ac71a5f..c8cc1d0b9 100644 --- a/hicn-light/src/hicn/core/connection.c +++ b/hicn-light/src/hicn/core/connection.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,347 +13,294 @@ * limitations under the License. */ -#include <limits.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> +/** + * @file connection.c + * @brief Implementation of hICN connections + */ -#include <hicn/core/connection.h> -#include <hicn/core/connectionState.h> -#include <hicn/core/messageHandler.h> -#include <hicn/core/ticks.h> -#include <hicn/core/wldr.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> +#include <assert.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#ifdef WITH_POLICY -#include <hicn/policy.h> -#endif /* WITH_POLICY */ +#include <hicn/core/forwarder.h> +#include <hicn/core/listener.h> +#include <hicn/util/log.h> +#include <hicn/core/wldr.h> -struct connection { +#include "connection.h" +#include "connection_vft.h" + +#define _conn_var(x) _connection_##x + +// This is called by configuration +connection_t *connection_create(face_type_t type, const char *name, + const address_pair_t *pair, + forwarder_t *forwarder) { + assert(face_type_is_valid(type)); + assert(pair); + assert(forwarder); + + face_type_t listener_type; + switch (type) { + case FACE_TYPE_UDP: + listener_type = FACE_TYPE_UDP_LISTENER; + break; + case FACE_TYPE_TCP: + listener_type = FACE_TYPE_TCP_LISTENER; + break; + default: + return NULL; + } - const AddressPair *addressPair; - IoOperations *ops; + listener_table_t *ltable = forwarder_get_listener_table(forwarder); + listener_key_t key = listener_key_factory(pair->local, listener_type); - unsigned refCount; + listener_t *listener = listener_table_get_by_key(ltable, &key); + if (!listener) { + WITH_ERROR({ + char addr_str[NI_MAXHOST]; + int port; + address_to_string(&pair->local, addr_str, &port); + ERROR("Could not find listener to match address %s:%d", addr_str, port); + }) - unsigned counter; + return NULL; + } - bool wldrAutoStart; // if true, wldr can be set automatically - // by default this value is set to true. - // if wldr is activated using a command (config - // file/hicnLightControl) this value is set to false so - // that a base station can not disable wldr at the client - Wldr *wldr; + connection_table_t *table = + forwarder_get_connection_table(listener->forwarder); + unsigned connection_id = listener_create_connection(listener, name, pair); + if (!connection_id_is_valid(connection_id)) return NULL; + return connection_table_at(table, connection_id); +} +/** + * @brief Initializes a connection + * + * @param [out] connection - Allocated connection buffer (eg. from pool) to be + * initialized. + * @param [in] forwarder - forwarder_t to which the connection is associated. + * This parameter needs to be non-NULL for connections receiving packets, such + * as TCP connections which are very close to UDP listeners, and unlike + * bound UDP connections). + * @param [in] fd - A fd specific to the connection, or 0 if the connection + * should inherit the fd of the listener. + * @return 0 if no error, -1 otherwise + */ +int connection_initialize(connection_t *connection, face_type_t type, + const char *name, const char *interface_name, int fd, + const address_pair_t *pair, bool local, + unsigned connection_id, listener_t *listener) { + int rc; + + assert(connection); + /* Interface name can be NULL eg always for TCP connnections */ + assert(pair); + // assert(address_pair_is_valid(pair)); TODO: local addr in the pair is not + // initialized for now + + if (fd == 0) WARN("Connection is not connected"); + + *connection = (connection_t){ + .id = connection_id, + .name = strdup(name), + .type = type, + .interface_name = strdup(interface_name), + .pair = *pair, + .fd = ((fd != 0) ? fd : listener_get_fd(listener)), + .connected = (fd != 0), + // .up = true, + .local = local, + // XXX UDP should start UP, TCP DOWN until remove side answer ? + .state = FACE_STATE_UNDEFINED, + .admin_state = FACE_STATE_UP, #ifdef WITH_POLICY - policy_tags_t tags; + .priority = 0, #endif /* WITH_POLICY */ -}; + .listener = listener, + .closed = false, -Connection *connection_Create(IoOperations *ops) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - Connection *conn = parcMemory_AllocateAndClear(sizeof(Connection)); - parcAssertNotNull(conn, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Connection)); - conn->addressPair = ioOperations_GetAddressPair(ops); - conn->ops = ops; - conn->refCount = 1; - conn->wldr = NULL; + /* WLDR */ + .wldr = NULL, + .wldr_autostart = true, + }; - conn->wldrAutoStart = true; - conn->counter = 0; + connection->data = + malloc(connection_vft[get_protocol(connection->type)]->data_size); + if (!connection->data) goto ERR_DATA; - /* By default, a connection will aim at the UP state */ - connection_SetAdminState(conn, CONNECTION_STATE_UP); + assert(connection_has_valid_id(connection)); -#ifdef WITH_POLICY - conn->tags = POLICY_TAGS_EMPTY; -#endif /* WITH_POLICY */ - - return conn; -} - -Connection *connection_Acquire(Connection *connection) { - parcAssertNotNull(connection, "Parameter conn must be non-null"); - connection->refCount++; - return connection; -} - -void connection_Release(Connection **connectionPtr) { - parcAssertNotNull(connectionPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*connectionPtr, - "Parameter must dereference to non-null pointer"); - Connection *conn = *connectionPtr; - - parcAssertTrue( - conn->refCount > 0, - "Invalid state, connection reference count should be positive, got 0."); - conn->refCount--; - if (conn->refCount == 0) { - // don't destroy addressPair, its part of ops. - ioOperations_Release(&conn->ops); - if (conn->wldr != NULL) { - wldr_Destroy(&(conn->wldr)); - } - parcMemory_Deallocate((void **)&conn); + rc = connection_vft[get_protocol(connection->type)]->initialize(connection); + if (rc < 0) { + goto ERR_VFT; } - *connectionPtr = NULL; -} - -bool connection_Send(const Connection *conn, Message *message) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - if (ioOperations_IsUp(conn->ops)) { - if (message_GetType(message) == MessagePacketType_ContentObject) { - uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn); - message_UpdatePathLabel(message, connectionId); + if (connection->connected) { + /* + * The file descriptor is created by the listener. We assume for now that + * all connections get their own fd, and we have to register it. + * + * TODO the connection has no more read callback, so we call the one from + * the listener. + */ + loop_fd_event_create(&connection->event_data, MAIN_LOOP, fd, listener, + (fd_callback_t)listener_read_callback, NULL); + + if (!connection->event_data) { + goto ERR_REGISTER_FD; } - if (conn->wldr != NULL) { - wldr_SetLabel(conn->wldr, message); - } else { - message_ResetWldrLabel(message); + + if (loop_fd_event_register(connection->event_data) < 0) { + goto ERR_REGISTER_FD; } - return ioOperations_Send(conn->ops, NULL, message); } - return false; -} - -bool connection_SendIOVBuffer(const Connection *conn, struct iovec *msg, - size_t size) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - parcAssertNotNull(msg, "Parameter message must be non-null"); - - return ioOperations_SendIOVBuffer(conn->ops, msg, size); -} - -bool connection_SendBuffer(const Connection *conn, u8 * buffer, size_t length) -{ - struct iovec iov[1]; - iov[0].iov_base = buffer; - iov[0].iov_len = length; - return connection_SendIOVBuffer(conn, iov, 1); -} -void connection_Probe(Connection *conn, uint8_t * probe) { - ioOperations_SendProbe(conn->ops, probe); -} - -void connection_HandleProbe(Connection *conn, uint8_t *probe){ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - parcAssertNotNull(probe, "Parameter pkt must be non-null"); - - if(messageHandler_IsInterest(probe)){ - messageHandler_CreateProbeReply(probe, HF_INET6_TCP); - ioOperations_SendProbe(conn->ops, probe); + return 0; + +ERR_REGISTER_FD: +#ifndef _WIN32 + close(fd); +#else + closesocket(fd); +#endif +ERR_VFT: + free(connection->data); +ERR_DATA: + free(connection->interface_name); + free(connection->name); + return -1; +} + +int connection_finalize(connection_t *connection) { + assert(connection); + assert(connection_has_valid_type(connection)); + + if (connection->connected) { + loop_event_unregister(connection->event_data); + loop_event_free(connection->event_data); } -} - -IoOperations *connection_GetIoOperations(const Connection *conn) { - return conn->ops; -} - -unsigned connection_GetConnectionId(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - return ioOperations_GetConnectionId(conn->ops); -} - -const AddressPair *connection_GetAddressPair(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - return ioOperations_GetAddressPair(conn->ops); -} - -bool connection_IsUp(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) return false; - return ioOperations_IsUp(conn->ops); -} -bool connection_IsLocal(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - return ioOperations_IsLocal(conn->ops); -} + if (connection->fd != 0) { // Only if connected socket +#ifndef _WIN32 + close(connection->fd); +#else + closesocket(connection->fd); +#endif + } -const void *connection_Class(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - return ioOperations_Class(conn->ops); -} + if (connection->wldr) wldr_free(connection->wldr); -bool connection_ReSend(const Connection *conn, Message *message, - bool notification) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - bool res = false; - - if (connection_IsUp(conn)) { - // here the wldr header is alreay set: this message is a retransmission or a - // notification - - // we need to recompiute the path lable since we always store a pointer to - // the same message if this message will be sent again to someonelse, the - // new path label must be computed starting from the orignal labelorignal - // label. Notice that we heve the same problem in case of PIT aggregation. - // That case is handled insied the MessageProcessor. This is specific to - // WLDR retransmittions. This is done only for data packets - - if (message_GetType(message) == MessagePacketType_ContentObject) { - uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn); - uint32_t old_path_label = message_GetPathLabel(message); - message_UpdatePathLabel(message, connectionId); - - res = ioOperations_Send(conn->ops, NULL, message); - - message_SetPathLabel(message, old_path_label); - } else { - res = ioOperations_Send(conn->ops, NULL, message); - } - } + connection_vft[get_protocol(connection->type)]->finalize(connection); - if (notification) { - // the notification is never destroyed - message_Release(&message); - } + if (connection->data) free(connection->data); + connection->data = NULL; + if (connection->interface_name) free(connection->interface_name); + connection->interface_name = NULL; + if (connection->name) free(connection->name); + connection->name = NULL; - return res; + return 0; } -void connection_AllowWldrAutoStart(Connection *conn, bool allow) { - conn->wldrAutoStart = allow; -} +int connection_send_packet(const connection_t *connection, + const uint8_t *packet, size_t size) { + assert(connection); + assert(face_type_is_valid(connection->type)); + assert(packet); -void connection_EnableWldr(Connection *conn) { - if (!connection_IsLocal(conn)) { - if (conn->wldr == NULL) { - printf("----------------- enable wldr\n"); - conn->wldr = wldr_Init(); - } - } + return connection_vft[get_protocol(connection->type)]->send_packet( + connection, packet, size); } -void connection_DisableWldr(Connection *conn) { - if (!connection_IsLocal(conn)) { - if (conn->wldr != NULL) { - printf("----------------- disable wldr\n"); - wldr_Destroy(&(conn->wldr)); - conn->wldr = NULL; - } - } +bool _connection_send(const connection_t *connection, msgbuf_t *msgbuf, + bool queue) { + return connection_vft[get_protocol(connection->type)]->send(connection, + msgbuf, queue); } -bool connection_HasWldr(const Connection *conn) { - if (conn->wldr == NULL) { - return false; - } else { - return true; - } +bool connection_flush(const connection_t *connection) { + return connection_vft[get_protocol(connection->type)]->flush(connection); } -bool connection_WldrAutoStartAllowed(const Connection *conn) { - return conn->wldrAutoStart; -} +bool connection_send(const connection_t *connection, off_t msgbuf_id, + bool queue) { + assert(connection); + assert(msgbuf_id_is_valid(msgbuf_id)); -void connection_DetectLosses(Connection *conn, Message *message) { - if (conn->wldr != NULL) wldr_DetectLosses(conn->wldr, conn, message); -} + // if (!connection_is_up(connection)) + // return false; -void connection_HandleWldrNotification(Connection *conn, Message *message) { - if (conn->wldr != NULL) - wldr_HandleWldrNotification(conn->wldr, conn, message); -} + const listener_t *listener = connection_get_listener(connection); + const forwarder_t *forwarder = listener_get_forwarder(listener); + const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); -connection_state_t connection_GetState(const Connection *conn) -{ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return CONNECTION_STATE_UNDEFINED; - return ioOperations_GetState(conn->ops); -} + if (connection->wldr) + wldr_set_label(connection->wldr, msgbuf); + else + msgbuf_reset_wldr_label(msgbuf); -void connection_SetState(Connection *conn, connection_state_t state) -{ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return; - ioOperations_SetState(conn->ops, state); + return _connection_send(connection, msgbuf, queue); } -connection_state_t connection_GetAdminState(const Connection *conn) -{ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return CONNECTION_STATE_UNDEFINED; - return ioOperations_GetAdminState(conn->ops); -} +/* + * here the wldr header is alreay set: this message is a retransmission or a + * notification + * + * we need to recompute the path label since we always store a pointer to + * the same message if this message will be sent again to someone else, the + * new path label must be computed starting from the orignal label. Note + * that we heve the same problem in case of PIT aggregation. That case is + * handled inside the MessageProcessor. This is specific to WLDR + * retransmittions. This is done only for data packets + */ +bool connection_resend(const connection_t *connection, msgbuf_t *msgbuf, + bool notification) { + assert(connection); + assert(msgbuf); -void connection_SetAdminState(Connection *conn, connection_state_t admin_state) -{ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return; - if ((admin_state != CONNECTION_STATE_UP) && (admin_state != CONNECTION_STATE_DOWN)) - return; - ioOperations_SetAdminState(conn->ops, admin_state); -} + bool ret = false; -#ifdef WITH_POLICY -uint32_t connection_GetPriority(const Connection *conn) -{ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return 0; - return ioOperations_GetPriority(conn->ops); -} + if (!connection_is_up(connection)) return ret; -void connection_SetPriority(Connection *conn, uint32_t priority) -{ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return; - ioOperations_SetPriority(conn->ops, priority); -} -#endif /* WITH_POLICY */ + ret = _connection_send(connection, msgbuf, false); /* no queueing */ -const char * connection_GetInterfaceName(const Connection * conn) -{ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return NULL; - return ioOperations_GetInterfaceName(conn->ops); + return ret; } -#ifdef WITH_POLICY +/* WLDR */ -void connection_AddTag(Connection *conn, policy_tag_t tag) -{ - policy_tags_add(&conn->tags, tag); +void connection_wldr_allow_autostart(connection_t *connection, bool value) { + connection->wldr_autostart = value; } -void connection_RemoveTag(Connection *conn, policy_tag_t tag) -{ - policy_tags_remove(&conn->tags, tag); +bool connection_wldr_autostart_is_allowed(const connection_t *connection) { + return connection->wldr_autostart; } -policy_tags_t connection_GetTags(const Connection *conn) -{ - return conn->tags; +void connection_wldr_enable(connection_t *connection, bool value) { + if (connection_is_local(connection)) return; + if (value) { + if (connection->wldr) return; + connection->wldr = wldr_create(); + } else { + if (!connection->wldr) return; + wldr_free(connection->wldr); + } } -void connection_SetTags(Connection *conn, policy_tags_t tags) -{ - conn->tags = tags; +bool connection_has_wldr(const connection_t *connection) { + return !!connection->wldr; } -void connection_ClearTags(Connection *conn) -{ - conn->tags = POLICY_TAGS_EMPTY; +void connection_wldr_detect_losses(const connection_t *connection, + const msgbuf_t *msgbuf) { + if (!connection->wldr) return; + wldr_detect_losses(connection->wldr, connection, msgbuf); } -int connection_HasTag(const Connection *conn, policy_tag_t tag) -{ - return policy_tags_has(conn->tags, tag); +void connection_wldr_handle_notification(const connection_t *connection, + const msgbuf_t *msgbuf) { + if (!connection->wldr) return; + wldr_handle_notification(connection->wldr, connection, msgbuf); } - -#endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/core/connection.h b/hicn-light/src/hicn/core/connection.h index b6513ea1a..05dc1d6e2 100644 --- a/hicn-light/src/hicn/core/connection.h +++ b/hicn-light/src/hicn/core/connection.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -15,19 +15,23 @@ /** * @file connection.h - * @brief Wrapper for different types of connections - * - * A connection wraps a specific set of {@link IoOperations}. Those operations - * allow for input and output. Connections get stored in the Connection Table. - * + * @brief hICN connections */ -#ifndef connection_h -#define connection_h -#include <hicn/hicn-light/config.h> -#include <hicn/core/connectionState.h> -#include <hicn/io/ioOperations.h> -#include <hicn/utils/address.h> +#ifndef HICNLIGHT_CONNECTION_H +#define HICNLIGHT_CONNECTION_H + +#include <hicn/face.h> + +#include "address_pair.h" +#include "listener.h" +#include "msgbuf.h" + +#ifdef WITH_POLICY +#include <hicn/policy.h> +#endif /* WITH_POLICY */ + +#define CONNECTION_ID_UNDEFINED ~0 #ifdef WITH_MAPME typedef enum { @@ -42,157 +46,193 @@ typedef enum { #endif /* WITH_MAPME */ +struct wldr_s; + +typedef struct { + unsigned id; + char* name; + char* interface_name; + face_type_t type; + address_pair_t pair; + // bool up; + bool local; + face_state_t state; + face_state_t admin_state; #ifdef WITH_POLICY -#include <hicn/policy.h> + policy_tags_t tags; + uint32_t priority; #endif /* WITH_POLICY */ -struct connection; -typedef struct connection Connection; + int fd; + bool connected; // true if the connection is connected and has its own fd + event_t* event_data; + + void* data; + + listener_t* listener; + // struct forwarder_s * forwarder; // recv only + bool closed; + + /* WLDR */ + + bool wldr_autostart; + /* + * if true, wldr can be set automatically by default this value is set to + * true. if wldr is activated using a command (config file/hicnLightControl) + * this value is set to false so that a base station can not disable wldr at + * the client. + */ + struct wldr_s* wldr; + +} connection_t; + +#if 1 +#define connection_get_id(C) ((C)->id) +#define connection_id_is_valid(ID) (ID != CONNECTION_ID_UNDEFINED) +#define connection_get_name(C) ((C)->name) +#define connection_get_type(C) ((C)->type) +#define connection_has_valid_id(C) \ + (connection_id_is_valid(connection_get_id(C))) +#define connection_has_valid_type(C) \ + (face_type_is_valid(connection_get_type(C))) +#define connection_get_pair(C) (&(C)->pair) +#define connection_get_local(C) (address_pair_get_local(connection_get_pair(C))) +#define connection_get_remote(C) \ + (address_pair_get_remote(connection_get_pair(C))) +#define connection_get_local(C) (address_pair_get_local(connection_get_pair(C))) +#define connection_get_remote(C) \ + (address_pair_get_remote(connection_get_pair(C))) +#define connection_is_up(C) ((C)->state == FACE_STATE_UP) +#define connection_is_closed(C) ((C)->closed == true) +#define connection_is_local(C) ((C)->local) +#define connection_get_state(C) ((C)->state) +#define connection_set_state(C, STATE) (C)->state = STATE +#define connection_get_admin_state(C) ((C)->admin_state) +#define connection_set_admin_state(C, STATE) (C)->admin_state = STATE +#define connection_get_interface_name(C) ((C)->interface_name) -/** - * Creates a connection object. - */ -Connection *connection_Create(IoOperations *ops); +#ifdef WITH_POLICY +#define connection_get_priority(C) ((C)->priority) +#define connection_set_priority(C, PRIORITY) (C)->priority = PRIORITY +#define connection_get_tags(C) ((C)->tags) +#define connection_set_tags(C, TAGS) (C)->tags = TAGS +#define connection_has_tag(C, TAG) policy_tags_has(connection_get_tags(C), TAG) +#define connection_add_tag(C, TAG) policy_tags_add(connection_get_tags(X), TAG) +#define connection_remove_tag(C, TAG) \ + do { \ + policy_tags_t _conn_var(tags); \ + _conn_var(tags) = connection_get_tags(C); \ + policy_tags_remove(_conn_var(tags), (TAG)); \ + connection_set_tags((C), _conn_var(tags)); \ + } while (0) +#define connection_clear_tags(C) connection_set_tags(C, POLICY_TAGS_EMPTY) -/** - * @function connection_Release - * @abstract Releases a reference count, destroying on last release - * @discussion - * Only frees the memory on the final reference count. The pointer will - * always be NULL'd. - */ -void connection_Release(Connection **connectionPtr); +#endif /* WITH_POLICY */ -/** - * @function connection_Acquire - * @abstract A reference counted copy. - * @discussion - * A shallow copy, they share the same memory. - */ -Connection *connection_Acquire(Connection *connection); +#else -/** - * @function connection_Send - * @abstract Sends the message on the connection - * @return true if message sent, false if connection not up - */ -bool connection_Send(const Connection *conn, Message *message); +/* Accessors */ +static inline unsigned connection_get_id(const connection_t* connection); -/** - * @function connection_SendIOVBuffer - * @abstract Sends an IOV buffer - */ -bool connection_SendIOVBuffer(const Connection *conn, struct iovec *msg, - size_t size); +#define connection_id_is_valid(id) (id != CONNECTION_ID_UNDEFINED) +#define connection_has_valid_id(C) (connection_id_is_valid(connection_get_id(C)) -/** - * @function connection_SendBuffer - * @abstract Sends a buffer - */ -bool connection_SendBuffer(const Connection *conn, u8 * buffer, size_t length); +static inline char* connection_get_name(const connection_t* connection); -/** - * Return the `IoOperations` instance associated with the specified `Connection` - * instance. - * @param [in] connection The allocated connection - * @return a pointer to the IoOperations instance associated by th specified - * connection. - */ -IoOperations *connection_GetIoOperations(const Connection *conn); +static inline face_type_t connection_get_type(const connection_t* connection); -/** - * Returns the unique identifier of the connection - * Calls the underlying IoOperations to fetch the connection id - * @param [in] connection The allocated connection - * @return unsigned The unique connection id - */ -unsigned connection_GetConnectionId(const Connection *conn); +static inline address_pair_t* connection_get_pair( + const connection_t* connection); -/** - * Returns the (remote, local) address pair that describes the connection - * @param [in] connection The allocated connection - * @return non-null The connection's remote and local address - * @return null Should never return NULL - */ -const AddressPair *connection_GetAddressPair(const Connection *conn); +#define connection_get_local(C) (address_pair_get_local(connection_get_pair(C))) +#define connection_get_remote(C) (address_pair_remote(connection_get_pair(C))) -/** - * Checks if the connection is in the "up" state - * @param [in] connection The allocated connection - * @return true The connection is in the "up" state - * @return false The connection is not in the "up" state - */ -bool connection_IsUp(const Connection *conn); +static inline bool connection_is_up(const connection_t* connection); -/** - * Checks if the connection is to a Local/Loopback address - * - * A local connection is PF_LOCAL (PF_UNIX) and a loopback connection is - * 127.0.0.0/8 or ::1 for IPv6. - * - * @param [in] connection The allocated connection - * - * @retval true The connection is local or loopback - * @retval false The connection is not local or loopback - */ -bool connection_IsLocal(const Connection *conn); +static inline bool connection_is_local(const connection_t* connection); -/** - * Returns an opaque pointer representing the class of the Io Operations - * - * Returns an opaque pointer that an implementation can use to detect if - * the connection is based on that class. - * - * @param [in] conn The Connection to analyze - * - * @return non-null An opaque pointer for each concrete implementation - */ -const void *connection_Class(const Connection *conn); +static inline face_state_t connection_get_state(const connection_t* connection); -bool connection_ReSend(const Connection *conn, Message *message, - bool notification); +static inline void connection_set_state(connection_t* connection, + face_state_t state); -void connection_Probe(Connection *conn, uint8_t *probe); +static inline face_state_t connection_get_admin_state( + const connection_t* connection); -void connection_HandleProbe(Connection *conn, uint8_t *message); +static inline void connection_set_admin_state(connection_t* connection, + face_state_t state); -void connection_AllowWldrAutoStart(Connection *conn, bool allow); +static inline const char* connection_get_interface_name( + const connection_t* connection); -void connection_EnableWldr(Connection *conn); +#ifdef WITH_POLICY -void connection_DisableWldr(Connection *conn); +static inline uint32_t connection_get_priority(const connection_t* connection); -bool connection_HasWldr(const Connection *conn); +static inline void connection_set_priority(connection_t* connection, + uint32_t priority); -bool connection_WldrAutoStartAllowed(const Connection *conn); +static inline policy_tags_t connection_get_tags(const connection_t* connection); -void connection_DetectLosses(Connection *conn, Message *message); +static inline void connection_set_tags(connection_t* connection, + policy_tags_t tags); -void connection_HandleWldrNotification(Connection *conn, Message *message); +#define connection_has_tag(C, TAG) policy_tags_has(connection_get_tags(C), TAG) -connection_state_t connection_GetState(const Connection *conn); +#define connection_add_tag(C, TAG) policy_tags_add(connection_get_tags(X), TAG) -void connection_SetState(Connection *conn, connection_state_t state); +#define connection_remove_tag(C, TAG) \ + do { \ + policy_tags_t _conn_var(tags); \ + _conn_var(tags) = connection_get_tags(C); \ + policy_tags_remove(_conn_var(tags), (TAG)); \ + connection_set_tags((C), _conn_var(tags)); \ + } while (0) -connection_state_t connection_GetAdminState(const Connection *conn); +#define connection_clear_tags(C) connection_set_tags(C, POLICY_TAGS_EMPTY) -void connection_SetAdminState(Connection *conn, connection_state_t admin_state); +#endif /* WITH_POLICY */ -#ifdef WITH_POLICY -uint32_t connection_GetPriority(const Connection *conn); +#endif -void connection_SetPriority(Connection *conn, uint32_t priority); -#endif /* WITH_POLICY */ +connection_t* connection_create(face_type_t type, const char* name, + const address_pair_t* pair, + struct forwarder_s* forwarder); -const char * connection_GetInterfaceName(const Connection * conn); +int connection_initialize(connection_t* connection, face_type_t type, + const char* name, const char* interface_name, int fd, + const address_pair_t* pair, bool local, + unsigned connection_id, listener_t* listener); -#ifdef WITH_POLICY -void connection_AddTag(Connection *conn, policy_tag_t tag); -void connection_RemoveTag(Connection *conn, policy_tag_t tag); -policy_tags_t connection_GetTags(const Connection *conn); -void connection_SetTags(Connection *conn, policy_tags_t tags); -void connection_ClearTags(Connection *conn); -int connection_HasTag(const Connection *conn, policy_tag_t tag); -#endif /* WITH_POLICY */ +int connection_finalize(connection_t* connection); + +int connection_send_packet(const connection_t* connection, + const uint8_t* packet, size_t size); + +bool connection_flush(const connection_t* connection); + +bool connection_send(const connection_t* connection, off_t msgbuf_id, + bool queue); + +size_t connection_process_buffer(connection_t* connection, + const uint8_t* buffer, size_t size); + +/* WLDR */ + +void connection_wldr_allow_autostart(connection_t* connection, bool value); + +bool connection_wldr_autostart_is_allowed(const connection_t* connection); + +void connection_wldr_enable(connection_t* connection, bool value); + +bool connection_has_wldr(const connection_t* connection); + +void connection_wldr_detect_losses(const connection_t* connection, + const msgbuf_t* msgbuf); + +void connection_wldr_handle_notification(const connection_t* connection, + const msgbuf_t* msgbuf); + +#define connection_get_listener(connection) (connection->listener) -#endif // connection_h +#endif /* HICNLIGHT_CONNECTION_H */ diff --git a/hicn-light/src/hicn/core/connectionList.c b/hicn-light/src/hicn/core/connectionList.c deleted file mode 100644 index d51a9aad5..000000000 --- a/hicn-light/src/hicn/core/connectionList.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Memory.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/core/connectionList.h> - -struct connection_list { - PARCArrayList *listOfConnections; -}; - -static void connectionList_ArrayDestroyer(void **voidPtr) { - Connection **entryPtr = (Connection **)voidPtr; - connection_Release(entryPtr); -} - -ConnectionList *connectionList_Create() { - ConnectionList *list = parcMemory_AllocateAndClear(sizeof(ConnectionList)); - parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ConnectionList)); - list->listOfConnections = parcArrayList_Create(connectionList_ArrayDestroyer); - return list; -} - -void connectionList_Destroy(ConnectionList **listPtr) { - parcAssertNotNull(listPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listPtr, "Parameter must dereference to non-null pointer"); - ConnectionList *list = *listPtr; - parcArrayList_Destroy(&list->listOfConnections); - parcMemory_Deallocate((void **)&list); - *listPtr = NULL; -} - -void connectionList_Append(ConnectionList *list, Connection *entry) { - parcAssertNotNull(list, "Parameter list must be non-null"); - parcAssertNotNull(entry, "Parameter entry must be non-null"); - - parcArrayList_Add(list->listOfConnections, connection_Acquire(entry)); -} - -size_t connectionList_Length(const ConnectionList *list) { - parcAssertNotNull(list, "Parameter list must be non-null"); - return parcArrayList_Size(list->listOfConnections); -} - -Connection *connectionList_Get(ConnectionList *list, size_t index) { - parcAssertNotNull(list, "Parameter list must be non-null"); - Connection *original = - (Connection *)parcArrayList_Get(list->listOfConnections, index); - return original; -} diff --git a/hicn-light/src/hicn/core/connectionList.h b/hicn-light/src/hicn/core/connectionList.h deleted file mode 100644 index fbba9f6d8..000000000 --- a/hicn-light/src/hicn/core/connectionList.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file connectionList.h - * @brief A typesafe list of Connection objects - * - * <#Detailed Description#> - * - */ - -#ifndef connectionList_h -#define connectionList_h - -struct connection_list; -typedef struct connection_list ConnectionList; - -#include <hicn/core/connection.h> - -/** - * Creates a lis of Connection - * - * @return non-null An allocated list - * @return null An error - */ -ConnectionList *connectionList_Create(void); - -/** - * Destroys the list and all objects inside it - */ -void connectionList_Destroy(ConnectionList **listPtr); - -/** - * @function connectionList_Append - * @abstract Adds a connection entry to the list. - * @discussion - * Acquires a reference to the passed entry and stores it in the list. - */ -void connectionList_Append(ConnectionList *list, Connection *entry); - -/** - * Returns the number of items on the list - * @param [in] list The allocated list to check - * @return number The number of items on the list - */ -size_t connectionList_Length(const ConnectionList *list); - -/** - * @function connectionList_Get - * @abstract Returns the connection entry. - * @discussion - * Caller must not destroy the returned value. If you will store the - * entry in your own data structure, you should acquire your own reference. - * Will assert if you go beyond the end of the list. - * - */ -Connection *connectionList_Get(ConnectionList *list, size_t index); -#endif // connectionList_h diff --git a/hicn-light/src/hicn/core/connectionManager.c b/hicn-light/src/hicn/core/connectionManager.c deleted file mode 100644 index 709f0902a..000000000 --- a/hicn-light/src/hicn/core/connectionManager.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * The Connection Manager sets itself up as a listener to the Messenger so it - * can take action based on system events. - * - * The Connection Manager queues and then processes in a later time slice the - * messages. - * - */ - -#include <hicn/hicn-light/config.h> -#include <hicn/core/connectionManager.h> -#include <hicn/core/forwarder.h> -#include <hicn/messenger/messenger.h> -#include <hicn/messenger/messengerRecipient.h> -#include <hicn/messenger/missiveDeque.h> -#include <stdio.h> - -#include <parc/algol/parc_Memory.h> - -#include <parc/assert/parc_Assert.h> - -struct connection_manager { - Forwarder *forwarder; - Logger *logger; - - MessengerRecipient *messengerRecipient; - - // we queue missives as they come in to process in our own - // event timeslice - MissiveDeque *missiveQueue; - - // for deferred queue processing - PARCEventTimer *timerEvent; -}; - -/** - * Receives missives from the messenger, queues them, and schedules our - * execution - * - * We defer processing of missives to a later time slice - */ -static void connectionManager_MessengerCallback(MessengerRecipient *recipient, - Missive *missive); - -/** - * Event callback - * - * This is our main run loop to process our queue of messages. It is scheduled - * in {@link connectionManager_MessengerCallback} when the queue becomes - * non-empty. - * - * When we are called here, we have exclusive use of the system, so we will not - * create any message loops - * - * @param [in] fd unused, required for compliance with function prototype - * @param [in] which_event unused, required for compliance with function - * prototype - * @param [in] connManagerVoidPtr A void* to ConnectionManager - * - */ -static void connectionManager_ProcessQueue(int fd, PARCEventType which_event, - void *connManagerVoidPtr); - -static void connectionManager_ProcessClosedMissive( - ConnectionManager *connManager, const Missive *missive); - -// ======================================================== -// Public API - -ConnectionManager *connectionManager_Create(Forwarder *forwarder) { - ConnectionManager *connManager = - parcMemory_AllocateAndClear(sizeof(ConnectionManager)); - parcAssertNotNull(connManager, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ConnectionManager)); - connManager->forwarder = forwarder; - connManager->missiveQueue = missiveDeque_Create(); - connManager->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - Messenger *messenger = forwarder_GetMessenger(connManager->forwarder); - - // creates the timer, but does not start it - PARCEventScheduler *base = - dispatcher_GetEventScheduler(forwarder_GetDispatcher(forwarder)); - connManager->timerEvent = parcEventTimer_Create( - base, 0, connectionManager_ProcessQueue, connManager); - - connManager->messengerRecipient = messengerRecipient_Create( - connManager, connectionManager_MessengerCallback); - messenger_Register(messenger, connManager->messengerRecipient); - return connManager; -} - -void connectionManager_Destroy(ConnectionManager **managerPtr) { - parcAssertNotNull(managerPtr, "Double pointer must be non-null"); - parcAssertNotNull(*managerPtr, "Double pointer must dereference to non-null"); - - ConnectionManager *connManager = *managerPtr; - - Messenger *messenger = forwarder_GetMessenger(connManager->forwarder); - parcEventTimer_Destroy(&(connManager->timerEvent)); - messenger_Unregister(messenger, connManager->messengerRecipient); - messengerRecipient_Destroy(&connManager->messengerRecipient); - missiveDeque_Release(&connManager->missiveQueue); - logger_Release(&connManager->logger); - - parcMemory_Deallocate((void **)&connManager); - *managerPtr = NULL; -} - -// ======================================================== -// Internal Functions - -static void connectionManager_MessengerCallback(MessengerRecipient *recipient, - Missive *missive) { - ConnectionManager *connManager = - messengerRecipient_GetRecipientContext(recipient); - - // we do not release our reference count, we store it until later - // We are called with our own reference, so we do not need to acquire the - // missive here. - missiveDeque_Append(connManager->missiveQueue, missive); - - if (missiveDeque_Size(connManager->missiveQueue) == 1) { - // When it becomes non-empty, schedule {@link - // connectionManager_ProcessQueue} - struct timeval immediateTimeout = {0, 0}; - parcEventTimer_Start(connManager->timerEvent, &immediateTimeout); - } -} - -static void connectionManager_ProcessQueue(int fd, PARCEventType which_event, - void *connManagerVoidPtr) { - ConnectionManager *connManager = (ConnectionManager *)connManagerVoidPtr; - - Missive *missive; - while ((missive = missiveDeque_RemoveFirst(connManager->missiveQueue)) != - NULL) { - switch (missive_GetType(missive)) { - case MissiveType_ConnectionCreate: - // hook to signal that a new connection was created - break; - case MissiveType_ConnectionUp: - // hook to signal that a new connection is up - break; - case MissiveType_ConnectionDown: - // hook to signal that a connection is down - break; - case MissiveType_ConnectionClosed: - connectionManager_ProcessClosedMissive(connManager, missive); - break; - case MissiveType_ConnectionDestroyed: - // hook to signal that a connection was destroyed - break; - default: - parcTrapUnexpectedState("Missive %p of unknown type: %d", - (void *)missive, missive_GetType(missive)); - } - missive_Release(&missive); - } -} - -static void connectionManager_ProcessClosedMissive( - ConnectionManager *connManager, const Missive *missive) { - logger_Log(connManager->logger, LoggerFacility_Core, PARCLogLevel_Debug, - __func__, "Processing CLOSED message for connid %u", - missive_GetConnectionId(missive)); - - ConnectionTable *table = forwarder_GetConnectionTable(connManager->forwarder); - const Connection *conn = - connectionTable_FindById(table, missive_GetConnectionId(missive)); - - if (conn) { - // this will destroy the connection if its the last reference count - connectionTable_Remove(table, conn); - - // remove from FIB - forwarder_RemoveConnectionIdFromRoutes(connManager->forwarder, - missive_GetConnectionId(missive)); - } -} diff --git a/hicn-light/src/hicn/core/connectionManager.h b/hicn-light/src/hicn/core/connectionManager.h deleted file mode 100644 index 34fee8717..000000000 --- a/hicn-light/src/hicn/core/connectionManager.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file connectionManager.h - * @brief The connection manager handles connection events, such as going down - * - * The connection manager listens to the event notification system. Based on - * those events, the connection manager will take specific actions. This is - * expected to be a singleton instantiated by the forwarder. - * - */ - -#ifndef connectionManager_h -#define connectionManager_h - -#include <hicn/core/forwarder.h> - -struct connection_manager; -typedef struct connection_manager ConnectionManager; - -ConnectionManager *connectionManager_Create(Forwarder *forwarder); - -void connectionManager_Destroy(ConnectionManager **managerPtr); -#endif // connectionManager_h diff --git a/hicn-light/src/hicn/core/connectionTable.c b/hicn-light/src/hicn/core/connectionTable.c deleted file mode 100644 index f8589c12b..000000000 --- a/hicn-light/src/hicn/core/connectionTable.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @header ConnectionTable - * @abstract Records all the current connections and references to them - * @discussion - * - */ - -#ifndef _WIN32 -#include <unistd.h> -#endif -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_HashCodeTable.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_TreeRedBlack.h> -#include <hicn/core/connectionTable.h> -#include <hicn/io/addressPair.h> - -struct connection_table { - // The main storage table that has a Destroy method. - // The key is an unsigned int pointer. We use an unsigned int pointer - // because we want to be able to lookup by the id alone, and not have to - // have the IoOperations everywhere. - PARCHashCodeTable *storageTableById; - - // The key is a AddressPair - // It does not have a destroy method for the data or key, - // as they are derived from the storage table. - PARCHashCodeTable *indexByAddressPair; - - // An iterable stucture organized by connection id. The keys and - // values are the same pointers as in storageTableById, so there - // are no destructors in the tree. - // The only reason to keep this tree is so we have an iterable list - // of connections, which the hash table does not give us. - PARCTreeRedBlack *listById; -}; - -static bool connectionTable_ConnectionIdEquals(const void *keyA, - const void *keyB) { - unsigned idA = *((unsigned *)keyA); - unsigned idB = *((unsigned *)keyB); - return (idA == idB); -} - -static int connectionTable_ConnectionIdCompare(const void *keyA, - const void *keyB) { - unsigned idA = *((unsigned *)keyA); - unsigned idB = *((unsigned *)keyB); - if (idA < idB) { - return -1; - } - if (idA > idB) { - return +1; - } - return 0; -} - -static bool connectionTable_AddressPairEquals(const void *keyA, - const void *keyB) { - const AddressPair *pairA = (const AddressPair *)keyA; - const AddressPair *pairB = (const AddressPair *)keyB; - - return addressPair_Equals(pairA, pairB); -} - -static HashCodeType connectionTable_ConnectionIdHashCode(const void *keyA) { - unsigned idA = *((unsigned *)keyA); - return parcHash32_Int32(idA); -} - -static HashCodeType connectionTable_AddressPairHashCode(const void *keyA) { - const AddressPair *pairA = (const AddressPair *)keyA; - return addressPair_HashCode(pairA); -} - -static void connectionTable_ConnectionIdDestroyer(void **dataPtr) { - unsigned *idA = (unsigned *)*dataPtr; - parcMemory_Deallocate((void **)&idA); - *dataPtr = NULL; -} - -static void connectionTable_ConnectionDestroyer(void **dataPtr) { - connection_Release((Connection **)dataPtr); -} - -ConnectionTable *connectionTable_Create() { - size_t initialSize = 16384; - - ConnectionTable *conntable = - parcMemory_AllocateAndClear(sizeof(ConnectionTable)); - parcAssertNotNull(conntable, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ConnectionTable)); - - conntable->storageTableById = parcHashCodeTable_Create_Size( - connectionTable_ConnectionIdEquals, connectionTable_ConnectionIdHashCode, - connectionTable_ConnectionIdDestroyer, - connectionTable_ConnectionDestroyer, initialSize); - - // no key or data destroyer, this is an index into storageByid. - conntable->indexByAddressPair = parcHashCodeTable_Create_Size( - connectionTable_AddressPairEquals, connectionTable_AddressPairHashCode, - NULL, NULL, initialSize); - - conntable->listById = - parcTreeRedBlack_Create(connectionTable_ConnectionIdCompare, - NULL, // key free - NULL, // key copy - NULL, // value equals - NULL, // value free - NULL); // value copy - - return conntable; -} - -void connectionTable_Destroy(ConnectionTable **conntablePtr) { - parcAssertNotNull(conntablePtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*conntablePtr, - "Parameter must dereference to non-null pointer"); - - ConnectionTable *conntable = *conntablePtr; - - parcTreeRedBlack_Destroy(&conntable->listById); - parcHashCodeTable_Destroy(&conntable->indexByAddressPair); - parcHashCodeTable_Destroy(&conntable->storageTableById); - parcMemory_Deallocate((void **)&conntable); - *conntablePtr = NULL; -} - -/** - * @function connectionTable_Add - * @abstract Add a connection, takes ownership of memory - */ -void connectionTable_Add(ConnectionTable *table, Connection *connection) { - parcAssertNotNull(table, "Parameter table must be non-null"); - parcAssertNotNull(connection, "Parameter connection must be non-null"); - - unsigned *connectionIdKey = parcMemory_Allocate(sizeof(unsigned)); - parcAssertNotNull(connectionIdKey, "parcMemory_Allocate(%zu) returned NULL", - sizeof(unsigned)); - *connectionIdKey = connection_GetConnectionId(connection); - - if (parcHashCodeTable_Add(table->storageTableById, connectionIdKey, - connection)) { - parcHashCodeTable_Add(table->indexByAddressPair, - (void *)connection_GetAddressPair(connection), - connection); - parcTreeRedBlack_Insert(table->listById, connectionIdKey, connection); - } else { - parcTrapUnexpectedState( - "Could not add connection id %u -- is it a duplicate?", - *connectionIdKey); - } -} - -/** - * @function connectionTable_Remove - * @abstract Removes the connection, calling Destroy on our copy - */ -void connectionTable_Remove(ConnectionTable *table, - const Connection *connection) { - parcAssertNotNull(table, "Parameter table must be non-null"); - parcAssertNotNull(connection, "Parameter connection must be non-null"); - - unsigned connid = connection_GetConnectionId(connection); - - parcTreeRedBlack_Remove(table->listById, &connid); - parcHashCodeTable_Del(table->indexByAddressPair, - connection_GetAddressPair(connection)); - parcHashCodeTable_Del(table->storageTableById, &connid); -} - -void connectionTable_RemoveById(ConnectionTable *table, unsigned id) { - parcAssertNotNull(table, "Parameter table must be non-null"); - const Connection *connection = connectionTable_FindById(table, id); - if (connection) { - connectionTable_Remove(table, connection); - } -} - -const Connection *connectionTable_FindByAddressPair(ConnectionTable *table, - const AddressPair *pair) { - parcAssertNotNull(table, "Parameter table must be non-null"); - return (Connection *)parcHashCodeTable_Get(table->indexByAddressPair, pair); -} - -const Connection *connectionTable_FindById(const ConnectionTable *table, - unsigned id) { - parcAssertNotNull(table, "Parameter table must be non-null"); - return (Connection *)parcHashCodeTable_Get(table->storageTableById, &id); -} - -ConnectionList *connectionTable_GetEntries(const ConnectionTable *table) { - parcAssertNotNull(table, "Parameter table must be non-null"); - ConnectionList *list = connectionList_Create(); - - PARCArrayList *values = parcTreeRedBlack_Values(table->listById); - for (size_t i = 0; i < parcArrayList_Size(values); i++) { - Connection *original = parcArrayList_Get(values, i); - connectionList_Append(list, original); - } - parcArrayList_Destroy(&values); - return list; -} diff --git a/hicn-light/src/hicn/core/connectionTable.h b/hicn-light/src/hicn/core/connectionTable.h deleted file mode 100644 index 548ef8e6e..000000000 --- a/hicn-light/src/hicn/core/connectionTable.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 connectionTable_h -#define connectionTable_h - -#include <hicn/core/connection.h> -#include <hicn/core/connectionList.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> - -struct connection_table; -typedef struct connection_table ConnectionTable; - -/** - * Creates an empty connection table - */ -ConnectionTable *connectionTable_Create(void); - -/** - * Destroys the connection table - * This will release the reference to all connections stored in the connection - * table. - * @param [in,out] conntablePtr Pointer to the allocated connection table, will - * be NULL'd - */ -void connectionTable_Destroy(ConnectionTable **conntablePtr); - -/** - * @function connectionTable_Add - * @abstract Add a connection, takes ownership of memory - */ -void connectionTable_Add(ConnectionTable *table, Connection *connection); - -/** - * @function connectionTable_Remove - * @abstract Removes the connection, calling Destroy on our copy - */ -void connectionTable_Remove(ConnectionTable *table, - const Connection *connection); - -/** - * Removes a connection from the connection table - * - * Looks up a connection by its connection ID and removes it from the connection - * table. Removing the connection will call connection_Release() on the - * connection object. - * - * @param [in] table The allocated connection table - * @param [in] id The connection ID - */ -void connectionTable_RemoveById(ConnectionTable *table, unsigned id); - -/** - * Lookup a connection by the (local, remote) addres pair - * - * @param [in] table The allocated connection table - * @param [in] pair The address pair to match, based on the inner values of the - * local and remote addresses - * - * @retval non-null The matched conneciton - * @retval null No match found or error - */ -const Connection *connectionTable_FindByAddressPair(ConnectionTable *table, - const AddressPair *pair); - -/** - * @function connectionTable_FindById - * @abstract Find a connection by its numeric id. - * @return NULL if not found - */ -const Connection *connectionTable_FindById(const ConnectionTable *table, unsigned id); - -/** - * @function connectionTable_GetEntries - * @abstract Returns a list of connections. They are reference counted copies - * from the table. - * @discussion - * An allocated list of connections in the table. Each list entry is a - * reference counted copy of the connection in the table, thus they are "live" - * objects. - */ -ConnectionList *connectionTable_GetEntries(const ConnectionTable *table); -#endif // connectionTable_h diff --git a/hicn-light/src/hicn/core/connection_table.c b/hicn-light/src/hicn/core/connection_table.c new file mode 100644 index 000000000..09236ae8e --- /dev/null +++ b/hicn-light/src/hicn/core/connection_table.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file connection_table.c + * \brief Implementation of hICN connection table + */ + +#include <hicn/util/log.h> + +#include "connection.h" +#include "connection_table.h" + +/* This is only used as a hint for first allocation, as the table is resizeable + */ +#define DEFAULT_CONNECTION_TABLE_SIZE 64 + +connection_table_t *_connection_table_create(size_t init_size, + size_t max_size) { + if (init_size == 0) init_size = DEFAULT_CONNECTION_TABLE_SIZE; + + connection_table_t *table = malloc(sizeof(connection_table_t)); + if (!table) return NULL; + + table->max_size = max_size; + + /* Initialize indices */ + table->id_by_pair = kh_init_ct_pair(); + table->id_by_name = kh_init_ct_name(); + + /* + * We start by allocating a reasonably-sized pool, as this will eventually + * be resized if needed. + */ + pool_init(table->connections, init_size, 0); + + return table; +} + +void connection_table_free(connection_table_t *table) { + const char *k_name; + const address_pair_t *k_pair; + unsigned v_conn_id; + + connection_t *connection; + const char *name; + kh_foreach(table->id_by_name, k_name, v_conn_id, { + connection = connection_table_get_by_id(table, v_conn_id); + name = connection_get_name(connection); + INFO("Removing connection %s [%d]", name, connection->fd); + connection_finalize(connection); + }); + + (void)v_conn_id; + kh_foreach(table->id_by_name, k_name, v_conn_id, { free((char *)k_name); }); + kh_foreach(table->id_by_pair, k_pair, v_conn_id, + { free((address_pair_t *)k_pair); }); + + kh_destroy_ct_pair(table->id_by_pair); + kh_destroy_ct_name(table->id_by_name); + pool_free(table->connections); + free(table); +} + +connection_t *connection_table_get_by_pair(const connection_table_t *table, + const address_pair_t *pair) { + khiter_t k = kh_get_ct_pair(table->id_by_pair, pair); + if (k == kh_end(table->id_by_pair)) return NULL; + return table->connections + kh_val(table->id_by_pair, k); +} + +off_t connection_table_get_id_by_name(const connection_table_t *table, + const char *name) { + khiter_t k = kh_get_ct_name(table->id_by_name, name); + if (k == kh_end(table->id_by_name)) return CONNECTION_ID_UNDEFINED; + return kh_val(table->id_by_name, k); +} + +connection_t *connection_table_get_by_name(const connection_table_t *table, + const char *name) { + unsigned conn_id = connection_table_get_id_by_name(table, name); + if (!connection_id_is_valid(conn_id)) return NULL; + return connection_table_at(table, conn_id); +} + +void connection_table_remove_by_id(connection_table_t *table, off_t id) { + connection_t *connection = connection_table_at(table, id); + INFO("Removing connection %d (%s)", id, connection_get_name(connection)); + + connection_table_deallocate(table, connection); +} + +void connection_table_print_by_pair(const connection_table_t *table) { + const address_pair_t *k; + unsigned v; + + char local_addr_str[NI_MAXHOST], remote_addr_str[NI_MAXHOST]; + int local_port, remote_port; + connection_t *connection; + const char *name; + + INFO("*** Connection table ***"); + kh_foreach(table->id_by_pair, k, v, { + address_to_string(&(k->local), local_addr_str, &local_port); + address_to_string(&(k->remote), remote_addr_str, &remote_port); + connection = connection_table_get_by_id(table, v); + name = connection_get_name(connection); + INFO("(%s:%d - %s:%d)\t\t\t(%u, %s)", local_addr_str, local_port, + remote_addr_str, remote_port, v, name); + }) +} + +void connection_table_print_by_name(const connection_table_t *table) { + const char *k; + unsigned v; + + connection_t *connection; + const char *name; + + INFO("*** Connection table ***"); + kh_foreach(table->id_by_name, k, v, { + connection = connection_table_get_by_id(table, v); + name = connection_get_name(connection); + INFO("(%s)\t\t\t(%u, %s)", k, v, name); + }) +} + +connection_t *_connection_table_get_by_id(connection_table_t *table, off_t id) { + return connection_table_get_by_id(table, id); +} + +#define RANDBYTE() (u8)(rand() & 0xFF) + +char *connection_table_get_random_name(const connection_table_t *table) { + char *connection_name = malloc(SYMBOLIC_NAME_LEN * sizeof(char)); + u8 rand_num; + + /* Generate a random connection name */ + while (1) { + rand_num = RANDBYTE(); + int rc = snprintf(connection_name, SYMBOLIC_NAME_LEN, "conn%u", rand_num); + _ASSERT(rc < SYMBOLIC_NAME_LEN); + + // Return if connection name does not already exist + khiter_t k = kh_get_ct_name(table->id_by_name, connection_name); + if (k == kh_end(table->id_by_name)) break; + } + + return connection_name; +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/core/connection_table.h b/hicn-light/src/hicn/core/connection_table.h new file mode 100644 index 000000000..4c03aa642 --- /dev/null +++ b/hicn-light/src/hicn/core/connection_table.h @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file connection_table.h + * \brief hICN connection_table + * + * The connection table is composed of : + * - a pool of connections allowing access through their id in constant time; + * - a set of indices in the form of hash table for efficient index lookups: + * . by name + * . by address pair + * + * For efficient index retrieval, the header will be prepended and the + * resulting pointer will directly point to the connection pool. + */ + +#ifndef HICNLIGHT_CONNECTION_TABLE_H +#define HICNLIGHT_CONNECTION_TABLE_H + +#include "address_pair.h" +#include "connection.h" +#include "../base/hash.h" +#include "../base/khash.h" +#include "../base/pool.h" + +#define _ct_var(x) _ct_var_##x + +/* Hash functions for indices. */ +#define address_pair_hash(pair) (hash_struct(pair)) +#define address_pair_hash_eq(a, b) \ + (address_pair_hash(b) == address_pair_hash(a)) + +/* Hash table types for indices. */ +KHASH_INIT(ct_pair, const address_pair_t *, unsigned, 1, address_pair_hash, + address_pair_hash_eq); +KHASH_MAP_INIT_STR(ct_name, unsigned); + +typedef struct { + size_t max_size; + + kh_ct_pair_t *id_by_pair; + kh_ct_name_t *id_by_name; + + connection_t *connections; // pool +} connection_table_t; + +/** + * @brief Allocate a connection from the connection table. + * + * @param[in] table The connection table from which to allocate a connection. + * @param[out] connection The pointer that will hold the allocated connection. + * @param[in] pair The address pair associated to the connection (to update + * index). + * @param[in] name The name associated to the connection (to update index). + * + * NOTE: + * - This function updates all indices from the connection table if the + * allocation is successful. + * - You should always check that the returned connection is not NULL, which + * would signal that the pool is exhausted and could not be extended. + */ +static inline connection_t *connection_table_allocate( + const connection_table_t *table, const address_pair_t *pair, + const char *name) { + connection_t *conn; + pool_get(table->connections, conn); + + if (conn) { + off_t id = conn - table->connections; + int res; + khiter_t k; + + // Add in name hash table + k = kh_put_ct_name(table->id_by_name, strdup(name), &res); + kh_value(table->id_by_name, k) = id; + + // Add in pair hash table + address_pair_t *pair_copy = + (address_pair_t *)malloc(sizeof(address_pair_t)); + memcpy(pair_copy, pair, sizeof(address_pair_t)); + + k = kh_put_ct_pair(table->id_by_pair, pair_copy, &res); + assert(res != -1); + kh_value(table->id_by_pair, k) = id; + } + + return conn; +} + +/** + * @brief Deallocate a connection and return it to the connection table pool. + * + * @param[in] table The connection table to which the connection is returned. + * @param[in] conn The connection that is returned to the pool. + * + * NOTE: + * - Upon returning a connection to the pool, all indices pointing to that + * connection are also cleared. + */ +static inline void connection_table_deallocate(const connection_table_t *table, + const connection_t *conn) { + const char *name = connection_get_name(conn); + const address_pair_t *pair = connection_get_pair(conn); + khiter_t k; + + // Remove from name hash table + k = kh_get_ct_name(table->id_by_name, name); + assert(k != kh_end(table->id_by_name)); + free((char *)kh_key(table->id_by_name, k)); + kh_del_ct_name(table->id_by_name, k); + + // Remove from pair hash table + k = kh_get_ct_pair(table->id_by_pair, pair); + assert(k != kh_end(table->id_by_pair)); + free((address_pair_t *)kh_key(table->id_by_pair, k)); + kh_del_ct_pair(table->id_by_pair, k); + + pool_put(table->connections, conn); +} + +/** + * @brief Returns the length of the connection table, the number of active + * connections. + * + * @param[in] table The connection table for which we retrieve the length. + * + * @return size_t The length of the connection table. + * + * NOTE: + * - The length of the connection table, that is the number of currently active + * connections. + */ +#define connection_table_len(table) (pool_len(table->connections)) + +/** + * @brief Validate an index in the connection table. + * + * @param[in] table The connection table in which to validate an index. + * @param[in] id The index of the connection to validate. + * + * @return bool A flag indicating whether the connection index is valid or not. + */ +#define connection_table_validate_id(table, id) \ + pool_validate_id((table)->connections, (id)) + +/** + * @brief Return the connection corresponding to the specified index in the + * connection table. + * + * @param[in] table The connection table for which to retrieve the connection. + * @param[in] id The index for which to retrieve the connection. + * + * @return connection_t * The connection correponding to the specified index in + * the connection table. + * + * @see connection_table_get_by_id + * + * NOTE: + * - In this function, the index is not validated. + */ +#define connection_table_at(table, id) ((table)->connections + id) + +/** + * @brief Return the connection corresponding to the specified and validated + * index in the connection table. + * + * @param[in] table The connection table for which to retrieve the connection. + * @param[in] id The index for which to retrieve the connection. + * + * @return connection_t * The connection correponding to the specified index in + * the connection table. + * + * @see connection_table_get_by_id + * + * NOTE: + * - In this function, the index is validated. + */ +#define connection_table_get_by_id(table, id) \ + connection_table_validate_id(table, id) ? connection_table_at(table, id) \ + : NULL + +/** + * @brief Helper function to avoid macro expansion in c++ tests. Wrapper around + * 'connection_table_get_by_id'. + */ +connection_t *_connection_table_get_by_id(connection_table_t *table, off_t id); + +/** + * @brief Returns the index of a given connection in the connection table. + * + * @param[in] table The connection table from which to retrieve the index. + * @param[in] conn The connection for which to retrieve the index. + * + * @return off_t The index of the specified connection in the connection table. + */ +#define connection_table_get_connection_id(table, conn) \ + (conn - table->connections) + +#define connection_table_foreach(table, conn, BODY) \ + pool_foreach(table->connections, (conn), BODY) + +#define connection_table_enumerate(table, i, conn, BODY) \ + pool_enumerate(table->connections, (i), (conn), BODY) + +/** + * @brief Create a new connection table (extended parameters). + * + * @param[in] init_size Initially allocated size (hint, 0 = use default value). + * @param[in] max_size Maximum size (0 = unlimited). + * + * @return connection_table_t* The newly created connection table. + */ +connection_table_t *_connection_table_create(size_t init_size, size_t max_size); + +/** + * @brief Create a new connection table (minimal parameters). + * + * @return connection_table_t* The newly created connection table. + */ +#define connection_table_create() _connection_table_create(0, 0) + +/** + * @brief Free a connection table + * + * @param[in] table Connection table to free + */ +void connection_table_free(connection_table_t *table); + +/** + * @brief Retrieve a connection from the connection table by address pair. + * + * @param[in] table The connection table in which to search. + * @param[in] pair The address pair to search for. + * + * @return connection_t * The connection matching the specified address pair, or + * NULL if not found. + */ +connection_t *connection_table_get_by_pair(const connection_table_t *table, + const address_pair_t *pair); + +/** + * @brief Return a connection index from the connection table by name. + * + * @param[in] table The connection table in which to search. + * @param[in] name The name to search for. + * + * @return off_t The index of the connection matching the name, or + * CONNECTION_ID_UNDEFINED if not found. + */ +off_t connection_table_get_id_by_name(const connection_table_t *table, + const char *name); + +/** + * @brief Return a connection from the connection table by name. + * + * @param[in] table The connection table in which to search. + * @param[in] name The name to search for. + * + * @return connection_t * The connection matching the name, or NULL if not + * found. + */ +connection_t *connection_table_get_by_name(const connection_table_t *table, + const char *name); + +/** + * @brief Remove a connection from the connection table by its index. + * + * @param[in] table The connection table from which to delete the connection. + * @param[in] id The index of the connection to remove. + */ +void connection_table_remove_by_id(connection_table_t *table, off_t id); + +/** + * @brief Print the connection table content. + * + * @param[in] table The connection table to print. + */ +void connection_table_print_by_pair(const connection_table_t *table); + +void connection_table_print_by_name(const connection_table_t *table); + +char *connection_table_get_random_name(const connection_table_t *table); + +#endif /* HICNLIGHT_CONNECTION_TABLE_H */ diff --git a/hicn-light/src/hicn/core/connection_vft.c b/hicn-light/src/hicn/core/connection_vft.c new file mode 100644 index 000000000..fe97096d3 --- /dev/null +++ b/hicn-light/src/hicn/core/connection_vft.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file connection_vft.c + * @brief Implementation of connection VFT + */ + +#include "connection_vft.h" + +#ifdef __linux +extern connection_ops_t connection_hicn; +#endif + +extern connection_ops_t connection_tcp; +extern connection_ops_t connection_udp; + +const connection_ops_t *connection_vft[] = { +#ifdef __linux + [FACE_PROTOCOL_HICN] = &connection_hicn, +#endif + + [FACE_PROTOCOL_TCP] = &connection_tcp, + [FACE_PROTOCOL_UDP] = &connection_udp, +}; diff --git a/hicn-light/src/hicn/core/connection_vft.h b/hicn-light/src/hicn/core/connection_vft.h new file mode 100644 index 000000000..e6290cdd4 --- /dev/null +++ b/hicn-light/src/hicn/core/connection_vft.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file connection_vft.h + * @brief Connection VFT + */ + +#ifndef HICNLIGHT_CONNECTION_VFT_H +#define HICNLIGHT_CONNECTION_VFT_H + +#include "connection.h" + +typedef struct { + int (*initialize)(connection_t* connection); + void (*finalize)(connection_t* connection); + int (*get_socket)(const listener_t* listener, const address_t* local, + const address_t* remote, const char* interface_name); + bool (*flush)(const connection_t* connection); + bool (*send)(const connection_t* connection, msgbuf_t* msgbuf, bool queue); + int (*send_packet)(const connection_t* connection, const uint8_t* packet, + size_t size); + // void (*read_callback)(connection_t * connection, int fd, void * data); + size_t data_size; +} connection_ops_t; + +#define DECLARE_CONNECTION(NAME) \ + const connection_ops_t connection_##NAME = { \ + .initialize = connection_##NAME##_initialize, \ + .finalize = connection_##NAME##_finalize, \ + .get_socket = listener_##NAME##_get_socket, \ + .flush = connection_##NAME##_flush, \ + .send = connection_##NAME##_send, \ + .send_packet = connection_##NAME##_send_packet, \ + .data_size = sizeof(connection_##NAME##_data_t), \ + }; + +// .read_callback = connection_ ## NAME ## _read_callback, + +extern const connection_ops_t* connection_vft[]; + +#endif /* HICNLIGHT_CONNECTION_VFT_H */ diff --git a/hicn-light/src/hicn/core/content_store.c b/hicn-light/src/hicn/core/content_store.c new file mode 100644 index 000000000..edbdc5ac1 --- /dev/null +++ b/hicn-light/src/hicn/core/content_store.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file content_store.c + * \brief Implementation of hICN content_store + */ + +#include "content_store.h" +#include "packet_cache.h" + +extern const cs_ops_t cs_lru; + +const cs_ops_t *const cs_vft[] = { + [CS_TYPE_LRU] = &cs_lru, +}; + +cs_t *_cs_create(cs_type_t type, size_t max_size) { + if (!CS_TYPE_VALID(type)) { + ERROR("[cs_create] Invalid content store type"); + return NULL; + } + + if (max_size == 0) max_size = DEFAULT_CS_SIZE; + + cs_t *cs = malloc(sizeof(cs_t)); + if (!cs) return NULL; + + cs->type = type; + cs->num_entries = 0; + cs->max_size = max_size; + cs_vft[type]->initialize(cs); + cs->stats.lru = (cs_lru_stats_t){0}; + + return cs; +} + +void cs_free(cs_t *cs) { + assert(cs); + + cs_vft[cs->type]->finalize(cs); + free(cs); +} + +void _cs_clear(cs_t **cs_ptr) { + cs_type_t cs_type = (*cs_ptr)->type; + size_t max_size = (*cs_ptr)->max_size; + + // Free and recreate the CS + cs_free(*cs_ptr); + *cs_ptr = _cs_create(cs_type, max_size); +} + +void cs_hit(cs_t *cs) { + cs->stats.lru.countHits++; + TRACE("ContentStore hit (hits %u, misses %u)", cs->stats.lru.countHits, + cs->stats.lru.countMisses); +} + +void cs_miss(cs_t *cs) { + cs->stats.lru.countMisses++; + TRACE("ContentStore miss (hits %u, misses %u)", cs->stats.lru.countHits, + cs->stats.lru.countMisses); +} + +void cs_log(cs_t *cs) { + DEBUG( + "Content store: size = %u, capacity = %u, hits = %u, misses = %u, adds = " + "%u, updates = %u, deletions = %u (with evictions = %u)", + cs->num_entries, cs->max_size, cs->stats.lru.countHits, + cs->stats.lru.countMisses, cs->stats.lru.countAdds, + cs->stats.lru.countUpdates, cs->stats.lru.countLruDeletions, + cs->stats.lru.countLruEvictions); +} diff --git a/hicn-light/src/hicn/core/content_store.h b/hicn-light/src/hicn/core/content_store.h new file mode 100644 index 000000000..d47d603be --- /dev/null +++ b/hicn-light/src/hicn/core/content_store.h @@ -0,0 +1,106 @@ +#ifndef HICNLIGHT_CS_H +#define HICNLIGHT_CS_H + +#include "../base/pool.h" +#include "../content_store/lru.h" +#include "msgbuf_pool.h" + +#define INVALID_ENTRY_ID ~0ul /* off_t */ +#define DEFAULT_CS_SIZE 256 // Fixed CS size + +typedef struct { + off_t msgbuf_id; + struct { + off_t prev; + off_t next; + } lru; +} cs_entry_t; + +#define cs_entry_get_msgbuf_id(entry) ((entry)->msgbuf_id) + +typedef enum { + CS_TYPE_UNDEFINED, + CS_TYPE_LRU, + CS_TYPE_N, +} cs_type_t; + +#define CS_TYPE_VALID(type) (type != CS_TYPE_UNDEFINED) && (type != CS_TYPE_N) + +typedef struct { + /* The maximum allowed expiry time (will never be exceeded). */ + uint64_t max_expiry_time; // XXX part of lru ? +} cs_options_t; + +typedef struct { + cs_type_t type; + int num_entries; + size_t max_size; + cs_lru_state_t lru; + union { + cs_lru_stats_t lru; + } stats; +} cs_t; + +/** + * @brief Create a new content store (extended parameters). + * + * @param[in] type Content store type + * @param[in] max_size Maximum size (0 = use default value) + * + * @return cs_t* - The newly created content store + */ +cs_t *_cs_create(cs_type_t type, size_t max_size); + +/** + * @brief Create a new content store + * + * @param[in] size Maximum content store size + * + * @return cs_t* - The newly created content store + */ +#define cs_create(size) _cs_create(CS_TYPE_LRU, (size)) + +/** + * @brief Free a content store data structure. + * + * @param[in] pool_ptr Pointer to the content store to free + */ +void cs_free(cs_t *cs); + +/** + * @brief Clear the content of the content store (helper). + * + * @param[in, out] cs Pointer to the content store to clear + */ +void _cs_clear(cs_t **cs); + +/** + * @brief Clear the content of the content store. + * + * @param[in, out] cs Pointer to the content store to clear + */ +#define cs_clear(cs) _cs_clear((cs_t **)&cs); + +/** + * @brief Update content store statistics upon CS hit event. + * + * @param[in] cs Pointer to the content store to use + */ +void cs_hit(cs_t *cs); + +/** + * @brief Update content store statistics upon CS miss event. + * + * @param[in] cs Pointer to the content store to use + */ +void cs_miss(cs_t *cs); + +/** + * @brief Log content store statistics, e.g. the CS current and maximum size, + * the number of matches, misses, add operations, update operations, evictions. + * + * @param cs Pointer to the CS data structure to use + */ +void cs_log(cs_t *cs); + +#endif /* HICNLIGHT_CS_H */ diff --git a/hicn-light/src/hicn/core/dispatcher.c b/hicn-light/src/hicn/core/dispatcher.c deleted file mode 100644 index 59951e950..000000000 --- a/hicn-light/src/hicn/core/dispatcher.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @header dispatcher.c - * @abstract Event dispatcher for hicn-light. Uses parcEvent - * @discussion - * Wraps the functions we use in parcEvent, along with StreamBuffer and - * Message. The dispatcher is the event loop, so it manages things like signals, - * timers, and network events. - */ - -#ifndef _WIN32 -#include <arpa/inet.h> -#include <sys/socket.h> -#include <unistd.h> -#endif -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <hicn/hicn-light/config.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <parc/algol/parc_EventQueue.h> -#include <parc/algol/parc_EventTimer.h> - -#include <parc/assert/parc_Assert.h> - -#include <hicn/core/dispatcher.h> - -#include <pthread.h> - -#ifndef INPORT_ANY -#define INPORT_ANY 0 -#endif - -struct dispatcher { - PARCEventScheduler *Base; - Logger *logger; -}; - -// ========================================== -// Public API - -PARCEventScheduler *dispatcher_GetEventScheduler(Dispatcher *dispatcher) { - return dispatcher->Base; -} - -Dispatcher *dispatcher_Create(Logger *logger) { - Dispatcher *dispatcher = parcMemory_AllocateAndClear(sizeof(Dispatcher)); - parcAssertNotNull(dispatcher, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Dispatcher)); - - dispatcher->Base = parcEventScheduler_Create(); - dispatcher->logger = logger_Acquire(logger); - - parcAssertNotNull(dispatcher->Base, - "Got NULL from parcEventScheduler_Create()"); - - return dispatcher; -} - -void dispatcher_Destroy(Dispatcher **dispatcherPtr) { - parcAssertNotNull(dispatcherPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*dispatcherPtr, - "Parameter must dereference to non-null pointer"); - Dispatcher *dispatcher = *dispatcherPtr; - - logger_Release(&dispatcher->logger); - parcEventScheduler_Destroy(&(dispatcher->Base)); - parcMemory_Deallocate((void **)&dispatcher); - *dispatcherPtr = NULL; -} - -void dispatcher_Stop(Dispatcher *dispatcher) { - struct timeval delay = {0, 1000}; - - parcEventScheduler_Stop(dispatcher->Base, &delay); -} - -void dispatcher_Run(Dispatcher *dispatcher) { - parcAssertNotNull(dispatcher, "Parameter must be non-null"); - - parcEventScheduler_Start(dispatcher->Base, 0); -} - -void dispatcher_RunDuration(Dispatcher *dispatcher, struct timeval *duration) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(duration, "Parameter duration must be non-null"); - - parcEventScheduler_Stop(dispatcher->Base, duration); - parcEventScheduler_Start(dispatcher->Base, 0); -} - -void dispatcher_RunCount(Dispatcher *dispatcher, unsigned count) { - parcAssertNotNull(dispatcher, "Parameter must be non-null"); - - for (unsigned i = 0; i < count; i++) { - parcEventScheduler_Start(dispatcher->Base, - PARCEventSchedulerDispatchType_LoopOnce); - } -} - -PARCEventSocket *dispatcher_CreateListener(Dispatcher *dispatcher, - PARCEventSocket_Callback *callback, - void *user_data, int backlog, - const struct sockaddr *sa, - int socklen) { - PARCEventSocket *listener = parcEventSocket_Create( - dispatcher->Base, callback, NULL, user_data, sa, socklen); - if (listener == NULL) { - perror("Problem creating listener"); - } - return listener; -} - -void dispatcher_DestroyListener(Dispatcher *dispatcher, - PARCEventSocket **listenerPtr) { - parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listenerPtr, - "Parameter must dereference to non-null pointer"); - parcEventSocket_Destroy(listenerPtr); -} - -PARCEventQueue *dispatcher_CreateStreamBufferFromSocket(Dispatcher *dispatcher, - SocketType fd) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - PARCEventQueue *buffer = parcEventQueue_Create( - dispatcher->Base, fd, - PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks); - parcAssertNotNull(buffer, - "Got null from parcEventBufver_Create for socket %d", fd); - return buffer; -} - -PARCEventTimer *dispatcher_CreateTimer(Dispatcher *dispatcher, bool isPeriodic, - PARCEvent_Callback *callback, - void *userData) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(callback, "Parameter callback must be non-null"); - - PARCEventType flags = 0; - if (isPeriodic) { - flags |= PARCEventType_Persist; - } - PARCEventTimer *event = - parcEventTimer_Create(dispatcher->Base, flags, callback, userData); - return event; -} - -void dispatcher_StartTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent, - struct timeval *delay) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(timerEvent, "Parameter timerEvent must be non-null"); - int failure = parcEventTimer_Start(timerEvent, delay); - parcAssertFalse(failure < 0, "Error starting timer event %p: (%d) %s", - (void *)timerEvent, errno, strerror(errno)); -} - -void dispatcher_StopTimer(Dispatcher *dispatcher, PARCEventTimer *event) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(event, "Parameter event must be non-null"); - - int failure = parcEventTimer_Stop(event); - parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s", - (void *)event, errno, strerror(errno)); -} - -void dispatcher_DestroyTimerEvent(Dispatcher *dispatcher, - PARCEventTimer **eventPtr) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(eventPtr, - "Parameter eventPtr must be non-null double pointer"); - parcAssertNotNull(*eventPtr, - "Paramter eventPtr must dereference to non-null pointer"); - - parcEventTimer_Destroy(eventPtr); - eventPtr = NULL; -} - -PARCEvent *dispatcher_CreateNetworkEvent(Dispatcher *dispatcher, - bool isPersistent, - PARCEvent_Callback *callback, - void *userData, int fd) { - short flags = PARCEventType_Timeout | PARCEventType_Read; - if (isPersistent) { - flags |= PARCEventType_Persist; - } - - PARCEvent *event = - parcEvent_Create(dispatcher->Base, fd, flags, callback, userData); - parcAssertNotNull(event, "Got null from parcEvent_Create for socket %d", fd); - return event; -} - -void dispatcher_DestroyNetworkEvent(Dispatcher *dispatcher, - PARCEvent **eventPtr) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(eventPtr, - "Parameter eventPtr must be non-null double pointer"); - parcAssertNotNull(*eventPtr, - "Paramter eventPtr must dereference to non-null pointer"); - - parcEvent_Destroy(eventPtr); - eventPtr = NULL; -} - -void dispatcher_StartNetworkEvent(Dispatcher *dispatcher, PARCEvent *event) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(event, "Parameter event must be non-null"); - - int failure = parcEvent_Start(event); - parcAssertFalse(failure < 0, "Error starting signal event %p: (%d) %s", - (void *)event, errno, strerror(errno)); -} - -void dispatcher_StopNetworkEvent(Dispatcher *dispatcher, PARCEvent *event) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(event, "Parameter event must be non-null"); - - int failure = parcEvent_Stop(event); - parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s", - (void *)event, errno, strerror(errno)); -} - -PARCEventSignal *dispatcher_CreateSignalEvent( - Dispatcher *dispatcher, PARCEventSignal_Callback *callback, void *userData, - int signal) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(callback, "Parameter callback must be non-null"); - - PARCEventSignal *event = parcEventSignal_Create( - dispatcher->Base, signal, PARCEventType_Signal | PARCEventType_Persist, - callback, userData); - parcAssertNotNull(event, - "Got null event when creating signal catcher for signal %d", - signal); - - return event; -} - -void dispatcher_DestroySignalEvent(Dispatcher *dispatcher, - PARCEventSignal **eventPtr) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(eventPtr, - "Parameter eventPtr must be non-null double pointer"); - parcAssertNotNull(*eventPtr, - "Paramter eventPtr must dereference to non-null pointer"); - - parcEventSignal_Destroy(eventPtr); - eventPtr = NULL; -} - -void dispatcher_StartSignalEvent(Dispatcher *dispatcher, - PARCEventSignal *event) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(event, "Parameter event must be non-null"); - - int failure = parcEventSignal_Start(event); - parcAssertFalse(failure < 0, "Error starting signal event %p: (%d) %s", - (void *)event, errno, strerror(errno)); -} - -void dispatcher_StopSignalEvent(Dispatcher *dispatcher, - PARCEventSignal *event) { - parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null"); - parcAssertNotNull(event, "Parameter event must be non-null"); - - int failure = parcEventSignal_Stop(event); - parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s", - (void *)event, errno, strerror(errno)); -} - -/** - * Bind to a local address/port then connect to peer. - */ -static bool dispatcher_StreamBufferBindAndConnect(Dispatcher *dispatcher, - PARCEventQueue *buffer, - struct sockaddr *localSock, - socklen_t localSockLength, - struct sockaddr *remoteSock, - socklen_t remoteSockLength) { - // we need to bind, then connect. Special operation, so we make our - // own fd then pass it off to the buffer event - -#ifndef _WIN32 - int fd = socket(localSock->sa_family, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } - - // Set non-blocking flag - int flags = fcntl(fd, F_GETFL, NULL); - if (flags < 0) { - perror("F_GETFL"); - close(fd); - return -1; - } - int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - if (failure) { - perror("F_SETFL"); - close(fd); - return -1; - } - - failure = bind(fd, localSock, localSockLength); - if (failure) { - perror("bind"); - close(fd); - return false; - } - - parcEventQueue_SetFileDescriptor(buffer, fd); - - failure = parcEventQueue_ConnectSocket(buffer, remoteSock, remoteSockLength); - if (failure && (errno != EINPROGRESS)) { - perror("connect"); - close(fd); - return false; - } -#else - SOCKET fd = socket(localSock->sa_family, SOCK_STREAM, 0); - if (fd == INVALID_SOCKET) { - perror("socket"); - return -1; - } - - // Set non-blocking flag - u_long mode = 1; - int result = ioctlsocket(fd, FIONBIO, &mode); - if (result == NO_ERROR) { - perror("ioctlsocket error"); - closesocket(fd); - WSACleanup(); - return -1; - } - - int failure = bind(fd, localSock, (int)localSockLength); - if (failure) { - perror("bind"); - closesocket(fd); - WSACleanup(); - return false; - } - - parcEventQueue_SetFileDescriptor(buffer, (int)fd); - - failure = parcEventQueue_ConnectSocket(buffer, remoteSock, remoteSockLength); - if (failure && (errno != EINPROGRESS)) { - perror("connect"); - closesocket(fd); - WSACleanup(); - return false; - } -#endif - - return true; -} - -/** - * Connect to an INET peer - * @return NULL on error, otherwise a streambuffer - */ -static PARCEventQueue *dispatcher_StreamBufferConnect_INET( - Dispatcher *dispatcher, const Address *localAddress, - const Address *remoteAddress) { - struct sockaddr_in localSock, remoteSock; - addressGetInet(localAddress, &localSock); - addressGetInet(remoteAddress, &remoteSock); - - PARCEventQueue *buffer = parcEventQueue_Create( - dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree); - parcAssertNotNull(buffer, "got null buffer from parcEventQueue_Create()"); - - bool success = dispatcher_StreamBufferBindAndConnect( - dispatcher, buffer, (struct sockaddr *)&localSock, sizeof(localSock), - (struct sockaddr *)&remoteSock, sizeof(remoteSock)); - if (!success) { - parcEventQueue_Destroy(&buffer); - buffer = NULL; - } - - return buffer; -} - -/** - * Connect to an INET peer - * @return NULL on error, otherwise a streambuffer - */ -static PARCEventQueue * -// static StreamBuffer * -dispatcher_StreamBufferConnect_INET6(Dispatcher *dispatcher, - const Address *localAddress, - const Address *remoteAddress) { - struct sockaddr_in6 localSock, remoteSock; - addressGetInet6(localAddress, &localSock); - addressGetInet6(remoteAddress, &remoteSock); - - PARCEventQueue *buffer = parcEventQueue_Create( - dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree); - parcAssertNotNull(buffer, "got null buffer from parcEventQueue_Create()"); - - bool success = dispatcher_StreamBufferBindAndConnect( - dispatcher, buffer, (struct sockaddr *)&localSock, sizeof(localSock), - (struct sockaddr *)&remoteSock, sizeof(remoteSock)); - if (!success) { - parcEventQueue_Destroy(&buffer); - buffer = NULL; - } - - return buffer; -} - -PARCEventQueue *dispatcher_StreamBufferConnect(Dispatcher *dispatcher, - const AddressPair *pair) { - const Address *localAddress = addressPair_GetLocal(pair); - const Address *remoteAddress = addressPair_GetRemote(pair); - - // they must be of the same address family - if (addressGetType(localAddress) != addressGetType(remoteAddress)) { - char message[2048]; - char *localAddressString = addressToString(localAddress); - char *remoteAddressString = addressToString(remoteAddress); - snprintf(message, 2048, - "Remote address not same type as local address, expected %d got " - "%d\nlocal %s remote %s", - addressGetType(localAddress), addressGetType(remoteAddress), - localAddressString, remoteAddressString); - - parcMemory_Deallocate((void **)&localAddressString); - parcMemory_Deallocate((void **)&remoteAddressString); - - parcAssertTrue( - addressGetType(localAddress) == addressGetType(remoteAddress), "%s", - message); - } - - address_type type = addressGetType(localAddress); - - PARCEventQueue *result = NULL; - - switch (type) { - case ADDR_INET: - return dispatcher_StreamBufferConnect_INET(dispatcher, localAddress, - remoteAddress); - break; - case ADDR_INET6: - return dispatcher_StreamBufferConnect_INET6(dispatcher, localAddress, - remoteAddress); - break; - default: - parcTrapIllegalValue(type, "local address unsupported address type: %d", - type); - } - return result; -} diff --git a/hicn-light/src/hicn/core/dispatcher.h b/hicn-light/src/hicn/core/dispatcher.h deleted file mode 100644 index e5c2df336..000000000 --- a/hicn-light/src/hicn/core/dispatcher.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @header hicn-light Dispatcher - * @abstract The dispatcher is the event loop run by Forwarder. - * @discussion - * These functions manage listeners, timers, and network events inside - * the event loop. - * - * Curently, it is a thin wrapper around an event so we don't have to - * expose that implementation detail to other modules. - * - */ - -#ifndef dispatcher_h -#define dispatcher_h - -#ifndef _WIN32 -#include <sys/socket.h> -#endif -#include <stdbool.h> - -struct dispatcher; -typedef struct dispatcher Dispatcher; - -#include <parc/algol/parc_Event.h> -#include <parc/algol/parc_EventQueue.h> -#include <parc/algol/parc_EventScheduler.h> -#include <parc/algol/parc_EventSignal.h> -#include <parc/algol/parc_EventSocket.h> -#include <parc/algol/parc_EventTimer.h> -#include <parc/algol/parc_Memory.h> - -#include <hicn/core/logger.h> - -PARCEventScheduler *dispatcher_GetEventScheduler(Dispatcher *dispatcher); -/** - * Creates an event dispatcher - * - * Event dispatcher based on PARCEvent - * - * @return non-null Allocated event dispatcher - * @return null An error - */ -Dispatcher *dispatcher_Create(Logger *logger); - -/** - * Destroys event dispatcher - * - * Caller is responsible for destroying call events before destroying - * the event dispatcher. - */ -void dispatcher_Destroy(Dispatcher **dispatcherPtr); - -/** - * @function dispatcher_Stop - * @abstract Called from a different thread, tells the dispatcher to stop - * @discussion - * Called from a user thread or from an interrupt handler. - * Does not block. Use <code>dispatcher_WaitForStopped()</code> to - * block until stopped after calling this. - */ -void dispatcher_Stop(Dispatcher *dispatcher); - -/** - * @function dispatcher_WaitForStopped - * @abstract Blocks until dispatcher in stopped state - * @discussion - * Used after <code>dispatcher_Stop()</code> to wait for stop. - */ -void dispatcher_WaitForStopped(Dispatcher *dispatcher); - -/** - * @function dispatcher_Run - * @abstract Runs the forwarder, blocks. - */ -void dispatcher_Run(Dispatcher *dispatcher); - -/** - * @function dispatcher_RunDuration - * @abstract Runs forwarder for at most duration, blocks. - * @discussion - * Blocks running the forwarder for a duration. May be called - * iteratively to keep running. Duration is a minimum, actual - * runtime may be slightly longer. - */ -void dispatcher_RunDuration(Dispatcher *dispatcher, struct timeval *duration); - -/** - * @header dispatcher_RunCount - * @abstract Run the event loop for the given count cycles - * @discussion - * Runs the event loop for the given number of cycles, blocking - * until done. May be called sequentially over and over. - * - */ -void dispatcher_RunCount(Dispatcher *dispatcher, unsigned count); - -typedef int SocketType; - -typedef struct evconnlistener Listener; - -/** - * @typedef ListenerCallback - * @abstract Callback function typedef for a stream listener - * - * @constant listener is the object created by <code>forwarder_NewBind()</code> - * that received the client connection - * @constant client_socket is the client socket - * @constant user_data is the user_data passed to - * <code>forwarder_NewBind()</code> - * @constant client_addr is the client address - * @constant socklen is the length of client_addr - * @discussion <#Discussion#> - */ -typedef void(ListenerCallback)(Listener *listener, SocketType client_socket, - struct sockaddr *client_addr, int socklen, - void *user_data); - -/** - * @header forwarder_NewBind - * @abstract Allocate a new stream listener - * @discussion - * The server socket will be freed when closed and will be reusable. - * - * @param forwarder that owns the event loop - * @param cb is the callback for a new connection - * @param user_data is opaque user data passed to the callback - * @param backlog is the listen() depth, may use -1 for a default value - * @param sa is the socket address to bind to (INET, INET6, LOCAL) - * @param socklen is the sizeof the actual sockaddr (e.g. sizeof(sockaddr_un)) - */ -PARCEventSocket *dispatcher_CreateListener(Dispatcher *dispatcher, - PARCEventSocket_Callback *callback, - void *user_data, int backlog, - const struct sockaddr *sa, - int socklen); - -void dispatcher_DestroyListener(Dispatcher *dispatcher, - PARCEventSocket **listenerPtr); - -typedef struct event TimerEvent; -typedef struct event NetworkEvent; -typedef struct event SignalEvent; - -/** - * @typedef EventCallback - * @abstract A network event or a timer callback - * @constant fd The file descriptor associated with the event, may be -1 for - * timers - * @constant which_event is a bitmap of the EventType - * @constant user_data is the user_data passed to - * <code>Forwarder_CreateEvent()</code> - */ -typedef void(EventCallback)(SocketType fd, short which_event, void *user_data); - -/** - * @function dispatcher_CreateTimer - * @abstract Creates a Event for use as a timer. - * @discussion - * - * When created, the timer is idle and you need to call - * <code>forwarder_StartTimer()</code> - * - * @param isPeriodic means the timer will fire repeatidly, otherwise it is a - * one-shot and needs to be set again with <code>dispatcher_StartTimer()</code> - */ -PARCEventTimer *dispatcher_CreateTimer(Dispatcher *dispatcher, bool isPeriodic, - PARCEvent_Callback *callback, - void *userData); - -/** - * @function dispatcher_StartTimer - * @abstract Starts the timer with the given delay. - * @discussion - * If the timer is periodic, it will keep firing with the given delay - */ -void dispatcher_StartTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent, - struct timeval *delay); - -void dispatcher_StopTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent); - -/** - * @function dispatcher_DestroyTimerEvent - * @abstract Cancels the timer and frees the event - */ -void dispatcher_DestroyTimerEvent(Dispatcher *dispatcher, - PARCEventTimer **eventPtr); - -/** - * @function dispatcher_CreateNetworkEvent - * @abstract Creates a network event callback on the socket - * @discussion - * May be used on any sort of file descriptor or socket. The event is edge - * triggered and non-reentrent. This means you need to drain the events off the - * socket, as the callback will not be called again until a new event arrives. - * - * When created, the event is idle and you need to call - * <code>forwarder_StartNetworkEvent()</code> - * - * @param isPersistent means the callback will keep firing with new events, - * otherwise its a one-shot - * @param fd is the socket to monitor - */ -PARCEvent *dispatcher_CreateNetworkEvent(Dispatcher *dispatcher, - bool isPersistent, - PARCEvent_Callback *callback, - void *userData, int fd); - -void dispatcher_StartNetworkEvent(Dispatcher *dispatcher, PARCEvent *event); -void dispatcher_StopNetworkEvent(Dispatcher *dispatcher, PARCEvent *event); - -void dispatcher_DestroyNetworkEvent(Dispatcher *dispatcher, - PARCEvent **eventPtr); - -/** - * @function dispatcher_CreateSignalEvent - * @abstract Creates a signal trap - * @discussion - * May be used on catchable signals. The event is edge triggered and - * non-reentrent. Signal events are persistent. - * - * When created, the signal trap is idle and you need to call - * <code>forwarder_StartSignalEvent()</code> - * - * @param signal is the system signal to monitor (e.g. SIGINT). - * @return <#return#> - */ -PARCEventSignal *dispatcher_CreateSignalEvent( - Dispatcher *dispatcher, PARCEventSignal_Callback *callback, void *userData, - int signal); - -void dispatcher_DestroySignalEvent(Dispatcher *dispatcher, - PARCEventSignal **eventPtr); - -void dispatcher_StartSignalEvent(Dispatcher *dispatcher, - PARCEventSignal *event); -void dispatcher_StopSignalEvent(Dispatcher *dispatcher, PARCEventSignal *event); - -// ============= -// stream buffers - -#include <hicn/core/streamBuffer.h> -#include <hicn/io/addressPair.h> - -/** - * @function dispatcher_CreateStreamBuffer - * @abstract Creates a high-function buffer around a stream socket - */ -PARCEventQueue *dispatcher_CreateStreamBufferFromSocket(Dispatcher *dispatcher, - SocketType fd); - -/** - * @function dispatcher_StreamBufferConnect - * @abstract Create a TCP tunnel to a remote peer - * @discussion - * For TCP, both address pairs need to be the same address family: both INET - * or both INET6. The remote address must have the complete socket information - * (address, port). The local socket could be wildcarded or may specify down to - * the (address, port) pair. - * - * If the local address is IPADDR_ANY and the port is 0, then it is a normal - * call to "connect" that will use whatever local IP address and whatever local - * port for the connection. If either the address or port is set, the local - * socket will first be bound (via bind(2)), and then call connect(). - * - * It is unlikely that the buffer will be connected by the time the function - * returns. The eventCallback will fire once the remote system accepts the - * conneciton. - * - * @return NULL on error, otherwise a streambuffer. - */ -PARCEventQueue *dispatcher_StreamBufferConnect(Dispatcher *dispatcher, - const AddressPair *pair); -#endif // dispatcher_h diff --git a/hicn-light/src/hicn/core/fib.c b/hicn-light/src/hicn/core/fib.c new file mode 100644 index 000000000..d8d3c7cfa --- /dev/null +++ b/hicn-light/src/hicn/core/fib.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <hicn/hicn-light/config.h> +#include <stdio.h> + +#include <hicn/core/fib.h> + +typedef struct fib_node_s { + struct fib_node_s *left; + struct fib_node_s *right; + fib_entry_t *entry; + bool is_used; +} fib_node_t; + +static fib_node_t *fib_node_create(fib_node_t *left, fib_node_t *right, + fib_entry_t *entry, bool is_used) { + fib_node_t *node = malloc(sizeof(fib_node_t)); + if (!node) return NULL; + + *node = (fib_node_t){ + .left = left, + .right = right, + .entry = entry, + .is_used = is_used, + }; + + return node; +} + +static void fib_node_free(fib_node_t *node) { + if (!node) return; + + fib_node_free(node->right); + fib_node_free(node->left); + + fib_entry_free(node->entry); + free(node); +} + +/******************************************************************************/ + +struct fib_s { + void *forwarder; + fib_node_t *root; + unsigned size; +}; + +fib_t *fib_create(void *forwarder) { + fib_t *fib = malloc(sizeof(fib_t)); + if (!fib) return NULL; + + fib->forwarder = forwarder; + fib->root = NULL; + fib->size = 0; + + return fib; +} + +void fib_free(fib_t *fib) { + assert(fib); + + fib_node_free(fib->root); + + free(fib); +} + +size_t fib_get_size(const fib_t *fib) { + assert(fib); + return fib->size; +} + +#define FIB_SET(CURR, NEW_PREFIX, CURR_PREFIX_LEN) \ + do { \ + bool bit; \ + int res = nameBitvector_testBit(NEW_PREFIX, CURR_PREFIX_LEN, &bit); \ + assert(res >= 0); \ + (void)res; /* unused */ \ + CURR = bit ? CURR->right : CURR->left; \ + } while (0) + +#define FIB_INSERT(DST, SRC, PREFIX, PREFIX_LEN) \ + do { \ + bool bit; \ + int res = nameBitvector_testBit(PREFIX, PREFIX_LEN, &bit); \ + assert(res >= 0); \ + (void)res; /* unused */ \ + if (bit) \ + DST->right = SRC; \ + else \ + DST->left = SRC; \ + } while (0) + +void fib_add(fib_t *fib, fib_entry_t *entry) { + assert(fib); + assert(entry); + + NameBitvector *new_prefix = name_GetContentName(fib_entry_get_prefix(entry)); + uint32_t new_prefix_len = nameBitvector_GetLength(new_prefix); + fib_node_t *curr = fib->root; + fib_node_t *last = NULL; + + NameBitvector *curr_name; + uint32_t curr_prefix_len; + uint32_t match_len; + + while (curr) { + curr_name = name_GetContentName(fib_entry_get_prefix(curr->entry)); + + match_len = nameBitvector_lpm(new_prefix, curr_name); + curr_prefix_len = nameBitvector_GetLength(curr_name); + + if (curr_prefix_len != + match_len || // the new entry does not match the curr + curr_prefix_len >= + new_prefix_len) // in this case we cannot procede anymore + break; + + last = curr; + FIB_SET(curr, new_prefix, curr_prefix_len); + } + + // this is the root (empty trie) or an empty child + if (!curr) { + fib_node_t *new_node = fib_node_create(NULL, NULL, entry, true); + if (!last) { + fib->root = new_node; + } else { + uint32_t last_prefix_len = nameBitvector_GetLength( + name_GetContentName(fib_entry_get_prefix(last->entry))); + + FIB_INSERT(last, new_node, new_prefix, last_prefix_len); + } + fib->size++; + return; + } + + // curr is not null + + // the node already exist + // if is not in use we turn it on and we set the rigth fib entry + if (curr_prefix_len == match_len && new_prefix_len == match_len) { + if (!curr->is_used) { + curr->is_used = true; + curr->entry = entry; + fib->size++; + return; + } else { + // this case should never happen beacuse of the way we add + // entries in the fib + const nexthops_t *nexthops = fib_entry_get_nexthops(entry); + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, + { fib_entry_nexthops_add(curr->entry, nexthop); }); + } + } + + // key is prefix of the curr node (so new_prefix_len < curr_prefix_len) + if (new_prefix_len == match_len) { + fib_node_t *new_node = fib_node_create(NULL, NULL, entry, true); + if (!last) { + fib->root = new_node; + } else { + uint32_t last_prefix_len = nameBitvector_GetLength( + name_GetContentName(fib_entry_get_prefix(last->entry))); + FIB_INSERT(last, new_node, new_prefix, last_prefix_len); + } + FIB_INSERT(new_node, curr, curr_name, match_len); + fib->size++; + return; + } + + // in the last case we need to add an inner node + Name inner_prefix = EMPTY_NAME; + name_Copy(fib_entry_get_prefix(entry), &inner_prefix); + nameBitvector_clear(name_GetContentName(&inner_prefix), match_len); + name_setLen(&inner_prefix, match_len); + + // this is an inner node, we don't want an acctive strategy + // like low_latency that sends probes in this node + fib_entry_t *inner_entry = fib_entry_create( + &inner_prefix, STRATEGY_TYPE_UNDEFINED, NULL, fib->forwarder); + + fib_node_t *inner_node = fib_node_create(NULL, NULL, inner_entry, false); + fib_node_t *new_node = fib_node_create(NULL, NULL, entry, true); + + if (!last) { + // we need to place the inner_node at the root + fib->root = inner_node; + } else { + uint32_t last_prefix_len = nameBitvector_GetLength( + name_GetContentName(fib_entry_get_prefix(last->entry))); + NameBitvector *inner_name = name_GetContentName(&inner_prefix); + FIB_INSERT(last, inner_node, inner_name, last_prefix_len); + } + + bool bit; + int res = nameBitvector_testBit(new_prefix, match_len, &bit); + assert(res >= 0); + (void)res; /* unused */ + inner_node->left = bit ? curr : new_node; + inner_node->right = bit ? new_node : curr; + fib->size++; +} + +fib_entry_t *fib_contains(const fib_t *fib, const Name *prefix) { + assert(fib); + assert(prefix); + + NameBitvector *key_name = name_GetContentName(prefix); + uint32_t key_prefix_len = nameBitvector_GetLength(key_name); + + fib_node_t *curr = fib->root; + + while (curr) { + NameBitvector *curr_name = + name_GetContentName(fib_entry_get_prefix(curr->entry)); + uint32_t match_len = nameBitvector_lpm(key_name, curr_name); + uint32_t curr_prefix_len = nameBitvector_GetLength(curr_name); + + if (match_len < curr_prefix_len) { + // the current node does not match completelly the key, so + // the key is not in the trie + // this implies curr_prefix_len > key_prefix_len + return NULL; + } + + if (curr_prefix_len == key_prefix_len) { //== match_len + // this is an exact match + if (!curr->is_used) { + // the key does not exists + return NULL; + } + // we found the key + return curr->entry; + } + + FIB_SET(curr, key_name, curr_prefix_len); + } + + return NULL; +} + +static void fib_node_remove(fib_t *fib, const Name *prefix) { + assert(fib); + assert(prefix); + + NameBitvector *key_name = name_GetContentName(prefix); + uint32_t key_prefix_len = nameBitvector_GetLength(key_name); + + fib_node_t *curr = fib->root; + fib_node_t *parent = NULL; + fib_node_t *grandpa = NULL; + + uint32_t match_len; + uint32_t curr_prefix_len; + + while (curr) { + NameBitvector *curr_name = + name_GetContentName(fib_entry_get_prefix(curr->entry)); + match_len = nameBitvector_lpm(key_name, curr_name); + curr_prefix_len = nameBitvector_GetLength(curr_name); + + if (match_len < curr_prefix_len || curr_prefix_len == key_prefix_len) { + break; + } + + grandpa = parent; + parent = curr; + + FIB_SET(curr, key_name, curr_prefix_len); + } + + if (!curr || !curr->is_used || (curr_prefix_len != key_prefix_len)) { + // the node does not exists + return; + } + + // curr has 2 children, leave it there and mark it as inner + if (curr->right && curr->left) { + curr->is_used = false; + fib->size--; + return; + } + + // curr has no children + if (!curr->right && !curr->left) { + if (!parent) { + // curr is the root and is the only node in the fib + fib->root = NULL; + fib->size--; + fib_node_free(curr); + return; + } + if (!grandpa) { + // parent is the root + if (fib->root->left == curr) + fib->root->left = NULL; + else + fib->root->right = NULL; + fib->size--; + fib_node_free(curr); + return; + } + if (!parent->is_used) { + // parent is an inner node + // remove curr and inner_node (parent), connect the other child + // of the parent to the grandpa + fib_node_t *tmp = (parent->right == curr) ? parent->left : parent->right; + + if (grandpa->right == parent) + grandpa->right = tmp; + else + grandpa->left = tmp; + + fib->size--; + fib_node_free(curr); + fib_node_free(parent); + return; + } + // parent is node not an inner_node + // just remove curr the node + if (parent->right == curr) + parent->right = NULL; + else + parent->left = NULL; + fib->size--; + fib_node_free(curr); + return; + } + + // curr has one child + if (curr->right || curr->left) { + if (!parent) { + // curr is the root + fib->root = fib->root->right ? fib->root->right : fib->root->left; + fib->size--; + fib_node_free(curr); + return; + } + // attach the child of curr to parent + fib_node_t *tmp = curr->right ? curr->right : curr->left; + + if (parent->right == curr) + parent->right = tmp; + else + parent->left = tmp; + + fib->size--; + fib_node_free(curr); + return; + } +} + +void fib_remove(fib_t *fib, const Name *name, unsigned conn_id) { + assert(fib); + assert(name); + + fib_entry_t *entry = fib_contains(fib, name); + if (!entry) return; + + fib_entry_nexthops_remove(entry, conn_id); +#ifndef WITH_MAPME + if (fib_entry_nexthops_len(entry) == 0) fib_node_remove(fib, name); +#endif /* WITH_MAPME */ +} + +static size_t fib_node_remove_connection_id(fib_node_t *node, unsigned conn_id, + fib_entry_t **array, size_t pos) { + if (!node) return pos; + if (node->is_used) { + fib_entry_nexthops_remove(node->entry, conn_id); +#ifndef WITH_MAPME + if (fib_entry_nexthops_len(node->entry) == 0) array[pos++] = node->entry; +#endif /* WITH_MAPME */ + } + pos = fib_node_remove_connection_id(node->right, conn_id, array, pos); + pos = fib_node_remove_connection_id(node->left, conn_id, array, pos); + return pos; +} + +void fib_remove_connection_id(fib_t *fib, unsigned conn_id) { + assert(fib); + + fib_entry_t **array = malloc(sizeof(fib_entry_t *) * fib->size); + + size_t pos = 0; + pos = fib_node_remove_connection_id(fib->root, conn_id, array, pos); + + for (int i = 0; i < pos; i++) + fib_node_remove(fib, fib_entry_get_prefix(array[i])); + free(array); +} + +fib_entry_t *fib_match_message(const fib_t *fib, + const msgbuf_t *interest_msgbuf) { + assert(fib); + assert(interest_msgbuf); + + return fib_match_bitvector( + fib, name_GetContentName(msgbuf_get_name(interest_msgbuf))); +} + +fib_entry_t *fib_match_name(const fib_t *fib, const Name *name) { + assert(fib); + assert(name); + + return fib_match_bitvector(fib, name_GetContentName(name)); +} + +fib_entry_t *fib_match_bitvector(const fib_t *fib, const NameBitvector *name) { + assert(fib); + assert(name); + + uint32_t key_prefix_len = nameBitvector_GetLength(name); + + fib_node_t *curr = fib->root; + fib_node_t *candidate = NULL; + + while (curr) { + NameBitvector *curr_name = + name_GetContentName(fib_entry_get_prefix(curr->entry)); + uint32_t match_len = nameBitvector_lpm(name, curr_name); + uint32_t curr_prefix_len = nameBitvector_GetLength(curr_name); + + if (match_len < curr_prefix_len) { + // the current node does not match completelly the key, so + // return the parent of this node (saved in candidate) + break; + } + + if (curr->is_used) candidate = curr; + + // if we are here match_len == curr_prefix_len (can't be larger) + // so this node is actually a good candidate for a match + if (curr_prefix_len == key_prefix_len) { + // this an exact match, do not continue + break; + } + + FIB_SET(curr, name, curr_prefix_len); + } + + return candidate ? candidate->entry : NULL; +} + +static size_t fib_node_collect_entries(fib_node_t *node, fib_entry_t **array, + size_t pos) { + assert(array); + + if (!node) return pos; + + if (node->is_used) array[pos++] = node->entry; + + pos = fib_node_collect_entries(node->right, array, pos); + pos = fib_node_collect_entries(node->left, array, pos); + return pos; +} + +size_t fib_get_entry_array(const fib_t *fib, fib_entry_t ***array_p) { + size_t pos = 0; + *array_p = malloc(sizeof(fib_entry_t *) * fib->size); + if (!*array_p) return pos; + pos = fib_node_collect_entries(fib->root, *array_p, pos); + return pos; +} diff --git a/hicn-light/src/hicn/core/fib.h b/hicn-light/src/hicn/core/fib.h new file mode 100644 index 000000000..c0fda960b --- /dev/null +++ b/hicn-light/src/hicn/core/fib.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 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 HICNLIGHT_FIB_H +#define HICNLIGHT_FIB_H + +#include "fib_entry.h" +#include "msgbuf.h" +#include "name.h" + +#define _fib_var(x) _fib_##x + +typedef struct fib_s fib_t; + +fib_t *fib_create(void *forwarder); + +void fib_free(fib_t *fib); + +size_t fib_get_size(const fib_t *fib); + +void fib_add(fib_t *fib, fib_entry_t *node); + +fib_entry_t *fib_contains(const fib_t *fib, const Name *prefix); + +void fib_remove(fib_t *fib, const Name *prefix, unsigned conn_id); + +void fib_remove_connection_id(fib_t *fib, unsigned conn_id); + +fib_entry_t *fib_match_message(const fib_t *fib, + const msgbuf_t *interest_msgbuf); +fib_entry_t *fib_match_name(const fib_t *fib, const Name *name); +fib_entry_t *fib_match_bitvector(const fib_t *fib, const NameBitvector *name); + +size_t fib_get_entry_array(const fib_t *fib, fib_entry_t ***array_p); + +#define fib_foreach_entry(FIB, ENTRY, BODY) \ + do { \ + fib_entry_t **_fib_var(array); \ + size_t _fib_var(n) = fib_get_entry_array((FIB), &_fib_var(array)); \ + size_t _fib_var(i); \ + for (_fib_var(i) = 0; _fib_var(i) < _fib_var(n); _fib_var(i)++) { \ + ENTRY = _fib_var(array)[_fib_var(i)]; \ + do { \ + BODY \ + } while (0); \ + } \ + free(_fib_var(array)); \ + } while (0) + +#endif /* HICNLIGHT_FIB_H */ diff --git a/hicn-light/src/hicn/core/fib_entry.c b/hicn-light/src/hicn/core/fib_entry.c new file mode 100644 index 000000000..616f12961 --- /dev/null +++ b/hicn-light/src/hicn/core/fib_entry.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <stdio.h> + +#include <hicn/hicn-light/config.h> +#include <hicn/core/fib_entry.h> +#include <hicn/core/strategy.h> +#include <hicn/core/nameBitvector.h> + +#ifdef WITH_MAPME +#include <hicn/core/ticks.h> +#endif /* WITH_MAPME */ + +#ifdef WITH_POLICY +#include <hicn/core/forwarder.h> +#include <hicn/policy.h> + +#ifdef WITH_MAPME +#include <hicn/core/mapme.h> +#endif /* WITH_MAPME */ + +#endif /* WITH_POLICY */ + +#ifdef WITH_POLICY_STATS +#include <hicn/core/policy_stats.h> +#endif /* WITH_POLICY_STATS */ + +fib_entry_t *fib_entry_create(Name *name, strategy_type_t strategy_type, + strategy_options_t *strategy_options, + const forwarder_t *forwarder) { + assert(name); + assert(forwarder); + + fib_entry_t *entry = malloc(sizeof(fib_entry_t)); + if (!entry) goto ERR_MALLOC; + + memset(entry, 0, sizeof(*entry)); + name_Copy(name, &entry->name); + entry->nexthops = NEXTHOPS_EMPTY; + + fib_entry_add_strategy_options(entry, STRATEGY_TYPE_BESTPATH, NULL); + fib_entry_add_strategy_options(entry, STRATEGY_TYPE_REPLICATION, NULL); + fib_entry_set_strategy(entry, strategy_type, strategy_options); + +#ifdef WITH_MAPME + entry->user_data = NULL; + entry->user_data_release = NULL; +#endif /* WITH_MAPME */ + + entry->forwarder = forwarder; + +#ifdef WITH_POLICY + entry->policy = POLICY_EMPTY; +#endif /* WITH_POLICY */ + +#ifdef WITH_POLICY_STATS + entry->policy_stats = POLICY_STATS_EMPTY; + entry->policy_counters = POLICY_COUNTERS_EMPTY; +#endif /* WITH_POLICY_STATS */ + + return entry; + +ERR_MALLOC: + return NULL; +} + +void fib_entry_free(fib_entry_t *entry) { + assert(entry); +#ifdef WITH_MAPME + if (entry->user_data) entry->user_data_release(&entry->user_data); +#endif /* WITH_MAPME */ + free(entry); +} + +void fib_entry_add_strategy_options(fib_entry_t *entry, + strategy_type_t strategy_type, + strategy_options_t *strategy_options) { + // for the moment only the best path and replication strategies support + // strategy options return for the other strategyes + if (strategy_type != STRATEGY_TYPE_BESTPATH && + strategy_type != STRATEGY_TYPE_REPLICATION) + return; + + if (!strategy_options) { + if (strategy_type == STRATEGY_TYPE_BESTPATH) { + entry->strategy.options.bestpath.local_prefixes = NULL; + } else { + entry->strategy.options.replication.local_prefixes = NULL; + } + return; + } + + local_prefixes_t *new_prefixes; + local_prefixes_t *curr_prefixes; + + if (strategy_type == STRATEGY_TYPE_BESTPATH) { + new_prefixes = strategy_options->bestpath.local_prefixes; + curr_prefixes = entry->strategy.options.bestpath.local_prefixes; + + if (!curr_prefixes) { + entry->strategy.options.bestpath.local_prefixes = create_local_prefixes(); + curr_prefixes = entry->strategy.options.bestpath.local_prefixes; + } + } else { + new_prefixes = strategy_options->replication.local_prefixes; + curr_prefixes = entry->strategy.options.replication.local_prefixes; + + if (!curr_prefixes) { + entry->strategy.options.replication.local_prefixes = + create_local_prefixes(); + curr_prefixes = entry->strategy.options.replication.local_prefixes; + } + } + + local_prefixes_add_prefixes(curr_prefixes, new_prefixes); +} + +void fib_entry_set_strategy(fib_entry_t *entry, strategy_type_t strategy_type, + strategy_options_t *strategy_options) { + // Default strategy if undefined + if (!STRATEGY_TYPE_VALID(strategy_type)) strategy_type = STRATEGY_TYPE_RANDOM; + + if (entry->strategy.type == strategy_type) { // startegy alredy set + if (strategy_type != STRATEGY_TYPE_BESTPATH) { + return; // nothing to do + } else { + strategy_initialize(&entry->strategy, entry->forwarder); + return; + } + } + + entry->strategy.type = strategy_type; + if (strategy_options) entry->strategy.options = *strategy_options; + + strategy_initialize(&entry->strategy, entry->forwarder); +} + +#ifdef WITH_POLICY + +nexthops_t *fib_entry_filter_nexthops(fib_entry_t *entry, nexthops_t *nexthops, + unsigned ingress_id, bool prefer_local) { + assert(entry); + assert(nexthops); + + nexthops_reset(nexthops); + + // DEBUG("[fib_entry_filter_nexthops] num=%d/%d ingress_id=%d", + // nexthops_get_curlen(nexthops), nexthops_get_len(nexthops), + // ingress_id); + + /* Filter out ingress, down & administrative down faces */ + const connection_table_t *table = + forwarder_get_connection_table(entry->forwarder); + connection_t *conn; + unsigned nexthop, i; + uint_fast32_t flags; + + hicn_policy_t policy = fib_entry_get_policy(entry); + + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, nexthop == ingress_id); + nexthops_disable_if(nexthops, i, + (connection_get_admin_state(conn) == FACE_STATE_DOWN)); + nexthops_disable_if(nexthops, i, + (connection_get_state(conn) == FACE_STATE_DOWN)); + }); + + // DEBUG("After pruning, num=%d/%d", nexthops_get_curlen(nexthops), + // nexthops_get_len(nexthops)); + + if (prefer_local) { + /* Backup flags and cur_len*/ + flags = nexthops->flags; + size_t cur_len = nexthops_get_curlen(nexthops); + + /* Filter local */ + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, (!connection_is_local(conn))); + }); + + /* Local faces have priority */ + if (nexthops_get_curlen(nexthops) > 0) return nexthops; + + nexthops->flags = flags; + nexthops->cur_elts = cur_len; + } + + /* Filter out local */ + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, (connection_is_local(conn))); + + /* Policy filtering : next hops */ + nexthops_disable_if( + nexthops, i, + (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_REQUIRE) && + (!connection_has_tag(conn, POLICY_TAG_WIRED))); + nexthops_disable_if( + nexthops, i, + (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_PROHIBIT) && + (connection_has_tag(conn, POLICY_TAG_WIRED))); + nexthops_disable_if( + nexthops, i, + (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_REQUIRE) && + (!connection_has_tag(conn, POLICY_TAG_WIFI))); + nexthops_disable_if( + nexthops, i, + (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_PROHIBIT) && + (connection_has_tag(conn, POLICY_TAG_WIFI))); + nexthops_disable_if( + nexthops, i, + (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_REQUIRE) && + (!connection_has_tag(conn, POLICY_TAG_CELLULAR))); + nexthops_disable_if( + nexthops, i, + (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_PROHIBIT) && + (connection_has_tag(conn, POLICY_TAG_CELLULAR))); + nexthops_disable_if( + nexthops, i, + (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE) && + (!connection_has_tag(conn, POLICY_TAG_TRUSTED))); + nexthops_disable_if( + nexthops, i, + (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_PROHIBIT) && + (connection_has_tag(conn, POLICY_TAG_TRUSTED))); + }); + + if (nexthops_get_curlen(nexthops) == 0) { + DEBUG("After REQUIRE/PROHIBIT pruning, num=%d/%d", + nexthops_get_curlen(nexthops), nexthops_get_len(nexthops)); + return nexthops; + } + + /* We have at least one matching next hop, implement heuristic */ + + /* + * As VPN connections might trigger duplicate uses of one interface, we start + * by filtering out interfaces based on trust status. + */ + flags = nexthops->flags; + + if ((policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE) || + (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_PREFER)) { + /* Try to filter out NON TRUSTED faces */ + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + (!connection_has_tag(conn, POLICY_TAG_TRUSTED))); + }); + + if ((nexthops_get_curlen(nexthops) == 0) && + (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE)) { + return nexthops; + } + + } else { + /* Try to filter out TRUSTED faces */ + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + (connection_has_tag(conn, POLICY_TAG_TRUSTED))); + }); + } + + if (nexthops_get_curlen(nexthops) == 0) nexthops->flags = flags; + + /* Other preferences */ + if (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_AVOID) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + connection_has_tag(conn, POLICY_TAG_WIRED)); + }); + if (nexthops_get_curlen(nexthops) == 0) nexthops->flags = flags; + } + if (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_AVOID) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + connection_has_tag(conn, POLICY_TAG_WIFI)); + }); + if (nexthops_get_curlen(nexthops) == 0) nexthops->flags = flags; + } + if (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_AVOID) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + connection_has_tag(conn, POLICY_TAG_CELLULAR)); + }); + if (nexthops_get_curlen(nexthops) == 0) nexthops->flags = flags; + } + + if (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_PREFER) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + !connection_has_tag(conn, POLICY_TAG_WIRED)); + }); + if (nexthops_get_curlen(nexthops) == 0) nexthops->flags = flags; + } + if (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_PREFER) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + !connection_has_tag(conn, POLICY_TAG_WIFI)); + }); + if (nexthops_get_curlen(nexthops) == 0) nexthops->flags = flags; + } + if (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_PREFER) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + !connection_has_tag(conn, POLICY_TAG_CELLULAR)); + }); + if (nexthops_get_curlen(nexthops) == 0) nexthops->flags = flags; + } + + DEBUG("[fib_entry_filter_nexthops] before face priority num=%d/%d", + nexthops_get_curlen(nexthops), nexthops_get_len(nexthops)); + + /* Priority */ + uint32_t max_priority = 0; + nexthops_foreach(nexthops, nexthop, { + conn = connection_table_at(table, nexthop); + uint32_t priority = connection_get_priority(conn); + if (priority > max_priority) max_priority = priority; + }); + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + connection_get_priority(conn) < max_priority); + }); + + DEBUG("[fib_entry_filter_nexthops] result num=%d/%d", + nexthops_get_curlen(nexthops), nexthops_get_len(nexthops)); + + return nexthops; +} + +/* + * Update available next hops following policy update. + * + * The last nexthop parameter is only used if needed, otherwise the pointer to + * fib entry is returned to avoid an useless copy + */ +nexthops_t *fib_entry_get_available_nexthops(fib_entry_t *entry, + unsigned ingress_id, + nexthops_t *new_nexthops) { + // DEBUG("[fib_entry_get_available_nexthops]"); + + connection_table_t *table = forwarder_get_connection_table(entry->forwarder); + + /* + * Give absolute preference to local faces, with no policy, unless + * ingress_id == ~0, which means we are searching faces on which to + * advertise our prefix + */ + if (ingress_id == ~0) { + assert(new_nexthops); + /* We create a nexthop structure based on connections */ + // XXX This should be done close to where it is needed + connection_t *connection; + connection_table_foreach(table, connection, { + if (connection_is_local(connection)) continue; + new_nexthops->elts[nexthops_get_len(new_nexthops)] = + connection_table_get_connection_id(table, connection); + nexthops_inc(new_nexthops); + }); + +#ifdef WITH_POLICY + return fib_entry_filter_nexthops(entry, new_nexthops, ingress_id, false); +#else + return new_nexthops; +#endif + } + +#ifdef WITH_POLICY + return fib_entry_filter_nexthops(entry, fib_entry_get_nexthops(entry), + ingress_id, true); +#else + return fib_entry_get_nexthops(entry); +#endif +} + +hicn_policy_t fib_entry_get_policy(const fib_entry_t *entry) { + return entry->policy; +} + +void fib_entry_set_policy(fib_entry_t *entry, hicn_policy_t policy) { + entry->policy = policy; + +#ifdef WITH_MAPME + /* + * Skip entries that do not correspond to a producer ( / have a locally + * served prefix / have no local connection as next hop) + */ + if (!fib_entry_has_local_nexthop(entry)) return; + mapme_t *mapme = forwarder_get_mapme(entry->forwarder); + mapme_set_all_adjacencies(mapme, entry); +#endif /* WITH_MAPME */ +} + +#endif /* WITH_POLICY */ + +void fib_entry_nexthops_add(fib_entry_t *entry, unsigned nexthop) { + /* + * Nexthop is added to both: + * - fib_entry: it is added to the nexthops_t struct, in the elts array. + * - strategy: only used to eventually initialize internal state, might be + * empty like in the random strategy. + */ + off_t id = nexthops_add(&entry->nexthops, nexthop); + strategy_add_nexthop(&entry->strategy, &entry->nexthops, id); +} + +void fib_entry_nexthops_remove(fib_entry_t *entry, unsigned nexthop) { + off_t id = nexthops_remove(&entry->nexthops, nexthop); + strategy_remove_nexthop(&entry->strategy, &entry->nexthops, id); +} + +nexthops_t *fib_entry_get_nexthops_from_strategy(fib_entry_t *entry, + const msgbuf_t *msgbuf, + bool is_retransmission) { + assert(entry); + assert(msgbuf); + + // DEBUG("[fib_entry_get_nexthops_from_strategy]"); + + const policy_stats_mgr_t *mgr = + forwarder_get_policy_stats_mgr(entry->forwarder); + assert(mgr); + + /* Filtering */ + nexthops_t *nexthops = fib_entry_get_available_nexthops( + entry, msgbuf_get_connection_id(msgbuf), NULL); + if (nexthops_get_curlen(nexthops) == 0) return nexthops; + +#ifdef WITH_POLICY_STATS + /* + * Update statistics about loss rates. We only detect losses upon + * retransmissions, and assume for the computation that the candidate set of + * output faces is the same as previously (i.e. does not take into account + * event such as face up/down, policy update, etc. Otherwise we would need to + * know what was the previous choice ! + */ + if (is_retransmission) + policy_stats_on_retransmission(mgr, &entry->policy_counters, nexthops); +#endif /* WITH_POLICY_STATS */ + + /* + * NOTE: We might want to call a forwarding strategy even with no nexthop to + * take a fallback decision. + */ + if (nexthops_get_curlen(nexthops) == 0) return nexthops; + +#ifdef WITH_POLICY + + /* + * Filter out nexthops with lowest strategy priority. + * Initializing at 0 allows to disable nexthops with a negative priority + */ + unsigned max_priority = 0; + unsigned i; + nexthop_t nexthop; + nexthops_enumerate(nexthops, i, nexthop, { + (void)nexthop; + int priority = nexthops->state[i].priority; + if (priority > max_priority) max_priority = priority; + }); + nexthops_enumerate(nexthops, i, nexthop, { + int priority = nexthops->state[i].priority; + nexthops_disable_if(nexthops, i, (priority < max_priority)); + }); + + /* + * If multipath is disabled, we don't offer much choice to the forwarding + * strategy, but still go through it for accounting purposes. + */ + hicn_policy_t policy = fib_entry_get_policy(entry); + if ((policy.tags[POLICY_TAG_MULTIPATH].state == POLICY_STATE_PROHIBIT) || + (policy.tags[POLICY_TAG_MULTIPATH].state == POLICY_STATE_AVOID)) { + DEBUG( + "[fib_entry_get_nexthops_from_strategy] select single nexthops due to " + "multipath policy"); + nexthops_select_first(nexthops); + } + +#endif /* WITH_POLICY */ + + // DEBUG("[fib_entry_get_nexthops_from_strategy] calling lookup_nethops " + // "on strategy (num=%d)", nexthops_get_len(nexthops)); + return strategy_lookup_nexthops(&entry->strategy, nexthops, msgbuf); +} + +void fib_entry_on_data(fib_entry_t *entry, nexthops_t *data_nexthops, + const msgbuf_t *msgbuf, Ticks pitEntryCreation, + Ticks objReception) { + assert(entry); + assert(data_nexthops); + assert(msgbuf); + +#ifdef WITH_POLICY_STATS + if (pitEntryCreation != 0) { // if pitEntryCreation we no match in the pit + // was found + const policy_stats_mgr_t *mgr = + forwarder_get_policy_stats_mgr(entry->forwarder); + Ticks rtt = objReception - pitEntryCreation; + policy_stats_on_data(mgr, &entry->policy_stats, &entry->policy_counters, + data_nexthops, msgbuf, rtt); + } +#endif /* WITH_POLICY_STATS */ + + if (pitEntryCreation != 0 || + (fib_entry_strategy_type(entry) == STRATEGY_TYPE_BESTPATH)) { + strategy_on_data(&entry->strategy, &entry->nexthops, data_nexthops, msgbuf, + pitEntryCreation, objReception); + } +} + +void fib_entry_on_timeout(fib_entry_t *entry, + const nexthops_t *timeout_nexthops) { + assert(entry); + assert(timeout_nexthops); + +#ifdef WITH_POLICY_STATS + const policy_stats_mgr_t *mgr = + forwarder_get_policy_stats_mgr(entry->forwarder); + policy_stats_on_timeout(mgr, &entry->policy_counters, timeout_nexthops); +#endif /* WITH_POLICY_STATS */ + + strategy_on_timeout(&entry->strategy, &entry->nexthops, timeout_nexthops); +} + +const Name *fib_entry_get_prefix(const fib_entry_t *entry) { + assert(entry); + return &(entry->name); +} + +/* + * Return true if we have at least one local connection as next hop + */ +bool fib_entry_has_local_nexthop(const fib_entry_t *entry) { + connection_table_t *table = forwarder_get_connection_table(entry->forwarder); + + unsigned nexthop; + nexthops_foreach(fib_entry_get_nexthops(entry), nexthop, { + const connection_t *conn = connection_table_at(table, nexthop); + /* Ignore non-local connections */ + if (!connection_is_local(conn)) continue; + return true; + }); + return false; +} + +#ifdef WITH_MAPME + +void *fib_entry_get_user_data(const fib_entry_t *entry) { + assert(entry); + + return entry->user_data; +} + +void fib_entry_set_user_data(fib_entry_t *entry, const void *user_data, + void (*user_data_release)(void **)) { + assert(entry); + assert(user_data); + assert(user_data_release); + + entry->user_data = (void *)user_data; + entry->user_data_release = user_data_release; +} + +#endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/core/fib_entry.h b/hicn-light/src/hicn/core/fib_entry.h new file mode 100644 index 000000000..628c4cd4f --- /dev/null +++ b/hicn-light/src/hicn/core/fib_entry.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file fib_entry.h + * @brief A forwarding entry in the FIB table + * + * A Forwarding Information Base (FIB) entry (fib_entry_t) is a + * set of nexthops for a name. It also indicates the forwarding strategy. + * + * Each nexthop contains the ConnectionId assocaited with it. This could be + * something specific like a MAC address or point-to-point tunnel. Or, it + * could be something general like a MAC group address or ip multicast overlay. + * + * See strategy.h for a description of forwarding strategies. + * In short, a strategy is the algorithm used to select one or more nexthops + * from the set of available nexthops. + * + * Each nexthop also contains a void* to a forwarding strategy data container. + * This allows a strategy to keep proprietary information about each nexthop. + * + * + */ + +#ifndef fib_entry_h +#define fib_entry_h + +#include "name.h" +#include "strategy.h" +#include "msgbuf.h" +#include "nexthops.h" +#include "policy_stats.h" + +typedef struct { + Name name; + unsigned refcount; + nexthops_t nexthops; + strategy_entry_t strategy; + + const void *forwarder; + +#ifdef WITH_POLICY + hicn_policy_t policy; +#endif /* WITH_POLICY */ + + policy_counters_t policy_counters; + policy_stats_t policy_stats; + +#ifdef WITH_MAPME + /* In case of no multipath, this stores the previous decision taken by policy. + * As the list of nexthops is not expected to change, we can simply store the + * flags */ + uint_fast32_t prev_nexthops_flags; + void *user_data; + void (*user_data_release)(void **user_data); +#endif /* WITH_MAPME */ +} fib_entry_t; + +#define _fib_entry_var(x) _fib_entry_##x + +#define fib_entry_strategy_type(fib_entry) ((fib_entry)->strategy.type) + +#define fib_entry_get_nexthops(fib_entry) (&(fib_entry)->nexthops) +#define fib_entry_nexthops_len(fib_entry) \ + (nexthops_get_len(&(fib_entry)->nexthops)) +#define fib_entry_nexthops_curlen(fib_entry) \ + (nexthops_curlen(&(fib_entry)->nexthops)) +#define fib_entry_get_nexthop(fib_entry, i) ((fib_entry)->nexthops.elts[i]) +#define fib_entry_foreach_nexthop(fib_entry, nexthop, BODY) \ + nexthops_foreach(fib_entry->nexthops, BODY) + +#define fib_entry_nexthops_changed(fib_entry) \ + ((fib_entry)->prev_nexthops_flags == fib_entry_get_nexthops(fib_entry)->flags) + +#define fib_entry_set_prev_nexthops(fib_entry) \ + ((fib_entry)->prev_nexthops_flags = fib_entry_get_nexthops(fib_entry)->flags) + +struct forwarder_s; +fib_entry_t *fib_entry_create(Name *name, strategy_type_t strategy_type, + strategy_options_t *strategy_options, + const struct forwarder_s *table); + +void fib_entry_free(fib_entry_t *entry); + +void fib_entry_add_strategy_options(fib_entry_t *entry, + strategy_type_t strategy_type, + strategy_options_t *strategy_options); + +void fib_entry_set_strategy(fib_entry_t *fib_entry, + strategy_type_t strategy_type, + strategy_options_t *strategy_options); + +void fib_entry_nexthops_add(fib_entry_t *fib_entry, unsigned nexthop); + +void fib_entry_nexthops_remove(fib_entry_t *fib_entry, unsigned nexthop); + +size_t fib_entry_NexthopCount(const fib_entry_t *fib_entry); + +/** + * @function fib_entry_nexthops_get + * @abstract Returns the nexthop set of the FIB entry. You must Acquire if it + * will be saved. + * @discussion + * Returns the next hop set for the FIB entry. + */ +const nexthops_t *fib_entry_nexthops_get(const fib_entry_t *fib_entry); + +const nexthops_t *fib_entry_nexthops_getFromForwardingStrategy( + fib_entry_t *fib_entry, const msgbuf_t *interest_msgbuf, + bool is_retransmission); + +void fib_entry_on_data(fib_entry_t *fib_entry, nexthops_t *nexthops, + const msgbuf_t *object_msgbuf, Ticks pit_entry_creation, + Ticks data_reception); + +#ifdef WITH_POLICY +hicn_policy_t fib_entry_get_policy(const fib_entry_t *fib_entry); +void fib_entry_reconsider_policy(fib_entry_t *fib_entry); +void fib_entry_set_policy(fib_entry_t *fib_entry, hicn_policy_t policy); +void fib_entry_update_stats(fib_entry_t *fib_entry, uint64_t now); +#endif /* WITH_POLICY */ + +nexthops_t *fib_entry_get_available_nexthops(fib_entry_t *fib_entry, + unsigned in_connection, + nexthops_t *new_nexthops); +void fib_entry_on_timeout(fib_entry_t *fib_entry, const nexthops_t *egressId); +nexthops_t *fib_entry_get_nexthops_from_strategy( + fib_entry_t *fib_entry, const msgbuf_t *interest_msgbuf, + bool is_retransmission); + +/** + * @function fib_entry_get_prefix + * @abstract Returns a copy of the prefix. + * @return A reference counted copy that you must destroy + */ +const Name *fib_entry_get_prefix(const fib_entry_t *fib_entry); + +bool fib_entry_has_local_nexthop(const fib_entry_t *entry); + +#ifdef WITH_MAPME + +/** + * @function fib_entry_get_user_data + * @abstract Returns user data associated to the FIB entry. + * @param [in] fib_entry - Pointer to the FIB entry. + * @return User data as a void pointer + */ +void *fib_entry_get_user_data(const fib_entry_t *fib_entry); + +/** + * @function fib_entry_get_user_data + * @abstract Associates user data and release callback to a FIB entry. + * @param [in] fib_entry - Pointer to the FIB entry. + * @param [in] user_data - Generic pointer to user data + * @param [in@ user_data_release - Callback used to release user data upon + * change of FIB entry removal. + */ +void fib_entry_set_user_data(fib_entry_t *fib_entry, const void *user_data, + void (*user_data_release)(void **)); + +#endif /* WITH_MAPME */ + +#endif // fib_entry_h diff --git a/hicn-light/src/hicn/core/forwarder.c b/hicn-light/src/hicn/core/forwarder.c index 94e8cc885..37502f3ac 100644 --- a/hicn-light/src/hicn/core/forwarder.c +++ b/hicn-light/src/hicn/core/forwarder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -23,6 +23,15 @@ * the event scheduler */ +/* Bypass FIB and send packet one by one */ +//#define BYPASS_FIB 1 + +/* Send packets one by one : only effective if FIB is not bypassed */ +//#define USE_SEND_PACKET 1 + +/* Batch sending: only if the previous option is undefined */ +#define USE_QUEUE true + #ifndef _WIN32 #include <arpa/inet.h> #include <sys/socket.h> @@ -30,8 +39,7 @@ #endif #include <errno.h> #include <fcntl.h> -#include <signal.h> -#include <hicn/hicn-light/config.h> +//#include <hicn/hicn-light/config.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -41,90 +49,108 @@ #define __STDC_FORMAT_MACROS #include <inttypes.h> -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> -#include <parc/logging/parc_LogReporterTextStdout.h> - -#include <hicn/core/connectionManager.h> -#include <hicn/core/connectionTable.h> -#include <hicn/core/dispatcher.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/messagePacketType.h> +#include "connection_table.h" +#include "fib.h" +#include "forwarder.h" +#include "listener_table.h" #ifdef WITH_MAPME -#include <hicn/core/mapme.h> +#include "mapme.h" #endif /* WITH_MAPME */ -#include <hicn/config/configuration.h> -#include <hicn/config/configurationFile.h> -#include <hicn/config/configurationListeners.h> -#include <hicn/processor/messageProcessor.h> +#include "msgbuf.h" +#include "msgbuf_pool.h" +#include "packet_cache.h" +#include "../config/configuration.h" +// #include "../config/configuration_file.h" +#include "../config/commands.h" +#include "../io/base.h" // MAX_MSG + +#ifdef WITH_POLICY_STATS +#include <hicn/core/policy_stats.h> +#endif /* WITH_POLICY_STATS */ #include <hicn/core/wldr.h> +#include <hicn/util/log.h> + +typedef struct { + // Packets processed + uint32_t countReceived; // Interest and data only + uint32_t countInterestsReceived; + uint32_t countObjectsReceived; + + // Packets Dropped + uint32_t countDropped; + uint32_t countInterestsDropped; + uint32_t countObjectsDropped; + uint32_t countOtherDropped; + + // Forwarding + uint32_t countInterestForwarded; + uint32_t countObjectsForwarded; + + // Errors while forwarding + uint32_t countDroppedConnectionNotFound; + uint32_t countSendFailures; + uint32_t countDroppedNoRoute; + + // Interest processing + uint32_t countInterestsAggregated; + uint32_t countInterestsRetransmitted; + uint32_t countInterestsSatisfiedFromStore; + uint32_t countInterestsExpired; + uint32_t countDataExpired; + + // Data processing + uint32_t countDroppedNoReversePath; + + // TODO(eloparco): Currently not used + // uint32_t countDroppedNoHopLimit; + // uint32_t countDroppedZeroHopLimitFromRemote; + // uint32_t countDroppedZeroHopLimitToRemote; +} forwarder_stats_t; + +struct forwarder_s { + // uint16_t server_port; -#include <parc/assert/parc_Assert.h> - -// the router's clock frequency (we now use the monotonic clock) -#define HZ 1000 - -// these will all be a little off because its all integer division -#define MSEC_PER_TICK (1000 / HZ) -#define USEC_PER_TICK (1000000 / HZ) -#define NSEC_PER_TICK ((1000000000ULL) / HZ) -#define MSEC_TO_TICKS(msec) \ - ((msec < FC_MSEC_PER_TICK) ? 1 : msec / FC_MSEC_PER_TICK) -#define NSEC_TO_TICKS(nsec) ((nsec < NSEC_PER_TICK) ? 1 : nsec / NSEC_PER_TICK) - -struct forwarder { - Dispatcher *dispatcher; - - uint16_t server_port; + // used by seed48 and nrand48 + unsigned short seed[3]; - PARCEventSignal *signal_int; - PARCEventSignal *signal_term; -#ifndef _WIN32 - PARCEventSignal *signal_usr1; -#endif - PARCEventTimer *keepalive_event; + connection_table_t *connection_table; + listener_table_t *listener_table; + configuration_t *config; - // will skew the virtual clock forward. In normal operaiton, it is 0. - Ticks clockOffset; + pkt_cache_t *pkt_cache; + fib_t *fib; + msgbuf_pool_t *msgbuf_pool; - unsigned nextConnectionid; - Messenger *messenger; - ConnectionManager *connectionManager; - ConnectionTable *connectionTable; - ListenerSet *listenerSet; - Configuration *config; +#ifdef WITH_MAPME + mapme_t *mapme; +#endif /* WITH_MAPME */ - // we'll eventually want to setup a threadpool of these - MessageProcessor *processor; + bool store_in_cs; + bool serve_from_cs; - Logger *logger; + forwarder_stats_t stats; +#ifdef WITH_POLICY_STATS + policy_stats_mgr_t policy_stats_mgr; +#endif /* WITH_POLICY_STATS */ - PARCClock *clock; + /* + * The message forwarder has to decide whether to queue incoming packets for + * batching, or trigger the transmission on the connection + */ + unsigned pending_conn[MAX_MSG]; + size_t num_pending_conn; -#if !defined(__APPLE__) - hicn_socket_helper_t - *hicnSocketHelper; // state required to manage hicn connections -#endif - // used by seed48 and nrand48 - unsigned short seed[3]; + // msgbuf_t msgbuf; /* Storage for msgbuf, which are currently processed 1 by + // 1 */ -#ifdef WITH_MAPME - MapMe *mapme; -#endif /* WITH_MAPME */ + subscription_table_t *subscriptions; }; -// signal traps through the event scheduler -static void _signal_cb(int, PARCEventType, void *); - -// A no-op keepalive to prevent Libevent from exiting the dispatch loop -static void _keepalive_cb(int, PARCEventType, void *); - /** * Reseed our pseudo-random number generator. */ -static void forwarder_Seed(Forwarder *forwarder) { +static void forwarder_seed(forwarder_t *forwarder) { #ifndef _WIN32 int fd; ssize_t res; @@ -150,452 +176,990 @@ static void forwarder_Seed(Forwarder *forwarder) { #endif } -Logger *forwarder_GetLogger(const Forwarder *forwarder) { - return forwarder->logger; -} +forwarder_t *forwarder_create(configuration_t *configuration) { + forwarder_t *forwarder = malloc(sizeof(forwarder_t)); + if (!forwarder) goto ERR_MALLOC; -// ============================================================================ -// Setup and destroy section + forwarder_seed(forwarder); + srand(forwarder->seed[0] ^ forwarder->seed[1] ^ forwarder->seed[2]); -Forwarder *forwarder_Create(Logger *logger) { - Forwarder *forwarder = parcMemory_AllocateAndClear(sizeof(Forwarder)); - parcAssertNotNull(forwarder, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Forwarder)); - memset(forwarder, 0, sizeof(Forwarder)); - forwarder_Seed(forwarder); + forwarder->config = configuration; - forwarder->clock = parcClock_Monotonic(); - forwarder->clockOffset = 0; + forwarder->listener_table = listener_table_create(); + if (!forwarder->listener_table) goto ERR_LISTENER_TABLE; - if (logger) { - forwarder->logger = logger_Acquire(logger); - logger_SetClock(forwarder->logger, forwarder->clock); - } else { - PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); - forwarder->logger = logger_Create(reporter, forwarder->clock); - parcLogReporter_Release(&reporter); - } + forwarder->connection_table = connection_table_create(); + if (!forwarder->connection_table) goto ERR_CONNECTION_TABLE; - forwarder->nextConnectionid = 1; - forwarder->dispatcher = dispatcher_Create(forwarder->logger); - forwarder->messenger = messenger_Create(forwarder->dispatcher); - forwarder->connectionManager = connectionManager_Create(forwarder); - forwarder->connectionTable = connectionTable_Create(); - forwarder->listenerSet = listenerSet_Create(); - forwarder->config = configuration_Create(forwarder); - forwarder->processor = messageProcessor_Create(forwarder); - - forwarder->signal_term = dispatcher_CreateSignalEvent( - forwarder->dispatcher, _signal_cb, forwarder, SIGTERM); - dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_term); - - forwarder->signal_int = dispatcher_CreateSignalEvent( - forwarder->dispatcher, _signal_cb, forwarder, SIGINT); - dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_int); -#ifndef _WIN32 - forwarder->signal_usr1 = dispatcher_CreateSignalEvent( - forwarder->dispatcher, _signal_cb, forwarder, SIGPIPE); - dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_usr1); -#endif + forwarder->fib = fib_create(forwarder); + if (!forwarder->fib) goto ERR_FIB; -#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \ - defined(PUNTING) - forwarder->hicnSocketHelper = hicn_create(); - if (!forwarder->hicnSocketHelper) - goto ERR_SOCKET; -#endif /* __APPLE__ */ + forwarder->msgbuf_pool = msgbuf_pool_create(); + if (!forwarder->msgbuf_pool) goto ERR_PACKET_POOL; -#ifdef WITH_MAPME - if (!(mapme_create(&forwarder->mapme, forwarder))) - goto ERR_MAPME; -#endif /* WITH_MAPME */ + size_t objectStoreSize = configuration_get_cs_size(configuration); + forwarder->pkt_cache = pkt_cache_create(objectStoreSize); + if (!forwarder->pkt_cache) goto ERR_PKT_CACHE; + forwarder->subscriptions = subscription_table_create(); + if (!forwarder->subscriptions) goto ERR_SUBSCRIPTION; - /* ignore child */ -#ifndef _WIN32 - signal(SIGCHLD, SIG_IGN); - - /* ignore tty signals */ - signal(SIGTSTP, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGTTIN, SIG_IGN); -#endif + // the two flags for the cs are set to true by default. If the cs + // is active it always work as expected unless the use modifies this + // values using controller + if (objectStoreSize != 0) { + forwarder->store_in_cs = true; + forwarder->serve_from_cs = true; + } - // We no longer use this for ticks, but we need to have at least one event - // schedule to keep Libevent happy. +#ifdef WITH_MAPME + forwarder->mapme = mapme_create(forwarder); + if (!forwarder->mapme) goto ERR_MAPME; +#endif /* WITH_MAPME */ - struct timeval wtnow_timeout; - timerclear(&wtnow_timeout); +#ifdef WITH_POLICY_STATS + if (policy_stats_mgr_initialize(&forwarder->policy_stats_mgr, forwarder) < 0) + goto ERR_MGR; +#endif /* WITH_POLICY_STATS */ - wtnow_timeout.tv_sec = 0; - wtnow_timeout.tv_usec = 50000; // 20 Hz keepalive + memset(&forwarder->stats, 0, sizeof(forwarder_stats_t)); - PARCEventScheduler *base = - dispatcher_GetEventScheduler(forwarder->dispatcher); - forwarder->keepalive_event = parcEventTimer_Create( - base, PARCEventType_Persist, _keepalive_cb, (void *)forwarder); - parcEventTimer_Start(forwarder->keepalive_event, &wtnow_timeout); + forwarder->num_pending_conn = 0; return forwarder; +ERR_MGR: #ifdef WITH_MAPME ERR_MAPME: #endif /* WITH_MAPME */ -#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \ - defined(PUNTING) - hicn_free(forwarder->hicnSocketHelper); -ERR_SOCKET: -#endif - listenerSet_Destroy(&(forwarder->listenerSet)); - connectionManager_Destroy(&(forwarder->connectionManager)); - connectionTable_Destroy(&(forwarder->connectionTable)); - messageProcessor_Destroy(&(forwarder->processor)); - configuration_Destroy(&(forwarder->config)); - messenger_Destroy(&(forwarder->messenger)); - - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_int)); - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_term)); -#ifndef _WIN32 - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_usr1)); -#endif - - parcClock_Release(&forwarder->clock); - logger_Release(&forwarder->logger); - // do the dispatcher last - dispatcher_Destroy(&(forwarder->dispatcher)); - - parcMemory_Deallocate((void **)&forwarder); +ERR_SUBSCRIPTION: + subscription_table_free(forwarder->subscriptions); +ERR_PKT_CACHE: + pkt_cache_free(forwarder->pkt_cache); + + msgbuf_pool_free(forwarder->msgbuf_pool); +ERR_PACKET_POOL: + fib_free(forwarder->fib); +ERR_FIB: + connection_table_free(forwarder->connection_table); +ERR_CONNECTION_TABLE: + listener_table_free(forwarder->listener_table); +ERR_LISTENER_TABLE: + free(forwarder); +ERR_MALLOC: return NULL; } -void forwarder_Destroy(Forwarder **ptr) { - parcAssertNotNull(ptr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*ptr, "Parameter must dereference to non-null pointer"); - Forwarder *forwarder = *ptr; -#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \ - defined(PUNTING) - hicn_free(forwarder->hicnSocketHelper); -#endif - parcEventTimer_Destroy(&(forwarder->keepalive_event)); +void forwarder_free(forwarder_t *forwarder) { + assert(forwarder); - listenerSet_Destroy(&(forwarder->listenerSet)); - connectionManager_Destroy(&(forwarder->connectionManager)); - connectionTable_Destroy(&(forwarder->connectionTable)); - messageProcessor_Destroy(&(forwarder->processor)); - configuration_Destroy(&(forwarder->config)); - - // the messenger is used by many of the other pieces, so destroy it last - messenger_Destroy(&(forwarder->messenger)); + policy_stats_mgr_finalize(&forwarder->policy_stats_mgr); #ifdef WITH_MAPME mapme_free(forwarder->mapme); #endif /* WITH_MAPME */ - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_int)); - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_term)); -#ifndef _WIN32 - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_usr1)); -#endif + pkt_cache_free(forwarder->pkt_cache); + msgbuf_pool_free(forwarder->msgbuf_pool); + fib_free(forwarder->fib); + connection_table_free(forwarder->connection_table); + listener_table_free(forwarder->listener_table); + subscription_table_free(forwarder->subscriptions); + configuration_free(forwarder->config); + free(forwarder); +} - parcClock_Release(&forwarder->clock); - logger_Release(&forwarder->logger); +void forwarder_setup_local_listeners(forwarder_t *forwarder, uint16_t port) { + assert(forwarder); + listener_setup_local(forwarder, port); +} - // do the dispatcher last - dispatcher_Destroy(&(forwarder->dispatcher)); +configuration_t *forwarder_get_configuration(forwarder_t *forwarder) { + assert(forwarder); + return forwarder->config; +} - parcMemory_Deallocate((void **)&forwarder); - *ptr = NULL; +subscription_table_t *forwarder_get_subscriptions(forwarder_t *forwarder) { + return forwarder->subscriptions; } -void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port, - const char *localPath) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); +connection_table_t *forwarder_get_connection_table( + const forwarder_t *forwarder) { + assert(forwarder); + return forwarder->connection_table; +} - configurationListeners_SetupAll(forwarder->config, port, localPath); +listener_table_t *forwarder_get_listener_table(forwarder_t *forwarder) { + assert(forwarder); + return forwarder->listener_table; } -void forwarder_SetupLocalListeners(Forwarder *forwarder, uint16_t port) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - configurationListeners_SetutpLocalIPv4(forwarder->config, port); +void forwarder_cs_set_store(forwarder_t *forwarder, bool val) { + assert(forwarder); + forwarder->store_in_cs = val; } -void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename) { - ConfigurationFile *configFile = configurationFile_Create(forwarder, filename); - if (configFile) { - configurationFile_Process(configFile); - configurationFile_Release(&configFile); - } +bool forwarder_cs_get_store(forwarder_t *forwarder) { + assert(forwarder); + return forwarder->store_in_cs; } -Configuration *forwarder_GetConfiguration(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->config; +void forwarder_cs_set_serve(forwarder_t *forwarder, bool val) { + assert(forwarder); + forwarder->serve_from_cs = val; } -// ============================================================================ +bool forwarder_cs_get_serve(forwarder_t *forwarder) { + assert(forwarder); + return forwarder->serve_from_cs; +} + +void forwarder_cs_set_size(forwarder_t *forwarder, size_t size) { + assert(forwarder); -unsigned forwarder_GetNextConnectionId(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->nextConnectionid++; + if (pkt_cache_set_cs_size(forwarder->pkt_cache, size) < 0) { + ERROR( + "Unable to resize the CS: provided maximum size (%u) is smaller than " + "the number of elements currently stored in the CS (%u). Clear the CS " + "and retry.", + size, pkt_cache_get_cs_size(forwarder->pkt_cache)); + } } -Messenger *forwarder_GetMessenger(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->messenger; +size_t forwarder_cs_get_size(forwarder_t *forwarder) { + assert(forwarder); + return pkt_cache_get_cs_size(forwarder->pkt_cache); } -Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->dispatcher; +size_t forwarder_cs_get_num_stale_entries(forwarder_t *forwarder) { + assert(forwarder); + return pkt_cache_get_num_cs_stale_entries(forwarder->pkt_cache); } -#ifdef WITH_POLICY -ConnectionTable *forwarder_GetConnectionTable(const Forwarder *forwarder) { +void forwarder_cs_clear(forwarder_t *forwarder) { + assert(forwarder); + + pkt_cache_cs_clear(forwarder->pkt_cache); +} + +/** + * @function forwarder_Drop + * @abstract Whenever we "drop" a message, increment counters + * @discussion + * This is a bookkeeping function. It increments the appropriate counters. + * + * The default action for a message is to destroy it in + * <code>forwarder_Receive()</code>, so this function does not need to do + * that. + * + */ +static ssize_t forwarder_drop(forwarder_t *forwarder, off_t msgbuf_id) { + forwarder->stats.countDropped++; + + const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + const msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + + switch (msgbuf_get_type(msgbuf)) { + case MSGBUF_TYPE_INTEREST: + forwarder->stats.countInterestsDropped++; + break; + + case MSGBUF_TYPE_DATA: + forwarder->stats.countObjectsDropped++; + break; + + default: + forwarder->stats.countOtherDropped++; + break; + } + + return msgbuf_get_len(msgbuf); + // dont destroy message here, its done at end of receive +} + +#ifndef BYPASS_FIB +/* + * If the hoplimit is equal to 0, then we may only forward it to local + * applications. Otherwise, we may forward it off the system. + * + */ + +static ssize_t forwarder_forward_via_connection(forwarder_t *forwarder, + off_t msgbuf_id, + unsigned conn_id) { + connection_table_t *table = forwarder_get_connection_table(forwarder); + + const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + + const connection_t *conn = connection_table_get_by_id(table, conn_id); + + if (!conn) { + forwarder->stats.countDroppedConnectionNotFound++; + WARN("forward msgbuf %lu to interface %u not found (count %u)", msgbuf_id, + conn_id, forwarder->stats.countDroppedConnectionNotFound); + return forwarder_drop(forwarder, msgbuf_id); + } + + /* Always queue the packet... */ + // DEBUG("Queueing packet\n"); + +#if defined(USE_SEND_PACKET) || !defined(__linux__) + + // Here we need to update the path label of a data packet before send + // it. The path label update can be done here because the packet is sent + // directly to the socket + if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) + msgbuf_update_pathlabel(msgbuf, connection_get_id(conn)); + + bool success = connection_send_packet(conn, msgbuf_get_packet(msgbuf), + msgbuf_get_len(msgbuf)); #else -ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder) { -#endif /* WITH_POLICY */ - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->connectionTable; + + // In this case we cannot update the path label even if it is need because + // the packet is not copied and only the packet id is enqueued to the ring + // buffer associated the output interface. If the path label is updated here + // all data packets get delivered to the next hop with the same label that is + // associated to the last connection used. For this reason the path label + // update must be done before the packet is actually sent inside the different + // IO implementations. + bool success = connection_send(conn, msgbuf_id, USE_QUEUE); + +#endif + + /* ... and mark the connection as pending if this is not yet the case */ + unsigned i; + for (i = 0; i < forwarder->num_pending_conn; i++) { + if (forwarder->pending_conn[i] == conn_id) break; + } + if (i == forwarder->num_pending_conn) // Not found + forwarder->pending_conn[forwarder->num_pending_conn++] = conn_id; + + if (!success) { + forwarder->stats.countSendFailures++; + + DEBUG("forward msgbuf %llu to interface %u send failure (count %u)", + msgbuf_id, conn_id, forwarder->stats.countSendFailures); + return forwarder_drop(forwarder, msgbuf_id); + } + + switch (msgbuf_get_type(msgbuf)) { + case MSGBUF_TYPE_INTEREST: + forwarder->stats.countInterestForwarded++; + break; + + case MSGBUF_TYPE_DATA: + forwarder->stats.countObjectsForwarded++; + break; + + default: + break; + } + + TRACE("forward msgbuf %p to interface %u", msgbuf, conn_id); + return msgbuf_get_len(msgbuf); } -ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->listenerSet; +/** + * @function forwarder_forward_to_nexthops + * @abstract Try to forward to each nexthop listed in the NumberSet + * @discussion + * Will not forward to the ingress connection. + * + * @return The number of nexthops tried + */ +static unsigned forwarder_forward_to_nexthops(forwarder_t *forwarder, + off_t msgbuf_id, + const nexthops_t *nexthops) { + // DEBUG("[forwarder_forward_to_nexthops] num=%d/%d", + // nexthops_get_curlen(nexthops), nexthops_get_len(nexthops)); + unsigned forwardedCopies = 0; + + const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + unsigned ingressId = msgbuf_get_connection_id(msgbuf); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + // DEBUG("[forwarder_forward_to_nexthops] - nexthop = %d"); + if (nexthop == ingressId) continue; + + forwardedCopies++; + // INFO("[forwarder_forward_to_nexthops] - nexthop = %d OK", nexthop); + forwarder_forward_via_connection(forwarder, msgbuf_id, nexthop); + }); + + return forwardedCopies; } -void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - messageProcessor_SetCacheStoreFlag(forwarder->processor, val); +static bool forwarder_forward_via_fib(forwarder_t *forwarder, off_t msgbuf_id, + pkt_cache_verdict_t verdict, + pkt_cache_entry_t *entry) { + assert(forwarder); + assert(msgbuf_id_is_valid(msgbuf_id)); + + const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST); + + fib_entry_t *fib_entry = fib_match_message(forwarder->fib, msgbuf); + if (!fib_entry) return false; + + // DEBUG("[forwarder] Getting nexthops from strategy"); + nexthops_t *nexthops = fib_entry_get_nexthops_from_strategy( + fib_entry, msgbuf, verdict == PKT_CACHE_VERDICT_RETRANSMIT_INTEREST); + + if (nexthops_get_curlen(nexthops) == 0) { + ERROR("Message %p returned an empty next hop set", msgbuf); + return false; + } + + // if this is the first time that we sent this interest the pit entry would be + // NULL. in that case we add the interest to the pit + if (entry == NULL) { + entry = pkt_cache_add_to_pit(forwarder->pkt_cache, msgbuf); + } + pit_entry_t *pit_entry = &entry->u.pit_entry; + if (!pit_entry) { + return false; + } + + pit_entry_set_fib_entry(pit_entry, fib_entry); + + // this requires some additional checks. It may happen that some of the output + // faces selected by the forwarding strategy are not usable. So far all the + // forwarding strategy return only valid faces (or an empty list) + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + // DEBUG("Adding egress to PIT for nexthop %d", nexthop); + pit_entry_egress_add(pit_entry, nexthop); + }); + + if (forwarder_forward_to_nexthops(forwarder, msgbuf_id, nexthops) <= 0) { + // this should never happen + ERROR("Message %p returned an empty next hop set", msgbuf); + return false; + } + + return true; } -bool forwarder_GetChacheStoreFlag(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return messageProcessor_GetCacheStoreFlag(forwarder->processor); +#endif /* ! BYPASS_FIB */ + +ssize_t _forwarder_forward_upon_interest(forwarder_t *forwarder, + msgbuf_pool_t *msgbuf_pool, + off_t data_msgbuf_id, + off_t interest_msgbuf_id, + pkt_cache_entry_t *entry, + pkt_cache_verdict_t verdict) { + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, interest_msgbuf_id); + + if (verdict == PKT_CACHE_VERDICT_AGGREGATE_INTEREST) { + // the packet shuold not be forwarder + forwarder_drop(forwarder, interest_msgbuf_id); + return msgbuf_get_len(msgbuf); + } + + // - Forward reply if a data packet matching the interest was found + if (verdict == PKT_CACHE_VERDICT_FORWARD_DATA) { + assert(forwarder->serve_from_cs == true); + + msgbuf_t *interest_msgbuf = msgbuf_pool_at(msgbuf_pool, interest_msgbuf_id); + msgbuf_t *data_msgbuf = msgbuf_pool_at(msgbuf_pool, data_msgbuf_id); + + msgbuf_reset_pathlabel(data_msgbuf); + + forwarder_forward_via_connection(forwarder, data_msgbuf_id, + msgbuf_get_connection_id(interest_msgbuf)); + + // - Try to forward the interest + } else if (!forwarder_forward_via_fib(forwarder, interest_msgbuf_id, verdict, + entry)) { + forwarder->stats.countDroppedNoRoute++; + INFO("Message %lu did not match FIB, no route (count %u)", + interest_msgbuf_id, forwarder->stats.countDroppedNoRoute); + + // - Drop the packet (no forwarding) + forwarder_drop(forwarder, interest_msgbuf_id); + } + + return msgbuf_get_len(msgbuf); +} + +static void _forwarder_update_interest_stats(forwarder_t *forwarder, + pkt_cache_verdict_t verdict, + msgbuf_t *msgbuf, + pkt_cache_entry_t *entry) { + long expiration = -1; + if (entry == NULL) + expiration = ticks_now() + msgbuf_get_interest_lifetime(msgbuf); + else if (entry->has_expire_ts) + expiration = entry->expire_ts; + + switch (verdict) { + case PKT_CACHE_VERDICT_FORWARD_INTEREST: + DEBUG( + "Message will be added to PIT (expiration=%ld), " + "if nexthops are available", + expiration); + break; + + case PKT_CACHE_VERDICT_AGGREGATE_INTEREST: + forwarder->stats.countInterestsAggregated++; + DEBUG("Message aggregated in PIT (expiration=%ld)", expiration); + break; + + case PKT_CACHE_VERDICT_RETRANSMIT_INTEREST: + forwarder->stats.countInterestsRetransmitted++; + DEBUG("Message retransmitted (expiration=%ld)", expiration); + break; + + case PKT_CACHE_VERDICT_FORWARD_DATA: + forwarder->stats.countInterestsSatisfiedFromStore++; + DEBUG("Message satisfied from content store (expiration=%ld)", + expiration); + break; + + case PKT_CACHE_VERDICT_INTEREST_EXPIRED_FORWARD_INTEREST: + forwarder->stats.countInterestsExpired++; + DEBUG("Message replaced expired interest (expiration=%ld)", expiration); + break; + + case PKT_CACHE_VERDICT_DATA_EXPIRED_FORWARD_INTEREST: + forwarder->stats.countDataExpired++; + DEBUG("Message replaced expired data (expiration=%ld)", expiration); + break; + + case PKT_CACHE_VERDICT_ERROR: + ERROR("Inivalid packet cache content"); + break; + + default: + break; + } } -void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - messageProcessor_SetCacheServeFlag(forwarder->processor, val); +/** + * @function forwarder_process_interest + * @abstract Receive an interest from the network + * @discussion + * (1) if interest in the PIT, aggregate in PIT + * (2) if interest in the ContentStore, reply + * (3) if in the FIB, forward + * (4) drop + * + */ +static ssize_t forwarder_process_interest(forwarder_t *forwarder, + off_t msgbuf_id) { + assert(forwarder); + assert(msgbuf_id_is_valid(msgbuf_id)); + + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + + assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST); + + forwarder->stats.countReceived++; + forwarder->stats.countInterestsReceived++; + + WITH_DEBUG({ + char *nameString = name_ToString(msgbuf_get_name(msgbuf)); + DEBUG("INTEREST (%s) msgbuf_id=%lu ingress=%u length=%u", nameString, + msgbuf_id, msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf)); + free(nameString); + }) + + pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR; + off_t data_msgbuf_id = INVALID_MSGBUF_ID; + pkt_cache_entry_t *entry = NULL; + pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, &verdict, + &data_msgbuf_id, &entry, forwarder->serve_from_cs); + + _forwarder_update_interest_stats(forwarder, verdict, msgbuf, entry); + + return _forwarder_forward_upon_interest( + forwarder, msgbuf_pool, data_msgbuf_id, msgbuf_id, entry, verdict); } -bool forwarder_GetChacheServeFlag(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return messageProcessor_GetCacheServeFlag(forwarder->processor); +static void _forwarder_log_on_data(forwarder_t *forwarder, + pkt_cache_verdict_t verdict) { + switch (verdict) { + case PKT_CACHE_VERDICT_FORWARD_DATA: + DEBUG("Message added to CS from PIT"); + break; + case PKT_CACHE_VERDICT_STORE_DATA: + DEBUG("Message added to CS (expired or no previous interest pending)"); + break; + case PKT_CACHE_VERDICT_CLEAR_DATA: + break; + case PKT_CACHE_VERDICT_UPDATE_DATA: + DEBUG("Message updated in CS"); + break; + case PKT_CACHE_VERDICT_IGNORE_DATA: + DEBUG("Message not stored in CS"); + break; + case PKT_CACHE_VERDICT_ERROR: + ERROR("Inivalid packet cache content"); + break; + default: + break; + } } -void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command, - struct iovec *message, unsigned ingressId) { - configuration_ReceiveCommand(forwarder->config, command, message, ingressId); +/** + * @function forwarder_process_data + * @abstract Process an in-bound content object + * @discussion + * (1) If it does not match anything in the PIT, drop it + * (2) Add to Content Store + * (3) Reverse path forward via PIT entries + * + * @param <#param1#> + */ +static ssize_t forwarder_process_data(forwarder_t *forwarder, off_t msgbuf_id) { + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + + WITH_DEBUG({ + char *nameString = name_ToString(msgbuf_get_name(msgbuf)); + DEBUG("DATA (%s) msgbuf_id=%lu ingress=%u length=%u", nameString, msgbuf_id, + msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf)); + free(nameString); + )} + + forwarder->stats.countReceived++; + forwarder->stats.countObjectsReceived++; + + const connection_table_t *table = forwarder_get_connection_table(forwarder); + const connection_t *conn = + connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); + + pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR; + bool wrong_egress; + nexthops_t *ingressSetUnion = + pkt_cache_on_data(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, + forwarder->store_in_cs, connection_is_local(conn), &wrong_egress, &verdict); + + _forwarder_log_on_data(forwarder, verdict); + + if (wrong_egress) { // Interest sent via a connection but received from another + WARN("Data coming from unexpected connection, discarded"); + } else if (!ingressSetUnion) { // No match in the PIT + forwarder->stats.countDroppedNoReversePath++; + DEBUG("Message %lu did not match PIT, no reverse path", msgbuf_id); + + // MOVE PROBE HOOK ELSEWHERE + // XXX relationship with forwarding strategy... insert hooks + // if the packet is a probe we need to analyze it + // NOTE : probes are not stored in PIT + if (msgbuf_is_probe(msgbuf)) { + fib_entry_t *entry = fib_match_message(forwarder->fib, msgbuf); + if (entry && fib_entry_strategy_type(entry) == STRATEGY_TYPE_BESTPATH) { + nexthops_t probe_nexthops = NEXTHOPS_EMPTY; + nexthops_add(&probe_nexthops, msgbuf_get_connection_id(msgbuf)); + fib_entry_on_data(entry, &probe_nexthops, msgbuf, 0, ticks_now()); + // XXX TODO CONFIRM WE DON'T EXIT HERE ? + } + } + forwarder_drop(forwarder, msgbuf_id); + } else { + // Reverse path forward via PIT entries + forwarder_forward_to_nexthops(forwarder, msgbuf_id, ingressSetUnion); + free(ingressSetUnion); + } + + return msgbuf_get_len(msgbuf); } -void forwarder_Receive(Forwarder *forwarder, Message *message) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); +void forwarder_flush_connections(forwarder_t *forwarder) { + // DEBUG("[forwarder_flush_connections]"); + const connection_table_t *table = forwarder_get_connection_table(forwarder); - // this takes ownership of the message, so we're done here + for (unsigned i = 0; i < forwarder->num_pending_conn; i++) { + unsigned conn_id = forwarder->pending_conn[i]; + const connection_t *conn = connection_table_at(table, conn_id); + if (!connection_flush(conn)) { + WARN("Could not flush connection queue"); + // XXX keep track of non flushed connections... + } + } + forwarder->num_pending_conn = 0; + // DEBUG("[forwarder_flush_connections] done"); +} +// XXX move to wldr file, worst case in connection. +void forwarder_apply_wldr(const forwarder_t *forwarder, const msgbuf_t *msgbuf, + connection_t *connection) { // this are the checks needed to implement WLDR. We set wldr only on the STAs - // and we let the AP to react according to choise of the client. + // and we let the AP to react according to choice of the client. // if the STA enables wldr using the set command, the AP enable wldr as well // otherwise, if the STA disable it the AP remove wldr // WLDR should be enabled only on the STAs using the command line // TODO // disable WLDR command line on the AP - const Connection *conn = connectionTable_FindById( - forwarder->connectionTable, message_GetIngressConnectionId(message)); - - if (!conn) { - /* - * Drop is a static method in messageProcessor which might or might not need - * to be called for accounting purposes. This call was initially absent so - * the behaviour was kept like this, as this situation is unlikely. We need - * to release memory though, as this is not done in Drop anyways. - */ - //messageProcessor_Drop(forwarder->processor, message); - message_Release(&message); - return; - } - - if (message_HasWldr(message)) { - if (connection_HasWldr(conn)) { + if (msgbuf_has_wldr(msgbuf)) { + if (connection_has_wldr(connection)) { // case 1: WLDR is enabled - connection_DetectLosses((Connection *)conn, message); - } else if (!connection_HasWldr(conn) && - connection_WldrAutoStartAllowed(conn)) { + connection_wldr_detect_losses(connection, msgbuf); + } else if (!connection_has_wldr(connection) && + connection_wldr_autostart_is_allowed(connection)) { // case 2: We are on an AP. We enable WLDR - connection_EnableWldr((Connection *)conn); - connection_DetectLosses((Connection *)conn, message); + connection_wldr_enable(connection, true); + connection_wldr_detect_losses(connection, msgbuf); } // case 3: Ignore WLDR } else { - if (connection_HasWldr(conn) && connection_WldrAutoStartAllowed(conn)) { + if (connection_has_wldr(connection) && + connection_wldr_autostart_is_allowed(connection)) { // case 1: STA do not use WLDR, we disable it - connection_DisableWldr((Connection *)conn); + connection_wldr_enable(connection, false); } } - - messageProcessor_Receive(forwarder->processor, message); } -Ticks forwarder_GetTicks(const Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return parcClock_GetTime(forwarder->clock) + forwarder->clockOffset; -} +bool forwarder_add_or_update_route(forwarder_t *forwarder, ip_prefix_t *prefix, + unsigned ingress_id) { + assert(forwarder); + assert(prefix); -Ticks forwarder_NanosToTicks(uint64_t nanos) { return NSEC_TO_TICKS(nanos); } + configuration_t *config = forwarder_get_configuration(forwarder); -uint64_t forwarder_TicksToNanos(Ticks ticks) { - return (1000000000ULL) * ticks / HZ; -} + char prefix_s[MAXSZ_IP_PREFIX]; + int rc = ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) return false; + + DEBUG("Adding prefix=%s for conn_id=%d", prefix_s, ingress_id); -bool forwarder_AddOrUpdateRoute(Forwarder *forwarder, - add_route_command *control, unsigned ifidx) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(control, "Parameter route must be non-null"); + // XXX TODO this should store options too + strategy_type_t strategy_type = configuration_get_strategy(config, prefix_s); - // we only have one message processor - bool res = - messageProcessor_AddOrUpdateRoute(forwarder->processor, control, ifidx); + Name name_prefix = EMPTY_NAME; + name_CreateFromAddress(&name_prefix, prefix->family, prefix->address, + prefix->len); + fib_entry_t *entry = fib_contains(forwarder->fib, &name_prefix); + if (!entry) { + entry = fib_entry_create(&name_prefix, strategy_type, NULL, forwarder); + fib_entry_nexthops_add(entry, ingress_id); + fib_add(forwarder->fib, entry); + + } else { + fib_entry_nexthops_add(entry, ingress_id); + } - return res; + return true; } +bool forwarder_remove_route(forwarder_t *forwarder, ip_prefix_t *prefix, + unsigned ingress_id) { + assert(forwarder); + assert(prefix); -bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control, - unsigned ifidx) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(control, "Parameter route must be non-null"); + Name name_prefix = EMPTY_NAME; + name_CreateFromAddress(&name_prefix, prefix->family, prefix->address, + prefix->len); + fib_remove(forwarder->fib, &name_prefix, ingress_id); - // we only have one message processor - return messageProcessor_RemoveRoute(forwarder->processor, control, ifidx); + return true; } #ifdef WITH_POLICY -bool forwarder_AddOrUpdatePolicy(Forwarder *forwarder, - add_policy_command *control) { - parcAssertNotNull(forwarder, "Parameter forwarder must be non-null"); - parcAssertNotNull(control, "Parameter control must be non-null"); +bool forwarder_add_or_update_policy(forwarder_t *forwarder, ip_prefix_t *prefix, + hicn_policy_t *policy) { + assert(forwarder); + assert(prefix); + assert(policy); - return messageProcessor_AddOrUpdatePolicy(forwarder->processor, control); + Name name_prefix = EMPTY_NAME; + name_CreateFromAddress(&name_prefix, prefix->family, prefix->address, + prefix->len); + fib_entry_t *entry = fib_contains(forwarder->fib, &name_prefix); + if (!entry) return false; + fib_entry_set_policy(entry, *policy); + + return true; } -bool forwarder_RemovePolicy(Forwarder *forwarder, remove_policy_command *control) { - parcAssertNotNull(forwarder, "Parameter forwarder must be non-null"); - parcAssertNotNull(control, "Parameter control must be non-null"); +bool forwarder_remove_policy(forwarder_t *forwarder, ip_prefix_t *prefix) { + assert(forwarder); + assert(prefix); + + Name name_prefix = EMPTY_NAME; + name_CreateFromAddress(&name_prefix, prefix->family, prefix->address, + prefix->len); + fib_entry_t *entry = fib_contains(forwarder->fib, &name_prefix); + + if (!entry) return false; + + fib_entry_set_policy(entry, POLICY_EMPTY); - return messageProcessor_RemovePolicy(forwarder->processor, control); + return true; } #endif /* WITH_POLICY */ -void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder, - unsigned connectionId) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - messageProcessor_RemoveConnectionIdFromRoutes(forwarder->processor, - connectionId); +void forwarder_remove_connection_id_from_routes(forwarder_t *forwarder, + unsigned connection_id) { + assert(forwarder); + + fib_remove_connection_id(forwarder->fib, connection_id); } -void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix, - strategy_type strategy, - unsigned related_prefixes_len, - Name **related_prefixes) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(prefix, "Parameter prefix must be non-null"); +void forwarder_add_strategy_options(forwarder_t *forwarder, Name *name_prefix, + strategy_type_t strategy_type, + strategy_options_t *strategy_options) { + assert(forwarder); + assert(name_prefix); + assert(strategy_options); + assert(STRATEGY_TYPE_VALID(strategy_type)); + + fib_entry_t *entry = fib_contains(forwarder->fib, name_prefix); + if (!entry) return; - processor_SetStrategy(forwarder->processor, prefix, strategy, - related_prefixes_len, related_prefixes); + fib_entry_add_strategy_options(entry, strategy_type, strategy_options); } -FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder) { - return messageProcessor_GetFibEntries(forwarder->processor); +void forwarder_set_strategy(forwarder_t *forwarder, Name *name_prefix, + strategy_type_t strategy_type, + strategy_options_t *strategy_options) { + assert(forwarder); + assert(name_prefix); + assert(STRATEGY_TYPE_VALID(strategy_type)); + /* strategy_options might be NULL */ + + fib_entry_t *entry = fib_contains(forwarder->fib, name_prefix); + if (!entry) { + // there is no exact match. so if the forwarding strategy is not in the list + // of strategies that can be set by the transport, return + if (strategy_type != STRATEGY_TYPE_BESTPATH && + strategy_type != STRATEGY_TYPE_REPLICATION) { + return; + } + + // here it may be the transprot that wants to set the strategy, but it has + // no knowledge of the length of the prefix. so we apply the strategy at the + // matching fib entry, which later will be the one that will be used to send + // interests with this name + entry = fib_match_name(forwarder->fib, name_prefix); + if (!entry) { + return; // no fib match, return + } + } + + fib_entry_set_strategy(entry, strategy_type, strategy_options); } -void forwarder_SetContentObjectStoreSize(Forwarder *forwarder, - size_t maximumContentStoreSize) { - messageProcessor_SetContentObjectStoreSize(forwarder->processor, - maximumContentStoreSize); +cs_t *forwarder_get_cs(const forwarder_t *forwarder) { + assert(forwarder); + + return pkt_cache_get_cs(forwarder->pkt_cache); } -void forwarder_ClearCache(Forwarder *forwarder) { - messageProcessor_ClearCache(forwarder->processor); +// ======================================================= + +fib_t *forwarder_get_fib(forwarder_t *forwarder) { return forwarder->fib; } + +msgbuf_pool_t *forwarder_get_msgbuf_pool(const forwarder_t *forwarder) { + return forwarder->msgbuf_pool; } -PARCClock *forwarder_GetClock(const Forwarder *forwarder) { - return forwarder->clock; +#ifdef WITH_MAPME +void forwarder_on_connection_event(const forwarder_t *forwarder, + const connection_t *connection, + connection_event_t event) { + mapme_on_connection_event(forwarder->mapme, connection, event); } -#if !defined(__APPLE__) -hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder) { - return forwarder->hicnSocketHelper; +mapme_t *forwarder_get_mapme(const forwarder_t *forwarder) { + return forwarder->mapme; } -#endif -// ======================================================= +#endif /* WITH_MAPME */ -static void _signal_cb(int sig, PARCEventType events, void *user_data) { - Forwarder *forwarder = (Forwarder *)user_data; +#ifdef WITH_POLICY_STATS +const policy_stats_mgr_t *forwarder_get_policy_stats_mgr( + const forwarder_t *forwarder) { + return &forwarder->policy_stats_mgr; +} +#endif /* WITH_POLICY_STATS */ - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "signal %d events %d", sig, events); +/** + * @brief Process a packet by creating the corresponding message buffer and + * dispatching it to the forwarder for further processing. + * @param[in] forwarder Forwarder instance. + * + */ +// XXX ??? XXX = process for listener as we are resolving connection id +// + +msgbuf_type_t get_type_from_packet(uint8_t *packet) { + if (messageHandler_IsTCP(packet)) { + if (messageHandler_IsData(packet)) { + return MSGBUF_TYPE_DATA; + } else if (messageHandler_IsInterest(packet)) { + return MSGBUF_TYPE_INTEREST; + } else { + return MSGBUF_TYPE_UNDEFINED; + } - switch ((int)sig) { - case SIGTERM: - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "Caught an terminate signal; exiting cleanly."); - dispatcher_Stop(forwarder->dispatcher); - break; + } else if (messageHandler_IsWldrNotification(packet)) { + return MSGBUF_TYPE_WLDR_NOTIFICATION; - case SIGINT: - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "Caught an interrupt signal; exiting cleanly."); - dispatcher_Stop(forwarder->dispatcher); - break; -#ifndef _WIN32 - case SIGUSR1: - // dump stats - break; -#endif + } else if (mapme_match_packet(packet)) { + return MSGBUF_TYPE_MAPME; - default: - break; - } -} + } else if (*packet == REQUEST_LIGHT) { + return MSGBUF_TYPE_COMMAND; -static void _keepalive_cb(int fd, PARCEventType what, void *user_data) { - parcAssertTrue(what & PARCEventType_Timeout, "Got unexpected tick_cb: %d", - what); - // function is just a keepalive for hicn-light, does not do anything + } else { + return MSGBUF_TYPE_UNDEFINED; + } } -#ifdef WITH_MAPME -FIB *forwarder_getFib(Forwarder *forwarder) { - return messageProcessor_getFib(forwarder->processor); +/** + * @brief Finalize (i.e. close fd and free internal data structures) + * the current connection ("SELF") when the command is received. + * The connection cannot be removed inside the command handling + * because it is needed to return the ack back. + */ +static void _forwarder_finalize_connection_if_self(connection_t *conn, + msgbuf_t *msgbuf) { + uint8_t *packet = msgbuf_get_packet(msgbuf); + msg_connection_remove_t *msg = (msg_connection_remove_t *)packet; + cmd_connection_remove_t *control = &msg->payload; + + if (strcmp(control->symbolic_or_connid, "SELF") == 0) + connection_finalize(conn); } -void forwarder_onConnectionEvent(Forwarder *forwarder, const Connection *conn, connection_event_t event) { -//#ifdef WITH_POLICY -// messageProcessor_onConnectionEvent(forwarder->processor, conn, event); -//#else - mapme_onConnectionEvent(forwarder->mapme, conn, event); -//#endif /* WITH_POLICY */ -} +ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener, + off_t msgbuf_id, address_pair_t *pair, Ticks now) { + assert(forwarder); + /* listener can be NULL */ + assert(msgbuf_id_is_valid(msgbuf_id)); + assert(pair); + + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + assert(msgbuf); + + uint8_t *packet = msgbuf_get_packet(msgbuf); + size_t size = msgbuf_get_len(msgbuf); + + /* Connection lookup */ + const connection_table_t *table = + forwarder_get_connection_table(listener->forwarder); + connection_t *connection = connection_table_get_by_pair(table, pair); + unsigned conn_id = connection + ? connection_table_get_connection_id(table, connection) + : CONNECTION_ID_UNDEFINED; + + assert((conn_id != CONNECTION_ID_UNDEFINED) || listener); + + msgbuf_type_t type = get_type_from_packet(msgbuf_get_packet(msgbuf)); + + msgbuf->type = type; + msgbuf->connection_id = conn_id; + msgbuf->recv_ts = now; + + switch (type) { + case MSGBUF_TYPE_INTEREST: + if (!connection_id_is_valid(msgbuf->connection_id)) { + char *conn_name = connection_table_get_random_name(table); + unsigned connection_id = + listener_create_connection(listener, conn_name, pair); + msgbuf->connection_id = connection_id; + connection = connection_table_get_by_id(table, connection_id); + free(conn_name); + } + msgbuf->path_label = 0; // not used for interest packets + name_create_from_interest(packet, msgbuf_get_name(msgbuf)); + forwarder_apply_wldr(forwarder, msgbuf, connection); + forwarder_process_interest(forwarder, msgbuf_id); + + pkt_cache_log(forwarder->pkt_cache); + return size; + + case MSGBUF_TYPE_DATA: + if (!connection_id_is_valid(msgbuf->connection_id)) + return forwarder_drop(forwarder, msgbuf_id); + msgbuf_init_pathlabel(msgbuf); + name_create_from_data(packet, msgbuf_get_name(msgbuf)); + forwarder_apply_wldr(forwarder, msgbuf, connection); + forwarder_process_data(forwarder, msgbuf_id); + + pkt_cache_log(forwarder->pkt_cache); + return size; + + case MSGBUF_TYPE_WLDR_NOTIFICATION: + if (!connection_id_is_valid(msgbuf->connection_id)) + return forwarder_drop(forwarder, msgbuf_id); + connection_wldr_handle_notification(connection, msgbuf); + return size; + + case MSGBUF_TYPE_MAPME: + // XXX what about acks ? + if (!connection_id_is_valid(msgbuf->connection_id)) { + char *conn_name = connection_table_get_random_name(table); + msgbuf->connection_id = + listener_create_connection(listener, conn_name, pair); + free(conn_name); + } + mapme_process(forwarder->mapme, msgbuf); + return size; + + case MSGBUF_TYPE_COMMAND: + // Create the connection to send the ack back + if (!connection_id_is_valid(msgbuf->connection_id)) { + char *conn_name = connection_table_get_random_name(table); + unsigned connection_id = + listener_create_connection(listener, conn_name, pair); + msgbuf->connection_id = connection_id; + connection = connection_table_get_by_id(table, connection_id); + free(conn_name); + } + + msg_header_t *msg = (msg_header_t *)packet; + msgbuf->command.type = msg->header.command_id; + if (!command_type_is_valid(msgbuf->command.type)) { + ERROR("Invalid command"); + return 0; + } + + size = command_process_msgbuf(forwarder, msgbuf); + if (msgbuf->command.type == COMMAND_TYPE_CONNECTION_REMOVE) + _forwarder_finalize_connection_if_self(connection, msgbuf); + return size; -void forwarder_ProcessMapMe(Forwarder *forwarder, const uint8_t *msgBuffer, - unsigned conn_id) { - mapme_Process(forwarder->mapme, msgBuffer, conn_id); + default: + ERROR("Invalid msgbuf type"); + forwarder_drop(forwarder, msgbuf_id); + return 0; + } } -MapMe * -forwarder_getMapmeInstance(const Forwarder *forwarder) { - return forwarder->mapme; +void forwarder_log(forwarder_t *forwarder) { + DEBUG( + "Forwarder: received = %u (interest = %u, data = %u), dropped = %u " + "(interest = %u, data = %u, other = %u), forwarded = { interests = %u, " + "data = %u }, dropped = { connection_not_found = %u, send_failure = %u, " + "no_route_in_fib = %u }, interest processing = { aggregated = %u, " + "retransmitted = %u, satisfied_from_cs = %u, expired_interests = %u, " + "expired_data = %u }, data processing = { " + "no_reverse_path = %u }\n", + forwarder->stats.countReceived, forwarder->stats.countInterestsReceived, + forwarder->stats.countObjectsReceived, forwarder->stats.countDropped, + forwarder->stats.countInterestsDropped, + forwarder->stats.countObjectsDropped, forwarder->stats.countOtherDropped, + forwarder->stats.countInterestForwarded, + forwarder->stats.countObjectsForwarded, + forwarder->stats.countDroppedConnectionNotFound, + forwarder->stats.countSendFailures, forwarder->stats.countDroppedNoRoute, + forwarder->stats.countInterestsAggregated, + forwarder->stats.countInterestsRetransmitted, + forwarder->stats.countInterestsSatisfiedFromStore, + forwarder->stats.countInterestsExpired, forwarder->stats.countDataExpired, + forwarder->stats.countDroppedNoReversePath); } - -#endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/core/forwarder.h b/hicn-light/src/hicn/core/forwarder.h index d1815b7d4..76c12368a 100644 --- a/hicn-light/src/hicn/core/forwarder.h +++ b/hicn-light/src/hicn/core/forwarder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -18,292 +18,212 @@ * only be called within the forwarders thread of execution. */ -#ifndef forwarder_h -#define forwarder_h +#ifndef HICNLIGHT_FORWARDER_H +#define HICNLIGHT_FORWARDER_H -#ifndef _WIN32 -#include <sys/time.h> -#endif -#include <stdlib.h> - -#include <hicn/core/connectionTable.h> -#include <hicn/core/dispatcher.h> -#include <hicn/messenger/messenger.h> +//#ifndef _WIN32 +//#include <sys/time.h> +//#endif +// -#include <hicn/core/message.h> +#include <stdlib.h> +#include <sys/socket.h> // struct mmsghdr -#include <hicn/config/configuration.h> +#include "connection.h" +#include "connection_table.h" +#include "packet_cache.h" +#include "listener_table.h" +#include "msgbuf.h" +#include "msgbuf_pool.h" +#include "../config/configuration.h" +#include "subscription.h" #ifdef WITH_MAPME -#include <hicn/processor/fib.h> +#include "fib.h" #endif /* WITH_MAPME */ -#include <hicn/core/logger.h> -#include <hicn/core/ticks.h> -#include <hicn/io/listenerSet.h> - -#include <hicn/processor/fibEntryList.h> - -#include <parc/algol/parc_Clock.h> - -#if !defined(__APPLE__) -#include <hicn/socket/api.h> -#endif - #define PORT_NUMBER 9695 #define PORT_NUMBER_AS_STRING "9695" -#include <hicn/utils/commands.h> +//#include <hicn/utils/commands.h> // ============================================== -struct forwarder; -typedef struct forwarder Forwarder; +typedef struct forwarder_s forwarder_t; /** - * @function forwarder_Create - * @abstract Create the forwarder and use the provided logger for diagnostic + * @brief Create the forwarder and use the provided logger for diagnostic * output * @discussion * If the logger is null, hicn-light will create a STDOUT logger. * * @param logger may be NULL */ -Forwarder *forwarder_Create(Logger *logger); +forwarder_t *forwarder_create(configuration_t *configuration); /** - * @function forwarder_Destroy - * @abstract Destroys the forwarder, stopping all traffic and freeing all memory + * @brief Destroys the forwarder, stopping all traffic and freeing all memory */ -void forwarder_Destroy(Forwarder **ptr); +void forwarder_free(forwarder_t *forwarder); /** - * @function forwarder_SetupAllListeners - * @abstract Setup all listeners (tcp, udp, local, ether, ip multicast) on all - * interfaces - * @discussion - * Sets up all listeners on all running interfaces. This provides a quick and - * easy startup, rather than providing a configuration file or programmatic - * commands. - * - * @param port is used by TCP and UDP listeners, in host byte order - * @param localPath is the AF_UNIX path to use, if NULL no AF_UNIX listener is - * setup - */ -void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port, - const char *localPath); -/** - * @function forwarder_SetupAllListeners - * @abstract Setup one tcp and one udp listener on address 127.0.0.1 and the + * @brief Setup one tcp and one udp listener on address 127.0.0.1 and the * given port */ -void forwarder_SetupLocalListeners(Forwarder *forwarder, uint16_t port); - -/** - * Configure hicn-light via a configuration file - * - * The configuration file is a set of lines, just like used in hicnLightControl. - * You need to have "add listener" lines in the file to receive connections. No - * default listeners are configured. - * - * @param [in] forwarder An alloated Forwarder - * @param [in] filename The path to the configuration file - */ -void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename); - -/** - * Returns the logger used by this forwarder - * - * If you will store the logger, you should acquire a reference to it. - * - * @param [in] forwarder An allocated hicn-light forwarder - * - * @retval non-null The logger used by hicn-light - * @retval null An error - */ -Logger *forwarder_GetLogger(const Forwarder *forwarder); - -/** - * @function forwarder_SetLogLevel - * @abstract Sets the minimum level to log - */ -void forwarder_SetLogLevel(Forwarder *forwarder, PARCLogLevel level); - -/** - * @function forwarder_GetNextConnectionId - * @abstract Get the next identifier for a new connection - */ -unsigned forwarder_GetNextConnectionId(Forwarder *forwarder); +void forwarder_setup_local_listeners(forwarder_t *forwarder, uint16_t port); -Messenger *forwarder_GetMessenger(Forwarder *forwarder); +configuration_t *forwarder_get_configuration(forwarder_t *forwarder); -Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder); +subscription_table_t *forwarder_get_subscriptions(forwarder_t *forwarder); /** * Returns the set of currently active listeners * - * @param [in] forwarder An allocated hicn-light forwarder + * @param[in] forwarder An allocated hicn-light forwarder * * @retval non-null The set of active listeners * @retval null An error */ -ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder); +listener_table_t *forwarder_get_listener_table(forwarder_t *forwarder); /** * Returns the forwrder's connection table * - * @param [in] forwarder An allocated hicn-light forwarder + * @param[in] forwarder An allocated hicn-light forwarder * * @retval non-null The connection tabler * @retval null An error * */ -#ifdef WITH_POLICY -ConnectionTable *forwarder_GetConnectionTable(const Forwarder *forwarder); -#else -ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder); -#endif /* WITH_POLICY */ +connection_table_t *forwarder_get_connection_table( + const forwarder_t *forwarder); -/** - * Returns a Tick-based clock - * - * Runs at approximately 1 msec per tick (see HZ in forwarder.c). - * Do not Release this clock. If you save a copy of it, create your own - * reference to it with parcClock_Acquire(). - * - * @param [in] forwarder An allocated hicn-light forwarder - * - * @retval non-null An allocated hicn-light Clock based on the Tick counter - * @retval null An error - */ -PARCClock *forwarder_GetClock(const Forwarder *forwarder); +void forwarder_cs_set_store(forwarder_t *forwarder, bool val); -/** - * Direct call to get the Tick clock - * - * Runs at approximately 1 msec per tick (see HZ in forwarder.c) - * - * @param [in] forwarder An allocated hicn-light forwarder - */ -Ticks forwarder_GetTicks(const Forwarder *forwarder); +bool forwarder_cs_get_store(forwarder_t *forwarder); + +void forwarder_cs_set_serve(forwarder_t *forwarder, bool val); + +bool forwarder_cs_get_serve(forwarder_t *forwarder); /** - * Convert nano seconds to Ticks + * Sets the maximum number of content objects in the content store * - * Converts nano seconds to Ticks, based on HZ (in forwarder.c) + * Implementation dependent - may wipe the cache. */ -Ticks forwarder_NanosToTicks(uint64_t nanos); - -uint64_t forwarder_TicksToNanos(Ticks ticks); +void forwarder_cs_set_size(forwarder_t *forwarder, size_t size); -void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command, - struct iovec *message, unsigned ingressId); - -void forwarder_Receive(Forwarder *forwarder, Message *mesage); +size_t forwarder_cs_get_size(forwarder_t *forwarder); +size_t forwarder_cs_get_num_stale_entries(forwarder_t *forwarder); +void forwarder_cs_clear(forwarder_t *forwarder); /** - * @function forwarder_AddOrUpdateRoute - * @abstract Adds or updates a route on all the message processors + * @brief Adds or updates a route on all the message processors */ -bool forwarder_AddOrUpdateRoute(Forwarder *forwarder, - add_route_command *control, unsigned ifidx); +bool forwarder_add_or_update_route(forwarder_t *forwarder, ip_prefix_t *prefix, + unsigned ingress_id); /** - * @function forwarder_RemoveRoute - * @abstract Removes a route from all the message processors + * @brief Removes a route from all the message processors */ -bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control, - unsigned ifidx); +bool forwarder_remove_route(forwarder_t *forwarder, ip_prefix_t *prefix, + unsigned ingress_id); #ifdef WITH_POLICY /** - * @function forwarder_AddOrUpdatePolicy - * @abstract Adds or updates a policy on the message processor + * @brief Adds or updates a policy on the message processor */ -bool forwarder_AddOrUpdatePolicy(Forwarder *forwarder, add_policy_command *control); +bool forwarder_add_or_update_policy(forwarder_t *forwarder, ip_prefix_t *prefix, + hicn_policy_t *policy); /** - * @function forwarder_RemovePolicy - * @abstract Removes a policy from the message processor + * @brief Removes a policy from the message processor */ -bool forwarder_RemovePolicy(Forwarder *forwarder, remove_policy_command *control); +bool forwarder_remove_policy(forwarder_t *forwarder, ip_prefix_t *prefix); + #endif /* WITH_POLICY */ /** * Removes a connection id from all routes */ -void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder, - unsigned connectionId); +void forwarder_remove_connection_id_from_routes(forwarder_t *forwarder, + unsigned connection_id); -/** - * @function forwarder_GetConfiguration - * @abstract The configuration object - * @discussion - * The configuration contains all user-issued commands. It does not include - * dynamic state. - */ -Configuration *forwarder_GetConfiguration(Forwarder *forwarder); +void forwarder_add_strategy_options(forwarder_t *forwarder, Name *name_prefix, + strategy_type_t strategy_type, + strategy_options_t *strategy_options); -FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder); +void forwarder_set_strategy(forwarder_t *forwarder, Name *name_prefix, + strategy_type_t strategy_type, + strategy_options_t *strategy_options); + +cs_t *forwarder_get_cs(const forwarder_t *forwarder); /** - * Sets the maximum number of content objects in the content store - * - * Implementation dependent - may wipe the cache. + * @brief Returns the forwarder's FIB. + * @param[in] forwarder - Pointer to the forwarder. + * @returns Pointer to the hICN FIB. */ -void forwarder_SetContentObjectStoreSize(Forwarder *forwarder, - size_t maximumContentStoreSize); - -void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val); - -bool forwarder_GetChacheStoreFlag(Forwarder *forwarder); - -void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val); - -bool forwarder_GetChacheServeFlag(Forwarder *forwarder); - -void forwarder_ClearCache(Forwarder *forwarder); - -void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix, - strategy_type strategy, unsigned related_prefixes_len, - Name **related_prefixes); -#if !defined(__APPLE__) -hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder); -#endif -#ifdef WITH_MAPME +fib_t *forwarder_get_fib(forwarder_t *forwarder); /** - * @function forwarder_getFib - * @abstract Returns the hICN forwarder's FIB. - * @param [in] forwarder - Pointer to the hICN forwarder. - * @returns Pointer to the hICN FIB. + * @brief Return the forwarder packet pool. + * @param[in] forwarder The forwarder from which to retrieve the packet + * pool. + * @return msgbuf_pool_t * The forwarder packet pool. */ -FIB *forwarder_getFib(Forwarder *forwarder); +msgbuf_pool_t *forwarder_get_msgbuf_pool(const forwarder_t *forwarder); + +#ifdef WITH_MAPME /** - * @function forwarder_onConnectionEvent - * @abstract Callback fired upon addition of a new connection through the + * @brief Callback fired upon addition of a new connection through the * control protocol. - * @param [in] forwarder - Pointer to the hICN forwarder. - * @param [in] conn - Pointer to the newly added connection. - * @param [in] event - Connection event + * @param[in] forwarder - Pointer to the forwarder. + * @param[in] conn - Pointer to the newly added connection. + * @param[in] event - Connection event */ -void forwarder_onConnectionEvent(Forwarder *forwarder, const Connection *conn, connection_event_t event); +void forwarder_on_connection_event(const forwarder_t *forwarder, + const connection_t *connection, + connection_event_t event); /** - * @function forwarder_ProcessMapMe - * @abstract Callback fired by an hICN listener upon reception of a MAP-Me + * @brief Callback fired by an hICN listener upon reception of a MAP-Me * message. - * @param [in] forwarder - Pointer to the hICN forwarder. - * @param [in] msgBuffer - MAP-Me buffer - * @param [in] conn_id - Ingress connection id + * @param[in] forwarder - Pointer to the forwarder. + * @param[in] msgBuffer - MAP-Me buffer + * @param[in] conn_id - Ingress connection id */ -void forwarder_ProcessMapMe(Forwarder *forwarder, const uint8_t *msgBuffer, - unsigned conn_id); +void forwarder_process_mapme(const forwarder_t *forwarder, + const uint8_t *packet, unsigned conn_id); -struct mapme; -struct mapme * forwarder_getMapmeInstance(const Forwarder *forwarder); +struct mapme_s *forwarder_get_mapme(const forwarder_t *forwarder); #endif /* WITH_MAPME */ -#endif // forwarder_h +#ifdef WITH_POLICY_STATS +const policy_stats_mgr_t *forwarder_get_policy_stats_mgr( + const forwarder_t *forwarder); +#endif /* WITH_POLICY_STATS */ + +void forwarder_flush_connections(forwarder_t *forwarder); + +/** + * @brief Handles a newly received packet from a listener. + * + * NOTE: the received msgbuf is incomplete and only holds the packet content and + * size/ + */ +ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener, + off_t msgbuf_id, address_pair_t *pair, Ticks now); + +/** + * @brief Log forwarder statistics, e.g. info about packets processed, packets + * dropped, packets forwarded, errors while forwarding, interest and data + * processing results. + * + * @param forwarder Pointer to the forwarder data structure to use + */ +void forwarder_log(forwarder_t *forwarder); + +#endif // HICNLIGHT_FORWARDER_H diff --git a/hicn-light/src/hicn/core/listener.c b/hicn-light/src/hicn/core/listener.c new file mode 100644 index 000000000..ecdfc38f4 --- /dev/null +++ b/hicn-light/src/hicn/core/listener.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file listener.c + * @brief Implementation of hICN listeners + */ + +#include <string.h> // strdup + +#include <hicn/util/log.h> + +#include "forwarder.h" +#include "listener_vft.h" +#include "../base/loop.h" +#include "../io/base.h" + +listener_key_t listener_key_factory(address_t address, face_type_t type) { + listener_key_t key; + memset(&key, 0, sizeof(listener_key_t)); + + key.address = address; + key.type = type; + return key; +} + +listener_t *listener_create(face_type_t type, const address_t *address, + const char *interface_name, const char *name, + forwarder_t *forwarder) { + listener_table_t *table = forwarder_get_listener_table(forwarder); + + listener_key_t key = listener_key_factory(*address, type); + + listener_t *listener = listener_table_allocate(table, &key, name); + unsigned listener_id = listener_table_get_listener_id(table, listener); + + int ret = listener_initialize(listener, type, name, listener_id, address, + interface_name, forwarder); + if (ret < 0) { + listener_table_remove_by_id(table, listener_id); + listener_finalize(listener); + return NULL; + } + + WITH_INFO({ + char addr_str[NI_MAXHOST]; + int port; + address_to_string(address, addr_str, &port); + INFO("LISTENER CREATE (%s) %p created for address %s:%d", + face_type_str(listener->type), listener, addr_str, port); + listener_table_print_by_key(table); + }) + + return listener; +} + +int listener_initialize(listener_t *listener, face_type_t type, + const char *name, unsigned listener_id, + const address_t *address, const char *interface_name, + forwarder_t *forwarder) { + int rc; + + assert(listener); + assert(forwarder); + + *listener = (listener_t){ + .id = listener_id, + .name = strdup(name), + .key = listener_key_factory(*address, type), + .interface_name = strdup(interface_name), + .family = address->as_ss.ss_family, + .fd = 0, + .forwarder = forwarder, + }; + + face_protocol_t face_protocol = get_protocol(listener->type); + if (face_protocol == FACE_PROTOCOL_UNKNOWN) goto ERR_VFT; + + listener->data = malloc(listener_vft[face_protocol]->data_size); + if (!listener->data) goto ERR_DATA; + + assert(listener_has_valid_type(listener)); + + rc = listener_vft[face_protocol]->initialize(listener); + if (rc < 0) goto ERR_VFT; + + listener->fd = listener_vft[face_protocol]->get_socket(listener, address, + NULL, interface_name); + if (listener->fd < 0) { + char addr_str[NI_MAXHOST]; + int port; + address_to_string(address, addr_str, &port); + ERROR("Error creating listener %s fd: (%d) %s", addr_str, errno, + strerror(errno)); + goto ERR_FD; + } + assert(listener->fd > 0); + + // XXX data should be pre-allocated here + + loop_fd_event_create(&listener->event_data, MAIN_LOOP, listener->fd, listener, + (fd_callback_t)listener_read_callback, NULL); + + if (!listener->event_data) { + goto ERR_REGISTER_FD; + } + + if (loop_fd_event_register(listener->event_data) < 0) { + goto ERR_REGISTER_FD; + } + + return 0; + +ERR_REGISTER_FD: +#ifndef _WIN32 + close(listener->fd); +#else + closesocket(listener->fd); +#endif +ERR_FD: +ERR_VFT: +ERR_DATA: + return -1; +} + +int listener_finalize(listener_t *listener) { + assert(listener); + assert(listener_has_valid_type(listener)); + + if (listener->event_data) { + loop_event_unregister(listener->event_data); + loop_event_free(listener->event_data); + } + + if (listener->fd != -1) { +#ifndef _WIN32 + close(listener->fd); +#else + closesocket(listener->fd); +#endif + } + + listener_vft[get_protocol(listener->type)]->finalize(listener); + + if (listener->data) free(listener->data); + listener->data = NULL; + if (listener->interface_name) free(listener->interface_name); + listener->interface_name = NULL; + if (listener->name) free(listener->name); + listener->name = NULL; + + return 0; +} + +int listener_get_socket(const listener_t *listener, const address_t *local, + const address_t *remote, const char *interface_name) { + assert(listener); + assert(listener_has_valid_type(listener)); + assert(local); + // assert(remote); TODO: can it be null? + + // DEBUG("[listener_get_socket]"); + + return listener_vft[get_protocol(listener->type)]->get_socket( + listener, local, remote, interface_name); +} + +/* + * This is called from the forwarder to dynamially create new connections on the + * listener, in that case, name is NULL. It is also called from + * connection_create, which is itself called from the configuration part. + */ +unsigned listener_create_connection(listener_t *listener, + const char *connection_name, + const address_pair_t *pair) { + assert(listener); + assert(listener_has_valid_type(listener)); + assert(pair); + + connection_table_t *table = + forwarder_get_connection_table(listener->forwarder); + connection_t *connection = + connection_table_allocate(table, pair, connection_name); + unsigned connection_id = + connection_table_get_connection_id(table, connection); + + /* + * We create a connected connection with its own fd, instead of returning + * the fd of the listener. This will allow to avoid specifying the + * destination address when sending packets, and will increase performance + * by avoiding a FIB lookup for each packet. + */ +#ifdef USE_CONNECTED_SOCKETS + int fd = listener_get_socket(listener, address_pair_get_local(pair), + address_pair_get_remote(pair), + listener->interface_name); +#else + int fd = 0; // means listener->fd; +#endif + bool local = address_is_local(address_pair_get_local(pair)); + + face_type_t connection_type; + switch (listener->type) { + case FACE_TYPE_UDP_LISTENER: + connection_type = FACE_TYPE_UDP; + break; + case FACE_TYPE_TCP_LISTENER: + connection_type = FACE_TYPE_TCP; + break; + default: + connection_table_remove_by_id(table, connection_id); + return CONNECTION_ID_UNDEFINED; + } + + int rc = connection_initialize(connection, connection_type, connection_name, + listener->interface_name, fd, pair, local, + connection_id, listener); + if (rc < 0) { + connection_table_remove_by_id(table, connection_id); + connection_finalize(connection); + return CONNECTION_ID_UNDEFINED; + } + + WITH_INFO({ + char local_addr_str[NI_MAXHOST]; + char remote_addr_str[NI_MAXHOST]; + int local_port; + int remote_port; + address_to_string(&(pair->local), local_addr_str, &local_port); + address_to_string(&(pair->remote), remote_addr_str, &remote_port); + INFO("%s connection %p created for address pair %s:%d (local=%s) - %s:%d", + face_type_str(connection->type), connection, local_addr_str, + local_port, connection_is_local(connection) ? "true" : "false", + remote_addr_str, remote_port); + connection_table_print_by_pair(table); + }) + +#if 0 + DEBUG("Notification for new connections"); + // Generate notification message + flag_interface_type_t interface_type = + FLAG_INTERFACE_TYPE_WIRED | FLAG_INTERFACE_TYPE_CELLULAR; + struct { + cmd_header_t header; + hc_event_interface_update_t payload; + } msg = {.header = + { + .message_type = NOTIFICATION_LIGHT, + .command_id = EVENT_INTERFACE_UPDATE, + .length = 0, + .seq_num = 0, + }, + .payload = {.interface_type = interface_type}}; + size_t size = sizeof(msg); + + // Retrieve subscribed connections + subscription_table_t *subscriptions = + forwarder_get_subscriptions(listener->forwarder); + unsigned *subscribed_conn_ids = subscription_table_get_connections_for_topic( + subscriptions, TOPIC_CONNECTION); + + // Send notification to subscribed connections + for (int i = 0; i < vector_len(subscribed_conn_ids); i++) { + DEBUG("Sending notification to connection: %u", subscribed_conn_ids[i]); + const connection_t *conn = + connection_table_at(table, subscribed_conn_ids[i]); + connection_send_packet(conn, (uint8_t *)&msg, size); + } +#endif + + return connection_id; +} + +int listener_punt(const listener_t *listener, const char *prefix_s) { + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_HICN); + assert(prefix_s); + + return listener_vft[get_protocol(listener->type)]->punt(listener, prefix_s); +} + +ssize_t listener_read_single(listener_t *listener, int fd) { + assert(listener); + + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(listener->forwarder); + + // Preapare the msgbuf + msgbuf_t *msgbuf = NULL; + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + if (!msgbuf_id_is_valid(msgbuf_id)) return -1; + + // Prepare the address pair + address_pair_t pair; + memset(&pair, 0, sizeof(address_pair_t)); + pair.local = listener->address; + + // Read message and populate the remote address + ssize_t n = listener_vft[get_protocol(listener->type)]->read_single( + fd, msgbuf, address_pair_get_remote(&pair)); + if (n <= 0) { + msgbuf_pool_put(msgbuf_pool, msgbuf); + return -1; + } + + msgbuf_pool_acquire(msgbuf); + + // Process received packet + size_t processed_bytes = forwarder_receive(listener->forwarder, listener, + msgbuf_id, &pair, ticks_now()); + forwarder_log(listener->forwarder); + if (processed_bytes <= 0) ERROR("Unable to handle message"); + + /* + * The connection on which we went packets might do batching (even without + * sendmmsg), and we need to inform the system that we want to proceed to + * sending packets. + */ + forwarder_flush_connections(listener->forwarder); + msgbuf_pool_release(msgbuf_pool, &msgbuf); + return processed_bytes; +} + +ssize_t listener_read_batch(listener_t *listener, int fd) { + assert(listener); + + size_t total_processed_bytes = 0; + ssize_t num_msg_received = 0; + off_t *acquired_msgbuf_ids; + vector_init(acquired_msgbuf_ids, MAX_MSG, 0); + + forwarder_t *forwarder = listener->forwarder; + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + + /* Receive messages in the loop as long as we manage to fill the buffers */ + do { + /* Prepare the msgbuf and address pair arrays */ + msgbuf_t *msgbufs[MAX_MSG]; + if (msgbuf_pool_getn(msgbuf_pool, msgbufs, MAX_MSG) < 0) { + ERROR("Unable to get message buffers"); + break; + } + + address_pair_t pair[MAX_MSG]; + address_t *address_remote[MAX_MSG]; + memset(&pair, 0, MAX_MSG * sizeof(address_pair_t)); + + off_t msgbuf_ids[MAX_MSG]; + for (unsigned i = 0; i < MAX_MSG; i++) { + // Copy the pointers to the remote addresses + address_remote[i] = address_pair_get_remote(&pair[i]); + + // Populate local addresses + pair[i].local = listener->address; + + // Do NOT rely on msgbuf pointers since a msgbuf pool rezise event may + // make them invalid, use msgbuf ids instead + msgbuf_ids[i] = msgbuf_pool_get_id(msgbuf_pool, msgbufs[i]); + } + + // Read batch and populate remote addresses + num_msg_received = listener_vft[get_protocol(listener->type)]->read_batch( + fd, msgbufs, address_remote, MAX_MSG); + + for (int i = 0; i < MAX_MSG; i++) { + // Release unused msg buffers + if (i >= num_msg_received) { + msgbuf_pool_put(msgbuf_pool, msgbufs[i]); + continue; + } + + msgbuf_pool_acquire(msgbufs[i]); + vector_push(acquired_msgbuf_ids, msgbuf_ids[i]); + } + + if (num_msg_received < 0) break; + TRACE("[listener_read_batch] batch size = %d", num_msg_received); + + for (unsigned i = 0; i < num_msg_received; i++) { + size_t processed_bytes = forwarder_receive( + forwarder, listener, msgbuf_ids[i], &pair[i], ticks_now()); + forwarder_log(listener->forwarder); + + total_processed_bytes += processed_bytes; + } + } while (num_msg_received == + MAX_MSG); /* backpressure based on queue size ? */ + + /* + * Signal to the forwarder that we reached the end of a batch and we need to + * flush connections out + */ + forwarder_flush_connections(forwarder); + + for (int i = 0; i < vector_len(acquired_msgbuf_ids); i++) { + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, acquired_msgbuf_ids[i]); + msgbuf_pool_release(msgbuf_pool, &msgbuf); + } + vector_free(acquired_msgbuf_ids); + + return total_processed_bytes; +} + +/* + * This might be called for a connection on the listener too. The listener is + * the entity that owns the buffers used for reading. + */ +ssize_t listener_read_callback(listener_t *listener, int fd, void *user_data) { + // DEBUG("[listener_read_callback]"); + // XXX make a single callback and arbitrate between read and readbatch + assert(listener); + + /* + * As the listener callback is shared between the listener and the different + * connections created on top of it, the fd might be either of them. + */ + // assert(fd == listener->fd); + + if (listener_vft[get_protocol(listener->type)]->read_batch) + return listener_read_batch(listener, fd); + + return listener_read_single(listener, fd); +} + +void listener_setup_local(forwarder_t *forwarder, uint16_t port) { + address_t localhost_ipv4_addr = ADDRESS4_LOCALHOST(port); + listener_create(FACE_TYPE_UDP_LISTENER, &localhost_ipv4_addr, "lo", "lo_udp4", + forwarder); + + address_t localhost_ipv6_addr = ADDRESS6_LOCALHOST(port); + listener_create(FACE_TYPE_UDP_LISTENER, &localhost_ipv6_addr, "lo", "lo_udp6", + forwarder); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/core/listener.h b/hicn-light/src/hicn/core/listener.h new file mode 100644 index 000000000..346c874c0 --- /dev/null +++ b/hicn-light/src/hicn/core/listener.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file listener.h + * @brief hICN listeners + */ + +#ifndef HICNLIGHT_LISTENER_H +#define HICNLIGHT_LISTENER_H + +#include <hicn/face.h> + +#include "address_pair.h" +#include "msgbuf.h" +#include "../base/loop.h" + +#define LISTENER_ID_UNDEFINED ~0 + +struct forwarder_s; + +typedef struct { + address_t address; + face_type_t type; +} listener_key_t; + +/** + * @brief Create a listener key starting from an address and a face type. + * + * @param address + * @param type + * @return listener_key_t The listener key created. + * + * @note The listener key returned is resetted before intializing + * the internal fields, to allow a reliable hash generation. + */ +listener_key_t listener_key_factory(address_t address, face_type_t type); + +/* This structure holds what is in common to all listeners */ +typedef struct { + int id; + char *name; + union { + listener_key_t key; + struct { + address_t address; + face_type_t type; + }; + }; + + char *interface_name; + unsigned family; + + int fd; + event_t *event_data; + + void *data; /* Listener specific data */ + struct forwarder_s *forwarder; +} listener_t; + +#define listener_get_id(L) ((L)->id) +#define listener_get_name(L) ((L)->name) +#define listener_get_key(L) (&(L)->key) +#define listener_get_type(L) ((L)->type) +#define listener_get_interface_name(L) ((L)->interface_name) +#define listener_get_address(L) (&(L)->address) +#define listener_has_valid_type(L) (face_type_is_valid((L)->type)) +#define listener_id_is_valid(ID) (ID != LISTENER_ID_UNDEFINED) + +listener_t *listener_create(face_type_t type, const address_t *address, + const char *interface_name, const char *symbolic, + struct forwarder_s *forwarder); + +/** + * @brief Helper function used inside 'listener_create' to + * setup variables in listener struct. + * + * @see listener_create + */ +int listener_initialize(listener_t *listener, face_type_t type, + const char *name, unsigned listener_id, + const address_t *address, const char *interface_name, + struct forwarder_s *forwarder); + +int listener_finalize(listener_t *listener); + +int listener_punt(const listener_t *listener, const char *prefix_s); + +int listener_get_socket(const listener_t *listener, const address_t *local, + const address_t *remote, const char *interface_name); + +unsigned listener_create_connection(listener_t *listener, const char *name, + const address_pair_t *pair); + +void listener_setup_local(struct forwarder_s *forwarder, uint16_t port); + +void listener_process_packet(const listener_t *listener, const uint8_t *packet, + size_t size); + +ssize_t listener_read_single(listener_t *listener, int fd); +ssize_t listener_read_batch(listener_t *listener, int fd); + +/** + * @brief Callback helper function for batch reading data from listener fd. + * + * This function is usually called from the listener read callback to proceed to + * actual reading of data from the fd. + * + * @see listener_read_callback + * + * NOTE: the function returns size_t as for TCP we might need to know how much + * data we can consume from the socket. + */ +ssize_t listener_read_callback(listener_t *listener, int fd, void *user_data); + +#define listener_get_forwarder(listener) (listener->forwarder) +#define listener_get_fd(listener) (listener->fd) + +#endif /* HICNLIGHT_LISTENER_H */ diff --git a/hicn-light/src/hicn/core/listener_table.c b/hicn-light/src/hicn/core/listener_table.c new file mode 100644 index 000000000..32b8e9d45 --- /dev/null +++ b/hicn-light/src/hicn/core/listener_table.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file listener_table.c + * \brief Implementation of hICN listener table + */ + +#include <hicn/util/log.h> + +#include "listener_table.h" +#include "listener.h" + +/* This is only used as a hint for first allocation, as the table is resizeable + */ +#define DEFAULT_LISTENER_TABLE_SIZE 64 + +listener_table_t *_listener_table_create(size_t init_size, size_t max_size) { + if (init_size == 0) init_size = DEFAULT_LISTENER_TABLE_SIZE; + + listener_table_t *table = malloc(sizeof(listener_table_t)); + if (!table) return NULL; + + table->max_size = max_size; + + /* Initialize indices */ + table->id_by_name = kh_init_lt_name(); + table->id_by_key = kh_init_lt_key(); + + /* + * We start by allocating a reasonably-sized pool, as this will eventually + * be resized if needed. + */ + pool_init(table->listeners, init_size, 0); + + return table; +} + +void listener_table_free(listener_table_t *table) { + const char *k_name; + const listener_key_t *k_key; + unsigned v; + + listener_t *listener; + const char *name; + kh_foreach(table->id_by_key, k_key, v, { + listener = listener_table_get_by_id(table, v); + name = listener_get_name(listener); + INFO("Removing listner %s [%d]", name, listener->fd); + listener_finalize(listener); + }); + + (void)v; + kh_foreach(table->id_by_name, k_name, v, { free((char *)k_name); }); + kh_foreach(table->id_by_key, k_key, v, { free((listener_key_t *)k_key); }); + + kh_destroy_lt_name(table->id_by_name); + kh_destroy_lt_key(table->id_by_key); + pool_free(table->listeners); + free(table); +} + +listener_t *listener_table_get_by_address(listener_table_t *table, + face_type_t type, + const address_t *address) { + listener_key_t key = listener_key_factory(*address, type); + khiter_t k = kh_get_lt_key(table->id_by_key, &key); + if (k == kh_end(table->id_by_key)) return NULL; + return listener_table_at(table, kh_val(table->id_by_key, k)); +} + +listener_t *listener_table_get_by_key(listener_table_t *table, + const listener_key_t *key) { + khiter_t k = kh_get_lt_key(table->id_by_key, key); + if (k == kh_end(table->id_by_key)) return NULL; + return listener_table_at(table, kh_val(table->id_by_key, k)); +} + +void listener_table_remove_by_id(listener_table_t *table, off_t id) { + listener_t *listener = listener_table_at(table, id); + INFO("Removing listener %d (%s)", id, listener_get_name(listener)); + + listener_table_deallocate(table, listener); +} + +off_t listener_table_get_id_by_name(const listener_table_t *table, + const char *name) { + khiter_t k = kh_get_lt_name(table->id_by_name, name); + if (k == kh_end(table->id_by_name)) return LISTENER_ID_UNDEFINED; + return kh_val(table->id_by_name, k); +} + +listener_t *listener_table_get_by_name(listener_table_t *table, + const char *name) { + unsigned listener_id = listener_table_get_id_by_name(table, name); + if (!listener_id_is_valid(listener_id)) return NULL; + return listener_table_at(table, listener_id); +} + +listener_t *_listener_table_get_by_id(listener_table_t *table, off_t id) { + return listener_table_get_by_id(table, id); +} + +void listener_table_print_by_key(const listener_table_t *table) { + const listener_key_t *k; + unsigned v; + + char addr_str[NI_MAXHOST]; + int port; + listener_t *listener; + const char *name; + + INFO("*** Listener table ***"); + kh_foreach(table->id_by_key, k, v, { + address_to_string(&k->address, addr_str, &port); + listener = listener_table_get_by_id(table, v); + name = listener_get_name(listener); + INFO("%s:%d - %s\t\t\t\t(%u, %s)", addr_str, port, face_type_str(k->type), + v, name); + }) +} + +void listener_table_print_by_name(const listener_table_t *table) { + const char *k; + unsigned v; + + char addr_str[NI_MAXHOST]; + int port; + listener_t *listener; + const listener_key_t *key; + + INFO("*** Listener table ***"); + kh_foreach(table->id_by_name, k, v, { + listener = listener_table_get_by_id(table, v); + key = listener_get_key(listener); + address_to_string(&key->address, addr_str, &port); + + INFO("%s:%d - %s\t\t\t\t(%u, %s)", addr_str, port, face_type_str(key->type), + v, k); + }) +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/core/listener_table.h b/hicn-light/src/hicn/core/listener_table.h new file mode 100644 index 000000000..5fed638e8 --- /dev/null +++ b/hicn-light/src/hicn/core/listener_table.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file listener_table.h + * \brief hICN listener table + * + * The listener table is composed of: + * - a pool of listeners allowing access through their index in constant time; + * - a set of indices in the form of hash table for efficient index lookups: + * . by name + * . by key (listener_type, address) + * + * For efficient index retrieval, the header will be prepended and the + * resulting pointer will directly point to the listener pool. + */ + +#ifndef HICNLIGHT_LISTENER_TABLE_H +#define HICNLIGHT_LISTENER_TABLE_H + +#include "address.h" +#include "listener.h" +#include "../base/common.h" +#include "../base/hash.h" +#include "../base/khash.h" +#include "../base/pool.h" + +#define _lt_var(x) _lt_var_##x + +/* Hash functions for indices */ +#define key_hash(key) (hash_struct(key)) +#define key_hash_eq(a, b) (key_hash(b) == key_hash(a)) + +/* Hash table types for indices */ +KHASH_MAP_INIT_STR(lt_name, unsigned); +KHASH_INIT(lt_key, const listener_key_t *, unsigned, 1, key_hash, key_hash_eq); + +typedef struct { + size_t max_size; + + kh_lt_key_t *id_by_key; + kh_lt_name_t *id_by_name; + + listener_t *listeners; // pool +} listener_table_t; + +/** + * @brief Allocate a listener from the listener table. + * + * @param[in] table The listener table from which to allocate a listener. + * @param[out] listener The pointer that will hold the allocated listener. + * @param[in] pair The address pair associated to the listener (to update index) + * @param[in] name The name associated to the listener (to update index) + * + * NOTE: + * - This function updates all indices from the listener table if the + * allocation is successful. + * - You should always check that the returned listener is not NULL, which + * would signal that the pool is exhausted and could not be extended. + */ + +static inline listener_t *listener_table_allocate(const listener_table_t *table, + const listener_key_t *key, + const char *name) { + listener_t *listener; + pool_get(table->listeners, listener); + + if (listener) { + off_t id = listener - table->listeners; + int res; + khiter_t k; + + // Add in name hash table + k = kh_put_lt_name(table->id_by_name, strdup(name), &res); + assert(res > 0); + kh_value(table->id_by_name, k) = id; + + // Add in key hash table + listener_key_t *key_copy = (listener_key_t *)malloc(sizeof(listener_key_t)); + memcpy(key_copy, key, sizeof(listener_key_t)); + + k = kh_put_lt_key(table->id_by_key, key_copy, &res); + assert(res > 0); + kh_value(table->id_by_key, k) = id; + } + + return listener; +} + +/** + * @brief Deallocate a listener and return it to the listener table pool. + * + * @param[in] table The listener table to which the listener is returned. + * @param[in] conn The listener that is returned to the pool. + * + * NOTE: + * - Upon returning a listener to the pool, all indices pointing to that + * listener are also cleared. + */ + +static inline void listener_table_deallocate(const listener_table_t *table, + listener_t *listener) { + const char *name = listener_get_name(listener); + listener_key_t *key = listener_get_key(listener); + khiter_t k; + + // Remove from name hash table + k = kh_get_lt_name(table->id_by_name, name); + assert(k != kh_end(table->id_by_name)); + free((char *)kh_key(table->id_by_name, k)); + kh_del_lt_name(table->id_by_name, k); + + // Remove from key hash table + k = kh_get_lt_key(table->id_by_key, key); + assert(k != kh_end(table->id_by_key)); + free((listener_key_t *)kh_key(table->id_by_key, k)); + kh_del_lt_key(table->id_by_key, k); + + pool_put(table->listeners, listener); +} + +/** + * @brief Returns the length of the listener table, the number of active + * listeners. + * + * @param[in] table The listener table for which we retrieve the length. + * + * @return size_t The length of the listener table. + * + * NOTE: + * - The length of the listener table, that is the number of currently active + * listeners. + */ +#define listener_table_len(table) (pool_len(table->listeners)) + +/** + * @brief Validate an index in the listener table. + * + * @param[in] table The listener table in which to validate an index. + * @param[in] id The index of the listener to validate. + * + * @return bool A flag indicating whether the listener index is valid or not. + */ +#define listener_table_validate_id(table, id) \ + pool_validate_id(table->listeners, id) + +/** + * @brief Return the listener corresponding to the specified index in the + * listener table. + * + * @param[in] table The listener table for which to retrieve the listener. + * @param[in] id The index for which to retrieve the listener. + * + * @return listener_t * The listener correponding to the specified index in + * the listener table. + * + * @see listener_table_get_by_id + * + * NOTE: + * - In this function, the index is not validated. + */ +#define listener_table_at(table, id) ((table)->listeners + id) + +/** + * @brief Return the listener corresponding to the specified and validated + * index in the listener table. + * + * @param[in] table The listener table for which to retrieve the listener. + * @param[in] id The index for which to retrieve the listener. + * + * @return listener_t * The listener correponding to the specified index in + * the listener table. + * + * @see listener_table_get_by_id + * + * NOTE: + * - In this function, the index is validated. + */ +#define listener_table_get_by_id(table, id) \ + listener_table_validate_id(table, id) ? listener_table_at(table, id) : NULL + +/** + * @brief Helper function to avoid macro expansion in c++ tests. Wrapper around + * 'listener_table_get_by_id'. + */ +listener_t *_listener_table_get_by_id(listener_table_t *table, off_t id); + +/** + * @brief Returns the index of a given listener in the listener table. + * + * @param[in] table The listener table from which to retrieve the index. + * @param[in] conn The listener for which to retrieve the index. + * + * @return off_t The index of the specified listener in the listener table. + */ +#define listener_table_get_listener_id(table, listener) \ + (listener - table->listeners) + +#define listener_table_foreach(table, listener, BODY) \ + pool_foreach( \ + table->listeners, listener, do { BODY } while (0)) + +#define listener_table_enumerate(table, i, conn, BODY) \ + pool_enumerate(table->listeners, (i), (conn), BODY) + +/** + * @brief Create a new listener table (extended parameters) + * + * @param[in] init_size Initially allocated size (hint, 0 = use default value) + * @param[in] max_size Maximum size (0 = unlimited) + * + * @return listener_table_t* - The newly created listener table + */ +listener_table_t *_listener_table_create(size_t init_size, size_t max_size); + +/** + * @brief Create a new listener table (minimal parameters) + * + * @return listener_table_t* - The newly created listener table + */ +#define listener_table_create() _listener_table_create(0, 0) + +/** + * @brief Free a listener table + * + * @param[in] table Listener table to free + */ +void listener_table_free(listener_table_t *table); + +/** + * @brief Retrieve a listener from the listener table by address. + * + * @param[in] table The listener table in which to search. + * @param[in] type The face type characterizing the listener to search for. + * @param[in] address The address to search for. + * + * @return listener_t * The listener matching the specified address, or + * NULL if not found. + */ +listener_t *listener_table_get_by_address(listener_table_t *table, + face_type_t type, + const address_t *address); + +/** + * @brief Retrieve a listener from the listener table by listener key (i.e. + * address + face type). + * + * @param[in] table The listener table in which to search. + * @param[in] key The listener key characterizing the listener to search for. + * + * @return listener_t * The listener matching the specified address, or + * NULL if not found. + */ +listener_t *listener_table_get_by_key(listener_table_t *table, + const listener_key_t *key); + +/** + * @brief Return a listener index from the listener table by name. + * + * @param[in] table The listener table in which to search. + * @param[in] name The name to search for. + * + * @return off_t The index of the listener matching the name, or + * LISTENER_ID_UNDEFINED if not found. + */ +off_t listener_table_get_id_by_name(const listener_table_t *table, + const char *name); + +/** + * @brief Return a listener from the listener table by name. + * + * @param[in] table The listener table in which to search. + * @param[in] name The name to search for. + * + * @return listener_t * The listener matching the name, or NULL if not + * found. + */ +listener_t *listener_table_get_by_name(listener_table_t *table, + const char *name); + +/** + * @brief Remove a listener from the listener table by its index. + * + * @param[in] table The listener table from which to delete the listener. + * @param[in] id The index of the listener to remove. + */ +void listener_table_remove_by_id(listener_table_t *table, off_t id); + +/** + * @brief Print the listener table content. + * + * @param[in] table The listener table to print. + */ +void listener_table_print_by_key(const listener_table_t *table); + +void listener_table_print_by_name(const listener_table_t *table); + +#endif /* HICNLIGHT_LISTENER_TABLE_H */ diff --git a/hicn-light/src/hicn/config/controlAddPolicy.h b/hicn-light/src/hicn/core/listener_vft.c index 273e3a476..600c9482f 100644 --- a/hicn-light/src/hicn/config/controlAddPolicy.h +++ b/hicn-light/src/hicn/core/listener_vft.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -14,22 +14,23 @@ */ /** - * @file control_AddPolicy.h - * @brief Add a static policy - * - * Implements the "add policy" node of the CLI tree - * + * @file listener_vft.c + * @brief Implementation of listener VFT */ -#ifndef Control_AddPolicy_h -#define Control_AddPolicy_h - -#ifdef WITH_POLICY +#include "listener_vft.h" -#include <hicn/config/controlState.h> -CommandOps *controlAddPolicy_Create(ControlState *state); -CommandOps *controlAddPolicy_HelpCreate(ControlState *state); +#ifdef __linux__ +extern listener_ops_t listener_hicn; +#endif +extern listener_ops_t listener_tcp; +extern listener_ops_t listener_udp; -#endif /* WITH_POLICY */ +const listener_ops_t* listener_vft[] = { +#ifdef __linux__ + [FACE_PROTOCOL_HICN] = &listener_hicn, +#endif -#endif // Control_AddPolicy_h + [FACE_PROTOCOL_TCP] = &listener_tcp, + [FACE_PROTOCOL_UDP] = &listener_udp, +}; diff --git a/hicn-light/src/hicn/core/listener_vft.h b/hicn-light/src/hicn/core/listener_vft.h new file mode 100644 index 000000000..97f08778c --- /dev/null +++ b/hicn-light/src/hicn/core/listener_vft.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file listener_vft.h + * @brief Listener VFT + */ + +#ifndef HICNLIGHT_LISTENER_VFT_H +#define HICNLIGHT_LISTENER_VFT_H + +#include <hicn/core/address_pair.h> +#include <hicn/core/connection.h> +#include <hicn/core/listener.h> +#include <hicn/face.h> + +typedef struct { + int (*initialize)(listener_t* listener); + void (*finalize)(listener_t* listener); + int (*punt)(const listener_t* listener, const char* prefix_s); + int (*get_socket)(const listener_t* listener, const address_t* local, + const address_t* remote, const char* interface_name); + int (*send)(const connection_t* connection, const address_t* dummy, + msgbuf_t* msgbuf, bool queue); + int (*send_packet)(const connection_t* connection, const uint8_t* packet, + size_t size); + ssize_t (*read_single)(int fd, msgbuf_t* msgbuf, address_t* address); + ssize_t (*read_batch)(int fd, msgbuf_t** msgbuf, address_t** address, + size_t len); + size_t data_size; +} listener_ops_t; + +#define DECLARE_LISTENER(NAME) \ + const listener_ops_t listener_##NAME = { \ + .initialize = listener_##NAME##_initialize, \ + .finalize = listener_##NAME##_finalize, \ + .punt = listener_##NAME##_punt, \ + .get_socket = listener_##NAME##_get_socket, \ + .read_single = listener_##NAME##_read_single, \ + .read_batch = listener_##NAME##_read_batch, \ + .data_size = sizeof(listener_##NAME##_data_t), \ + } + +extern const listener_ops_t* listener_vft[]; + +#endif /* HICNLIGHT_LISTENER_VFT_H */ diff --git a/hicn-light/src/hicn/core/logger.c b/hicn-light/src/hicn/core/logger.c deleted file mode 100644 index 0b9bb264c..000000000 --- a/hicn-light/src/hicn/core/logger.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 _WIN32 -#include <unistd.h> -#endif - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> - -#include <parc/logging/parc_Log.h> - -#include <hicn/core/forwarder.h> -#include <hicn/core/logger.h> - -struct logger { - PARCClock *clock; - - PARCLogReporter *reporter; - PARCLog *loggerArray[LoggerFacility_END]; -}; - -static const struct facility_to_string { - LoggerFacility facility; - const char *string; -} _facilityToString[] = { - {.facility = LoggerFacility_Config, .string = "Config"}, - {.facility = LoggerFacility_Core, .string = "Core"}, - {.facility = LoggerFacility_IO, .string = "IO"}, - {.facility = LoggerFacility_Message, .string = "Message"}, - {.facility = LoggerFacility_Processor, .string = "Processor"}, - {.facility = LoggerFacility_Strategy, .string = "Strategy"}, - {.facility = 0, .string = NULL}}; - -const char *logger_FacilityString(LoggerFacility facility) { - for (int i = 0; _facilityToString[i].string != NULL; i++) { - if (_facilityToString[i].facility == facility) { - return _facilityToString[i].string; - } - } - return "Unknown"; -} - -static void _allocateLoggers(Logger *logger, PARCLogReporter *reporter) { - parcTrapUnexpectedStateIf( - logger->reporter != NULL, - "Trying to allocate a reporter when the previous one is not null"); - logger->reporter = parcLogReporter_Acquire(reporter); - - char hostname[255]; - int gotHostName = gethostname(hostname, 255); - if (gotHostName < 0) { - snprintf(hostname, 255, "unknown"); - } - - for (int i = 0; i < LoggerFacility_END; i++) { - logger->loggerArray[i] = parcLog_Create(hostname, logger_FacilityString(i), - "forwarder", logger->reporter); - parcLog_SetLevel(logger->loggerArray[i], PARCLogLevel_Error); - } -} - -static void _releaseLoggers(Logger *logger) { - for (int i = 0; i < LoggerFacility_END; i++) { - parcLog_Release(&logger->loggerArray[i]); - } - parcLogReporter_Release(&logger->reporter); -} - -static void _destroyer(Logger **loggerPtr) { - Logger *logger = *loggerPtr; - _releaseLoggers(logger); - parcClock_Release(&(*loggerPtr)->clock); -} - -parcObject_ExtendPARCObject(Logger, _destroyer, NULL, NULL, NULL, NULL, NULL, - NULL); - -parcObject_ImplementAcquire(logger, Logger); - -parcObject_ImplementRelease(logger, Logger); - -Logger *logger_Create(PARCLogReporter *reporter, const PARCClock *clock) { - parcAssertNotNull(reporter, "Parameter reporter must be non-null"); - parcAssertNotNull(clock, "Parameter clock must be non-null"); - - Logger *logger = parcObject_CreateAndClearInstance(Logger); - if (logger) { - logger->clock = parcClock_Acquire(clock); - _allocateLoggers(logger, reporter); - } - - return logger; -} - -void logger_SetReporter(Logger *logger, PARCLogReporter *reporter) { - parcAssertNotNull(logger, "Parameter logger must be non-null"); - - // save the log level state - PARCLogLevel savedLevels[LoggerFacility_END]; - for (int i = 0; i < LoggerFacility_END; i++) { - savedLevels[i] = parcLog_GetLevel(logger->loggerArray[i]); - } - - _releaseLoggers(logger); - - _allocateLoggers(logger, reporter); - - // restore log level state - for (int i = 0; i < LoggerFacility_END; i++) { - parcLog_SetLevel(logger->loggerArray[i], savedLevels[i]); - } -} - -void logger_SetClock(Logger *logger, PARCClock *clock) { - parcAssertNotNull(logger, "Parameter logger must be non-null"); - parcClock_Release(&logger->clock); - logger->clock = parcClock_Acquire(clock); -} - -static void _assertInvariants(const Logger *logger, LoggerFacility facility) { - parcAssertNotNull(logger, "Parameter logger must be non-null"); - parcTrapOutOfBoundsIf(facility >= LoggerFacility_END, "Invalid facility %d", - facility); -} - -void logger_SetLogLevel(Logger *logger, LoggerFacility facility, - PARCLogLevel minimumLevel) { - _assertInvariants(logger, facility); - PARCLog *log = logger->loggerArray[facility]; - parcLog_SetLevel(log, minimumLevel); -} - -bool logger_IsLoggable(const Logger *logger, LoggerFacility facility, - PARCLogLevel level) { - _assertInvariants(logger, facility); - PARCLog *log = logger->loggerArray[facility]; - return parcLog_IsLoggable(log, level); -} - -void logger_Log(Logger *logger, LoggerFacility facility, PARCLogLevel level, - const char *module, const char *format, ...) { - if (logger_IsLoggable(logger, facility, level)) { - // this is logged as the messageid - uint64_t logtime = parcClock_GetTime(logger->clock); - - // logger_IsLoggable asserted invariants so we know facility is in bounds - PARCLog *log = logger->loggerArray[facility]; - - va_list va; - va_start(va, format); - - parcLog_MessageVaList(log, level, logtime, format, va); - - va_end(va); - } -} diff --git a/hicn-light/src/hicn/core/logger.h b/hicn-light/src/hicn/core/logger.h deleted file mode 100644 index 8ab741f40..000000000 --- a/hicn-light/src/hicn/core/logger.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file logger.h - * @brief Logger for the hicn-light forwarder - * - * A facility based logger to allow selective logging from different parts of - * hicn-light - * - */ - -#ifndef logger_h -#define logger_h - -#ifndef _WIN32 -#include <sys/time.h> -#endif -#include <parc/algol/parc_Buffer.h> -#include <parc/algol/parc_Clock.h> -#include <parc/logging/parc_LogLevel.h> -#include <parc/logging/parc_LogReporter.h> -#include <stdarg.h> - -struct logger; -typedef struct logger Logger; - -/** - * CONFIG faciilty concerns anything in the /config directory - * CORE concerns anything in the /core directory - * IO concerns anything in the /io directory (listeners, connectors, tcp, - * ethernet, etc.) PROCESSOR concerns FIB, PIT, CS MESSAGE concerns message - * events, like parsing - */ -typedef enum { - LoggerFacility_Config, - LoggerFacility_Core, - LoggerFacility_IO, - LoggerFacility_Processor, - LoggerFacility_Message, - LoggerFacility_Strategy, - LoggerFacility_END // sentinel value -} LoggerFacility; - -/** - * Returns a string representation of a facility - * - * Do not free the returned value. - * - * @param [in] facility The facility to change to a string - * - * @retval string A string representation of the facility - */ -const char *logger_FacilityString(LoggerFacility facility); - -/** - * Returns a string representation of a log level - * - * Do not free the returned value. - * - * @param [in] level The level to change to a string - * - * @retval string A string representation of the level - */ -const char *logger_LevelString(PARCLogLevel level); - -/** - * Create a logger that uses a given writer and clock - * - * <#Paragraphs Of Explanation#> - * - * @param [in] writer The output writer - * @param [in] clock The clock to use for log messages - * - * @retval non-null An allocated logger - * @retval null An error - */ -Logger *logger_Create(PARCLogReporter *reporter, const PARCClock *clock); - -/** - * Release logger - */ -void logger_Release(Logger **loggerPtr); - -/** - * Acquire logger - */ -Logger *logger_Acquire(const Logger *logger); - -/** - * Sets the minimum log level for a facility - * - * The default log level is ERROR. For a message to be logged, it must be of - * equal or higher log level. - * - * @param [in] logger An allocated logger - * @param [in] facility The facility to set the log level for - * @param [in] The minimum level to log - * - */ -void logger_SetLogLevel(Logger *logger, LoggerFacility facility, - PARCLogLevel minimumLevel); - -/** - * Tests if the log level would be logged - * - * If the facility would log the given level, returns true. May be used as a - * guard around expensive logging functions. - * - * @param [in] logger An allocated logger - * @param [in] facility The facility to test - * @param [in] The level to test - * - * @retval true The given facility would log the given level - * @retval false A message of the given level would not be logged - * - */ -bool logger_IsLoggable(const Logger *logger, LoggerFacility facility, - PARCLogLevel level); - -/** - * Log a message - * - * The message will only be logged if it is loggable (logger_IsLoggable returns - * true). - * - * @param [in] logger An allocated Logger - * @param [in] facility The facility to log under - * @param [in] level The log level of the message - * @param [in] module The specific module logging the message - * @param [in] format The message with varargs - * - */ -void logger_Log(Logger *logger, LoggerFacility facility, PARCLogLevel level, - const char *module, const char *format, ...); - -/** - * Switch the logger to a new reporter - * - * Will close the old reporter and re-setup the internal loggers to use the new - * reporter. All current log level settings are preserved. - * - * @param [in] logger An allocated Logger - * @param [in] reporter An allocated PARCLogReporter - */ -void logger_SetReporter(Logger *logger, PARCLogReporter *reporter); - -/** - * Set a new clock to use with the logger - * - * The logger will start getting the time (logged as the messageid) from the - * specified clock - * - * @param [in] logger An allocated Logger - * @param [in] clock An allocated PARCClock - */ -void logger_SetClock(Logger *logger, PARCClock *clock); -#endif // logger_h diff --git a/hicn-light/src/hicn/core/mapme.c b/hicn-light/src/hicn/core/mapme.c index 3a1c9777b..dfb30da5c 100644 --- a/hicn-light/src/hicn/core/mapme.c +++ b/hicn-light/src/hicn/core/mapme.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -16,6 +16,98 @@ /** * @file mapme.c * @brief MAP-Me : AnchorLess Producer Mobility Management. + * + * TODO: + * - review notification code with to integration of VPP implementation + * - reflect changes back in VPP + * - implement heuristic for update/notification selection + * + * MAP-Me hooks in forwarder + * + * A) Face table changes + * + * - face added + * + * * new local/producer face : this is a new prefix that we need to advertise + * on existing connections. + * + * We go over non-local connections an advertise the prefix through an IU + * provided that the connection satisfies the policy associated to the FIB + * entry. MAP-Me assumes the prefix already exists in the network, and the + * IU shall be discarded if the entry does not exist at the next hop. Three + * possibilities: + * . a bootstrap mechanism + * . we allow subprefixes of a prefix that is not empty by duplicating the + * FIB entry + * . we allow prefix creation in all circumstances : this is problematic + * since we might be creating spurious entries in routers for which we + * don't expect entries to be created. + * + * NOTE: because in general we will not allow for FIB entry creation, we + * cannot let the forwarder remove FIB entries with no nexthop (for instance + * after the producer leaves a point-of-attachment). This might creates + * permanent state in router's tables, but we assume it is the role of the + * routing plane to take care of routing entries. + * + * * new non-local face : a new face is available (eg. thanks to the face + * manager, after the node has connection to a new WiFi/LTE access point), + * and we thus need to advertise all local/producer prefixes onto this + * interface. + * + * For this, we currently scan the FIB for entries that have at least one + * local/producer face in nexthops, advertise the prefix on this new + * connection provided that it satisfies the associated policy. + * + * - face removed + * + * Currently, we take no action when a face is removed. It might however be a + * signal that a producer application is no more running at a given node, and + * that we can temporarily disable the forwarding towards that path. + * + * - face up / down + * + * - face nexthop added + * + * - face changed priority/tags + * + * B) Interest and Data forwarder path + * + * mapme_on_interest + * + * mapme_on_data + * + * + * EVENTS + * NH_SET + * NH_ADD + * PH_ADD + * PH_DEL + * + * C) Retransmission management + * + * Data structure + * + * mapme_on_timeout + * + * + * This allows us to define a convenient API for implementing MAP-Me: + * + * mapme_on_face_event XXX rename + * + * mapme_set_all_adjacencies(const mapme_t *mapme, fib_entry_t *entry) + * This function is used to update all the adjacencies. It needs to be called + * in case of face add/delete/change (priority/tas) and polocy + * + * mapme_set_adjacencies(const mapme_t *mapme, fib_entry_t *entry, + * nexthops_t *nexthops) + * This function updates only the nexthops and clear the tfib. It + * needs to be called by the forwarding strategy in case of path switch + * + * mapme_update_adjacencies(const mapme_t *mapme, fib_entry_t *entry, + * bool inc_iu_seq) + * This function is called to propagate the IU and it propagates the IU using + * the nexthops in the tfib. It needs to be used for mapme prcessing, IU + * forwarding, NATs and in case of timeouts */ #ifdef WITH_MAPME @@ -24,236 +116,184 @@ #include <hicn/core/mapme.h> #include <stdio.h> // printf +#include <hicn/base/loop.h> #include <hicn/core/connection.h> -#include <hicn/core/connectionList.h> #include <hicn/core/forwarder.h> -#include <hicn/core/logger.h> -#include <hicn/core/message.h> -#include <hicn/core/messagePacketType.h> // packet types +#include <hicn/core/msgbuf.h> #include <hicn/core/ticks.h> -#include <hicn/processor/fibEntry.h> -#include <hicn/processor/pitEntry.h> - -#include <parc/algol/parc_HashMap.h> -#include <parc/algol/parc_Iterator.h> -#include <parc/algol/parc_Unsigned.h> -#include <parc/assert/parc_Assert.h> +#include <hicn/core/fib_entry.h> +#include <hicn/core/pit.h> +#include <hicn/base/loop.h> +#include <hicn/util/log.h> #define MS2NS(x) x * 1000000 #define T2NS(x) forwarder_TicksToNanos(x) +//#define MAPME_ALLOW_NONEXISTING_FIB_ENTRY #define MAPME_DEFAULT_TU 5000 /* ms */ #define MAPME_DEFAULT_RETX 500 /* ms */ -#define MAX_RETX 3 +#define MAPME_DEFAULT_DISCOVERY false +#define MAPME_DEFAULT_PROTOCOL IPPROTO_IPV6 +#define MAPME_MAX_RETX 3 +#define MTU 1500 // XXX TODO Mutualize this define -#define NOT_A_NOTIFICATION false -#define NO_INGRESS 0 +#define DONT_QUEUE false #define TIMER_NO_REPEAT false -#define DO_DISCOVERY 1 #define MAPME_INVALID_DICOVERY_SEQ -1 +#define INIT_SEQ 0 -#define LOG_FACILITY LoggerFacility_Core +#define foreach_mapme_event \ + _(UNDEFINED) \ + _(FACE_ADD) \ + _(FACE_DEL) \ + _(NH_SET) \ + _(NH_ADD) \ + _(PH_ADD) \ + _(PH_DEL) \ + _(N) + +typedef enum { +#define _(x) MAPME_EVENT_##x, + foreach_mapme_event +#undef _ +} mapme_event_t; -#define LOG(mapme, log_level, fmt, ...) \ - do { \ - Logger *logger = forwarder_GetLogger(mapme->forwarder); \ - if (logger_IsLoggable(logger, LOG_FACILITY, log_level)) { \ - logger_Log(logger, LOG_FACILITY, log_level, __func__, fmt, \ - ##__VA_ARGS__); \ - } \ - } while (0) +/* + * We need a retransmission pool holding all necessary information for crafting + * special interests, thus including both the DPO and the prefix associated to + * it. + */ +#define NUM_RETX_ENTRIES 100 +#define NUM_RETX_SLOT 2 -#define WARN(mapme, fmt, ...) \ - LOG(mapme, PARCLogLevel_Warning, fmt, ##__VA_ARGS__) -#define ERR(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Error, fmt, ##__VA_ARGS__) -#define INFO(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Info, fmt, ##__VA_ARGS__) -#define DEBUG(mapme, fmt, ...) \ - LOG(mapme, PARCLogLevel_Debug, fmt, ##__VA_ARGS__) +typedef struct { + hicn_prefix_t prefix; + fib_entry_t *entry; + uint8_t retx_count; // Number of retransmissions since last tfib addition +} mapme_retx_t; /** * MAP-Me state data structure */ -struct mapme { - uint32_t retx; /* ms */ - uint32_t Tu; /* ms */ - bool removeFibEntries; +struct mapme_s { + /* Options XXX mapme_conf_t ! */ + uint32_t retx; /* retx timeout (in ms) */ + uint32_t timescale; /* timescale (in ms) */ + bool discovery; /* discovery flag */ + int protocol; + bool enabled; /* mapme enabled/disabled */ - Forwarder *forwarder; + /* + * Retransmissions + * Lite calendar queue with NUM_RETX_SLOT slots + */ + event_t *timer; + mapme_retx_t retx_array[NUM_RETX_SLOT][NUM_RETX_ENTRIES]; + uint8_t retx_len[NUM_RETX_SLOT]; + uint8_t cur; + uint8_t idle; + + forwarder_t *forwarder; }; -static MapMe MapMeDefault = {.retx = MAPME_DEFAULT_RETX, - .Tu = MAPME_DEFAULT_TU, - .removeFibEntries = false}; +#define NEXT_SLOT(CUR) (1 - CUR) +#define CUR mapme->retx_array[mapme->cur] +#define NXT mapme->retx_array[NEXT_SLOT(mapme->cur)] +#define CURLEN mapme->retx_len[mapme->cur] +#define NXTLEN mapme->retx_len[NEXT_SLOT(mapme->cur)] + +static mapme_t mapme_default = { + .retx = MAPME_DEFAULT_RETX, + .timescale = MAPME_DEFAULT_TU, + .discovery = MAPME_DEFAULT_DISCOVERY, + .protocol = MAPME_DEFAULT_PROTOCOL, + .enabled = true, + .timer = NULL, + // .retx_array = {{ 0 }}, // memset + .retx_len = {0}, + .cur = 0, /* current slot */ + .idle = 0, +}; /******************************************************************************/ -bool mapme_create(MapMe **mapme, Forwarder *forwarder) { - *mapme = malloc(sizeof(MapMe)); - if (!mapme) goto ERR_MALLOC; +int mapme_on_timeout(void *mapme_arg, int fd, void *data); - /* Internal state : set default values */ - memcpy(*mapme, &MapMeDefault, sizeof(MapMe)); - - (*mapme)->forwarder = forwarder; +mapme_t *mapme_create(void *forwarder) { + mapme_t *mapme = malloc(sizeof(mapme_t)); + if (!mapme) return NULL; - /* As there is no face table and no related events, we need to install hooks - * in various places in the forwarder, where both control commands and - * signalization are processed. - */ + /* Internal state : set default values */ + memcpy(mapme, &mapme_default, sizeof(mapme_t)); + memset(mapme->retx_array, 0, NUM_RETX_SLOT * NUM_RETX_ENTRIES); - return true; + mapme->forwarder = forwarder; + loop_timer_create(&mapme->timer, MAIN_LOOP, mapme, mapme_on_timeout, NULL); + if (!mapme->timer) { + ERROR("Error allocating mapme timer."); + free(mapme); + return NULL; + } -ERR_MALLOC: - return false; + return mapme; } -void mapme_free(MapMe *mapme) -{ - free(mapme); +void mapme_free(mapme_t *mapme) { + loop_event_free(mapme->timer); + free(mapme); } /****************************************************************************** * TFIB ******************************************************************************/ -#define INVALID_SEQ 0 -#define INIT_SEQ 0 - typedef struct { + // XXX We need magic number to know whether the TFIB was initialized or not + // ... or merge it inside the real data structure. + // NOTE: in VPP we reuse the nexthops in opposite order to gain room + // XXX need enough space in user_data !! uint32_t seq; - PARCHashMap *nexthops; + nexthops_t nexthops; // XXX useless shadow structure /* Update/Notification heuristic */ - Ticks lastAckedUpdate; -} MapMeTFIB; + Ticks last_acked_update; +} mapme_tfib_t; + +#define TFIB(FIB_ENTRY) ((mapme_tfib_t *)fib_entry_get_user_data(FIB_ENTRY)) + +static mapme_tfib_t *mapme_tfib_create() { + mapme_tfib_t *tfib; + tfib = malloc(sizeof(mapme_tfib_t)); + if (!tfib) return NULL; -static MapMeTFIB *mapmeTFIB_Create() { - MapMeTFIB *tfib; - tfib = malloc(sizeof(MapMeTFIB)); - if (!tfib) goto ERR_MALLOC; + // init tfib->seq = INIT_SEQ; - tfib->lastAckedUpdate = 0; - tfib->nexthops = parcHashMap_Create(); - if (!tfib->nexthops) goto ERR_HASHMAP; + tfib->last_acked_update = 0; + nexthops_set_len(&tfib->nexthops, 0); return tfib; - -ERR_HASHMAP: - free(tfib); -ERR_MALLOC: - return NULL; } -static PARCIterator *mapmeTFIB_CreateKeyIterator(const MapMeTFIB *tfib) { - /* - * Creating an iterator on an empty HashMap seems to raise an exception - * due to : - * parcTrapOutOfMemoryIf(state->listIterator == NULL, - * "Cannot create parcLinkedList_CreateIterator"); - * in : _parcHashMap_Init - * - * All buckets are empty, as they are after creation, and as they should be, - * but the error is triggered. - */ - if (parcHashMap_Size(tfib->nexthops) == 0) - return NULL; - return parcHashMap_CreateKeyIterator(tfib->nexthops); +void mapme_release_tfib(mapme_tfib_t **tfibPtr) { + mapme_tfib_t *tfib = *tfibPtr; + free(tfib); + tfibPtr = NULL; } -void mapmeTFIB_Release(const MapMe * mapme, MapMeTFIB **tfibPtr); - /** - * @function mapme_CreateTFIB - * @abstract Associate a new TFIB entry to a FIB entry. + * @function mapme_create_tfib + * @abstract Associate a new TFIB entry to a FIB entry. If a TFIB already exists + * the new one will be used * @param [in] - Pointer to the FIB entry. * @return Boolean indicating the success of the operation. */ -static void mapme_CreateTFIB(const MapMe * mapme, FibEntry *fibEntry) { - MapMeTFIB *tfib; - - /* Make sure we don't already have an associated TFIB entry */ - tfib = fibEntry_getUserData(fibEntry); - // assertNull(tfib); +static void mapme_create_tfib(const mapme_t *mapme, fib_entry_t *entry) { + mapme_tfib_t *tfib; - tfib = mapmeTFIB_Create(); - fibEntry_setUserData(fibEntry, mapme, tfib, (void (*)(const void*, void**))mapmeTFIB_Release); -} - -#define TFIB(fibEntry) ((MapMeTFIB *)fibEntry_getUserData(fibEntry)) - -static const PARCEventTimer *mapmeTFIB_Get(const MapMeTFIB *tfib, - unsigned conn_id) { - const PARCEventTimer *timer; - const PARCBuffer *buffer; - PARCUnsigned *cid = parcUnsigned_Create(conn_id); - buffer = parcHashMap_Get(tfib->nexthops, cid); - if (!buffer) { - timer = NULL; - goto END; - } - PARCByteArray *array = parcBuffer_Array(buffer); - timer = *((PARCEventTimer **)parcByteArray_Array(array)); -END: - parcUnsigned_Release(&cid); - return timer; + tfib = mapme_tfib_create(); + fib_entry_set_user_data(entry, tfib, (void (*)(void **))mapme_release_tfib); } -static void mapmeTFIB_Put(MapMeTFIB *tfib, unsigned conn_id, - const PARCEventTimer *timer) { - /* NOTE: Timers are not objects (the only class not being an object in - * fact), and as such, we cannot use them as values for the HashMap. - * Just like for unsigned we needed the PARC wrapper. - * There is no wrapper for pointers, so we use Arrays, which has an ubly - * syntax... - */ - PARCUnsigned *cid = parcUnsigned_Create(conn_id); - PARCBuffer *buffer = parcBuffer_CreateFromArray(&timer, sizeof(PARCEventTimer *)); - parcHashMap_Put(tfib->nexthops, cid, buffer); - - parcUnsigned_Release(&cid); - parcBuffer_Release(&buffer); -} - -static void mapmeTFIB_Remove(const MapMe * mapme, MapMeTFIB *tfib, unsigned conn_id) { - PARCUnsigned *cid = parcUnsigned_Create(conn_id); - - /* Release timer */ - const PARCBuffer *buffer = parcHashMap_Get(tfib->nexthops, cid); - if (buffer) { - PARCByteArray *array = parcBuffer_Array(buffer); - PARCEventTimer * timer = *((PARCEventTimer **)parcByteArray_Array(array)); - if (timer) { - parcEventTimer_Stop(timer); - Dispatcher *dispatcher = forwarder_GetDispatcher(mapme->forwarder); - dispatcher_DestroyTimerEvent(dispatcher, &timer); - } - } - - parcHashMap_Remove(tfib->nexthops, cid); - parcUnsigned_Release(&cid); -} - -void mapmeTFIB_Release(const MapMe * mapme, MapMeTFIB **tfibPtr) { - MapMeTFIB *tfib = *tfibPtr; - - /* Release all TFIB entries, incl. timers */ - PARCIterator *iterator = mapmeTFIB_CreateKeyIterator(tfib); - if (iterator) { - /* No iterator is created if the TFIB is empty */ - while (parcIterator_HasNext(iterator)) { - PARCUnsigned *cid = parcIterator_Next(iterator); - unsigned conn_id = parcUnsigned_GetUnsigned(cid); - mapmeTFIB_Remove(mapme, tfib, conn_id); - } - parcIterator_Release(&iterator); - } - - parcHashMap_Release(&tfib->nexthops); - free(tfib); - *tfibPtr = NULL; -} - - int hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix) { NameBitvector *bv = name_GetContentName(name); ip_prefix_t ip_prefix; @@ -263,500 +303,554 @@ int hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix) { return hicn_prefix_create_from_ip_prefix(&ip_prefix, prefix); } -static Message *mapme_createMessage(const MapMe *mapme, const Name *name, - mapme_params_t *params) { - Ticks now = forwarder_GetTicks(mapme->forwarder); - Logger *logger = forwarder_GetLogger(mapme->forwarder); - - INFO(mapme, "[MAP-Me] CreateMessage type=%d seq=%d", params->type, - params->seq); - - hicn_prefix_t prefix; - int rc = hicn_prefix_from_name(name, &prefix); - if (rc < 0) { - ERR(mapme, "[MAP-Me] Failed to create lib's name"); - goto ERR_NAME; - } - - - size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN - : HICN_MAPME_V4_HDRLEN; - uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size); - - INFO(mapme, "[MAP-Me] Creating MAP-Me packet"); - size_t len = hicn_mapme_create_packet(icmp_pkt, &prefix, params); - if (len == 0) { - ERR(mapme, "[MAP-Me] Failed to create mapme packet through lib"); - goto ERR_CREATE; - } - - // hicn_packet_dump(icmp_pkt, MAPME_HDRLEN); - - return message_CreateFromByteArray(NO_INGRESS, icmp_pkt, - MessagePacketType_Interest, now, logger); - -ERR_CREATE: - parcMemory_Deallocate(&icmp_pkt); -ERR_NAME: - return NULL; -} - -static Message *mapme_createAckMessage(const MapMe *mapme, - const uint8_t *msgBuffer, - const mapme_params_t *params) { - Ticks now = forwarder_GetTicks(mapme->forwarder); - Logger *logger = forwarder_GetLogger(mapme->forwarder); - - size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN - : HICN_MAPME_V4_HDRLEN; - uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size); - memcpy(icmp_pkt, msgBuffer, size); - - size_t len = hicn_mapme_create_ack(icmp_pkt, params); - if (len != size) { - ERR(mapme, "[MAP-Me] Failed to create mapme ack packet through lib"); - goto ERR; - } - - return message_CreateFromByteArray( - NO_INGRESS, icmp_pkt, MessagePacketType_ContentObject, now, logger); - -ERR: - parcMemory_Deallocate(&icmp_pkt); - return NULL; -} - -struct setFacePendingArgs { - const MapMe *mapme; - const Name *name; - FibEntry *fibEntry; - unsigned conn_id; - bool send; - bool is_producer; - uint32_t num_retx; -}; - -static bool mapme_setFacePending(const MapMe *mapme, const Name *name, - FibEntry *fibEntry, unsigned conn_id, - bool send, bool is_producer, bool clear_tfib, uint32_t num_retx); - -static void mapme_setFacePendingCallback(int fd, PARCEventType which_event, - void *data) { - struct setFacePendingArgs *args = (struct setFacePendingArgs *)data; - - parcAssertTrue(which_event & PARCEventType_Timeout, - "Event incorrect, expecting %X set, got %X", - PARCEventType_Timeout, which_event); - - INFO(args->mapme, "Timeout during retransmission. Re-sending"); - mapme_setFacePending(args->mapme, args->name, args->fibEntry, args->conn_id, - args->send, args->is_producer, false, args->num_retx); - free(args); -} - /** * @brief Update/Notification heuristic: * * NOTE: IN are currently disabled until the proper placeholder is agreed in the * interest header. */ -static hicn_mapme_type_t mapme_getTypeFromHeuristic(const MapMe *mapme, - FibEntry *fibEntry) { +static hicn_mapme_type_t mapme_get_type_from_heuristic(const mapme_t *mapme, + fib_entry_t *entry) { + if (fib_entry_has_local_nexthop(entry)) + /* We are a producer for this entry, send update */ + return UPDATE; + #if 0 /* interplay of IU/IN */ - if (TFIB(fibEntry)->lastAckedUpdate == 0) { + if (TFIB(fib_entry)->lastAckedUpdate == 0) { return UPDATE; } else { - Ticks interval = now - TFIB(fibEntry)->lastAckedUpdate; - return (T2NS(interval) > MS2NS(mapme->Tu)) ? UPDATE : NOTIFICATION; + Ticks interval = now - TFIB(fib_entry)->lastAckedUpdate; + return (T2NS(interval) > MS2NS(mapme->timescale)) ? UPDATE : NOTIFICATION; } #else /* Always send IU */ return UPDATE; #endif } -static bool mapme_setFacePending(const MapMe *mapme, const Name *name, - FibEntry *fibEntry, unsigned conn_id, - bool send, bool is_producer, bool clear_tfib, uint32_t num_retx) { - int rc; +/** + * + * Here nexthops is not necessarily FIB nexthops as we might advertise given FIB + * entries on various other connections. + */ +/* NOTE: if the face is pending an we receive an IN, maybe we should not cancel + * the timer + */ +// XXX Make sure this function is never called for Notifications +// XXX overall review notification code and integrate it in VPP +int mapme_send_to_nexthops(const mapme_t *mapme, fib_entry_t *entry, + const nexthops_t *nexthops) { + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return -1; + } - INFO(mapme, "[MAP-Me] SetFacePending connection=%d prefix=XX retx=%d", - conn_id, num_retx); + mapme_tfib_t *tfib = TFIB(entry); + if (tfib == NULL) { + mapme_create_tfib(mapme, entry); + tfib = TFIB(entry); + } - /* NOTE: if the face is pending an we receive an IN, maybe we should not - * cancel the timer - */ - Dispatcher *dispatcher = forwarder_GetDispatcher(mapme->forwarder); - PARCEventTimer *timer; + const Name *name = fib_entry_get_prefix(entry); - /* Safeguard during retransmissions */ - if (!TFIB(fibEntry)) - return true; + WITH_DEBUG({ + char *name_str = name_ToString(name); + DEBUG("sending IU/IN for name %s on all nexthops", name_str); + free(name_str); + }) - /* - * On the producer side, we have to clear the TFIB everytime we change the list - * of adjacencies, otherwise retransmissions will occur to preserve them. - */ - if (clear_tfib) { - /* - * It is likely we cannot iterator and remove elements from the hashmap at - * the same time, so we proceed in two steps - */ - if (parcHashMap_Size(TFIB(fibEntry)->nexthops) > 0) { + mapme_params_t params = { + .protocol = mapme->protocol, + .type = mapme_get_type_from_heuristic(mapme, entry), + .seq = tfib->seq, + }; - NumberSet * conns = numberSet_Create(); + hicn_prefix_t prefix; + if (hicn_prefix_from_name(name, &prefix) < 0) { + ERROR("Failed to create lib's name"); + return -1; + } - PARCIterator *it = parcHashMap_CreateKeyIterator(TFIB(fibEntry)->nexthops); - while (parcIterator_HasNext(it)) { - PARCUnsigned *cid = parcIterator_Next(it); - unsigned conn_id = parcUnsigned_GetUnsigned(cid); - numberSet_Add(conns, conn_id); - } - parcIterator_Release(&it); + uint8_t packet[MTU]; + size_t size = hicn_mapme_create_packet(packet, &prefix, ¶ms); + if (size <= 0) { + ERROR("Could not create MAP-Me packet"); + return -1; + } - for (size_t i = 0; i < numberSet_Length(conns); i++) { - unsigned conn_id = numberSet_GetItem(conns, i); - mapmeTFIB_Remove(mapme, TFIB(fibEntry), conn_id); - } + connection_table_t *table = forwarder_get_connection_table(mapme->forwarder); - numberSet_Release(&conns); - } - } + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + INFO("sending mapme packet on connection %d", nexthop); + const connection_t *conn = connection_table_get_by_id(table, nexthop); + connection_send_packet(conn, packet, size); + }); - // NOTE - // - at producer, send always true, we always send something reliably so we - // set the timer. - // - in the network, we always forward an IU, and never an IN - //if (is_producer || send) { - if (send) { - mapme_params_t params = { - .protocol = IPPROTO_IPV6, - .type = is_producer ? mapme_getTypeFromHeuristic(mapme, fibEntry) : UPDATE, - .seq = TFIB(fibEntry)->seq}; - Message *special_interest = mapme_createMessage(mapme, name, ¶ms); - if (!special_interest) { - INFO(mapme, "[MAP-Me] Could not create special interest"); - return false; - } + return 0; +} - const ConnectionTable *table = - forwarder_GetConnectionTable(mapme->forwarder); - const Connection *conn = - connectionTable_FindById((ConnectionTable *)table, conn_id); - if (conn) { - const Name * name = message_GetName(special_interest); - char * name_str = name_ToString(name); - INFO(mapme, "[MAP-Me] Sending MAP-Me packet name=%s seq=%d conn=%d", - name_str, params.seq, conn_id); - free(name_str); - connection_ReSend(conn, special_interest, NOT_A_NOTIFICATION); - } else { - INFO(mapme, "[MAP-Me] Stopped retransmissions as face went down"); - } - message_Release(&special_interest); - - if (num_retx < MAX_RETX) { - INFO(mapme, "[MAP-Me] - Scheduling retransmission\n"); - /* Schedule retransmission */ - struct setFacePendingArgs *args = - malloc(sizeof(struct setFacePendingArgs)); - if (!args) - goto ERR_MALLOC; - args->mapme = mapme; - args->name = name; - args->fibEntry = fibEntry; - args->conn_id = conn_id; - args->send = send; - args->is_producer = is_producer; - args->num_retx = num_retx + 1; - - timer = dispatcher_CreateTimer(dispatcher, TIMER_NO_REPEAT, - mapme_setFacePendingCallback, args); - struct timeval timeout = {mapme->retx / 1000, - (mapme->retx % 1000) * 1000}; - rc = parcEventTimer_Start(timer, &timeout); - if (rc < 0) { - free(args); - goto ERR_TIMER; - } - } else { - INFO(mapme, "[MAP-Me] Last retransmission."); - timer = NULL; - } - } else { - INFO(mapme, "[MAP-Me] - not forwarding as send is False"); - timer = NULL; +/** + * + * Here nexthops is not necessarily FIB nexthops as we might advertise given FIB + * entries on various other connections. + */ +void mapme_maybe_send_to_nexthops(const mapme_t *mapme, fib_entry_t *fib_entry, + const nexthops_t *nexthops) { + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return; } - mapmeTFIB_Remove(mapme, TFIB(fibEntry), conn_id); - mapmeTFIB_Put(TFIB(fibEntry), conn_id, timer); + /* Detect change */ + if (!fib_entry_nexthops_changed(fib_entry)) { + INFO("No change in nexthops"); + return; + } + fib_entry_set_prev_nexthops(fib_entry); + + mapme_send_to_nexthops(mapme, fib_entry, nexthops); +} + +/****************************************************************************** + * MAPME API + ******************************************************************************/ + +int mapme_set_all_adjacencies(const mapme_t *mapme, fib_entry_t *entry) { + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return -1; + } - return true; + /* Apply the policy of the fib_entry over all neighbours */ + nexthops_t new_nexthops = NEXTHOPS_EMPTY; + nexthops_t *nexthops = + fib_entry_get_available_nexthops(entry, ~0, &new_nexthops); -ERR_TIMER: - dispatcher_DestroyTimerEvent(dispatcher, &timer); -ERR_MALLOC: - return false; + /* We set force to true to avoid overriding the FIB cache */ + return mapme_set_adjacencies(mapme, entry, nexthops, true); } -/*------------------------------------------------------------------------------ - * Event handling - *----------------------------------------------------------------------------*/ +int mapme_set_adjacencies(const mapme_t *mapme, fib_entry_t *entry, + nexthops_t *nexthops, bool force) { + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return -1; + } -/* - * Return true if we have at least one local connection as next hop - */ -static bool mapme_hasLocalNextHops(const MapMe *mapme, - const FibEntry *fibEntry) { - const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry); - const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder); - - for (size_t j = 0; j < fibEntry_NexthopCount(fibEntry); j++) { - /* Retrieve Nexthop #j */ - unsigned conn_id = numberSet_GetItem(nexthops, j); - const Connection *conn = - connectionTable_FindById((ConnectionTable *)table, conn_id); - - /* Ignore non-local connections */ - if (!connection_IsLocal(conn)) continue; - /* We don't need to test against conn_added since we don't - * expect it to have any entry in the FIB */ + if (!fib_entry_has_local_nexthop(entry)) return -1; - return true; + /* Advertise prefix on all available next hops (if needed) */ + mapme_tfib_t *tfib = TFIB(entry); + if (tfib == NULL) { + mapme_create_tfib(mapme, entry); + tfib = TFIB(entry); } - return false; -} -void -mapme_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops) -{ - if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */ - mapme_CreateTFIB(mapme, fibEntry); - TFIB(fibEntry)->seq++; - - const Name *name = fibEntry_GetPrefix(fibEntry); - char *name_str = name_ToString(name); - bool clear_tfib = true; - - INFO(mapme, "[MAP-Me] Candidate next hops changed"); - for (size_t j = 0; j < numberSet_Length(nexthops); j++) { - unsigned nexthop_id = numberSet_GetItem(nexthops, j); - - /* We extract the nexthop type based on tags */ - const char * nexthop_type; - ConnectionTable * table = forwarder_GetConnectionTable(mapme->forwarder); - const Connection * conn = connectionTable_FindById(table, nexthop_id); - if (connection_HasTag(conn, POLICY_TAG_WIRED)) { - nexthop_type = "WIRED"; - } else if (connection_HasTag(conn, POLICY_TAG_WIFI)) { - nexthop_type = "WIFI"; - } else if (connection_HasTag(conn, POLICY_TAG_CELLULAR)) { - nexthop_type = "CELLULAR"; - } else { - nexthop_type = "UNKNOWN"; - } + nexthops_clear(&tfib->nexthops); + tfib->seq++; - INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d - %s (%s)", name_str, - nexthop_id, connection_GetInterfaceName(conn), nexthop_type); - mapme_setFacePending(mapme, name, fibEntry, nexthop_id, true, true, clear_tfib, 0); - clear_tfib = false; + if (force) { + mapme_send_to_nexthops(mapme, entry, nexthops); + return 0; } - INFO(mapme, "[MAP-Me] Done sending MAP-Me update"); - free(name_str); + + mapme_maybe_send_to_nexthops(mapme, entry, nexthops); + return 0; } +int mapme_update_adjacencies(const mapme_t *mapme, fib_entry_t *entry, + bool inc_iu_seq) { + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return -1; + } -void -mapme_maybe_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops) -{ - /* Detect change */ - NumberSet * previous_nexthops = fibEntry_GetPreviousNextHops(fibEntry); - if (numberSet_Equals(nexthops, previous_nexthops)) { - INFO(mapme, "[MAP-Me] No change in nexthops"); - return; + mapme_tfib_t *tfib = TFIB(entry); + if (tfib == NULL) { + mapme_create_tfib(mapme, entry); + tfib = TFIB(entry); } - fibEntry_SetPreviousNextHops(fibEntry, nexthops); - mapme_send_updates(mapme, fibEntry, nexthops); + if (inc_iu_seq) tfib->seq++; + + mapme_maybe_send_to_nexthops(mapme, entry, &tfib->nexthops); + return 0; } -void -mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry) -{ - /* - * Skip entries that do not correspond to a producer ( / have a locally - * served prefix / have no local connection as next hop) - */ - if (!mapme_hasLocalNextHops(mapme, fibEntry)) - return; +int mapme_send_to_nexthop(const mapme_t *mapme, fib_entry_t *entry, + unsigned nexthop) { + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return -1; + } - /* Apply the policy of the fibEntry over all neighbours */ - NumberSet * available_nexthops = fibEntry_GetAvailableNextHops(fibEntry, ~0); + nexthops_t nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, nexthop); - /* Advertise prefix on all available next hops (if needed) */ - mapme_send_updates(mapme, fibEntry, available_nexthops); - - numberSet_Release(&available_nexthops); + return mapme_send_to_nexthops(mapme, entry, &nexthops); } /* * Callback called everytime a new connection is created by the control protocol */ -void -mapme_onConnectionEvent(const MapMe *mapme, const Connection *conn_added, connection_event_t event) { +void mapme_on_connection_event(const mapme_t *mapme, + const connection_t *conn_added, + connection_event_t event) { + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return; + } + /* Does the priority change impacts the default route selection; if so, * advertise the prefix on this default route. If there are many default * routes, either v4 v6, or many connections as next hops on this default * route, then send to all. */ if (conn_added) { - if (connection_IsLocal(conn_added)) - return; + if (connection_is_local(conn_added)) return; - unsigned conn_added_id = connection_GetConnectionId(conn_added); - switch(event) { + unsigned conn_added_id = connection_get_id(conn_added); + switch (event) { case CONNECTION_EVENT_CREATE: - INFO(mapme, "[MAP-Me] Connection %d got created", conn_added_id); - break; + INFO("Connection %d got created", conn_added_id); + break; case CONNECTION_EVENT_DELETE: - INFO(mapme, "[MAP-Me] Connection %d got deleted", conn_added_id); - break; + INFO("Connection %d got deleted", conn_added_id); + break; case CONNECTION_EVENT_UPDATE: - INFO(mapme, "[MAP-Me] Connection %d got updated", conn_added_id); - break; + INFO("Connection %d got updated", conn_added_id); + break; case CONNECTION_EVENT_SET_UP: - INFO(mapme, "[MAP-Me] Connection %d went up", conn_added_id); - break; + INFO("Connection %d went up", conn_added_id); + break; case CONNECTION_EVENT_SET_DOWN: - INFO(mapme, "[MAP-Me] Connection %d went down", conn_added_id); - break; + INFO("Connection %d went down", conn_added_id); + break; case CONNECTION_EVENT_TAGS_CHANGED: - INFO(mapme, "[MAP-Me] Connection %d changed tags", conn_added_id); - break; + INFO("Connection %d changed tags", conn_added_id); + break; case CONNECTION_EVENT_PRIORITY_CHANGED: - INFO(mapme, "[MAP-Me] Connection %d changed priority to %d", - conn_added_id, connection_GetPriority(conn_added)); - break; + INFO("Connection %d changed priority to %d", conn_added_id, + connection_get_priority(conn_added)); + break; } } /* We need to send a MapMe update on the newly selected connections for - * each concerned fibEntry : connection is involved, or no more involved */ - FibEntryList *fiblist = forwarder_GetFibEntries(mapme->forwarder); - - /* Iterate a first time on the FIB to get the locally served prefixes */ - for (size_t i = 0; i < fibEntryList_Length(fiblist); i++) { - FibEntry *fibEntry = (FibEntry *)fibEntryList_Get(fiblist, i); - mapme_reconsiderFibEntry(mapme, fibEntry); - } - - fibEntryList_Destroy(&fiblist); - - INFO(mapme, "[MAP-Me] Done"); + * each concerned fib_entry : connection is involved, or no more involved */ + const fib_t *fib = forwarder_get_fib(mapme->forwarder); + fib_entry_t *entry; + fib_foreach_entry(fib, entry, { mapme_set_all_adjacencies(mapme, entry); }); } /*------------------------------------------------------------------------------ * Special Interest handling *----------------------------------------------------------------------------*/ -/** - * @discussion This function is way too long and should be cut out - */ -static bool mapme_onSpecialInterest(const MapMe *mapme, - const uint8_t *msgBuffer, - unsigned conn_in_id, hicn_prefix_t *prefix, - mapme_params_t *params) { - const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder); - /* The cast is needed since connectionTable_FindById miss the - * const qualifier for the first parameter */ - const Connection *conn_in = - connectionTable_FindById((ConnectionTable *)table, conn_in_id); - seq_t fibSeq, seq = params->seq; - bool send = (params->type == UPDATE); - bool rv; - - Name *name = name_CreateFromPacket(msgBuffer, MessagePacketType_Interest); - name_setLen(name, prefix->len); - char *name_str = name_ToString(name); - INFO(mapme, - "[MAP-Me] Ack'ed Special Interest on connection %d - prefix=%s type=XX " - "seq=%d", - conn_in_id, name_str, seq); - free(name_str); +// XXX this code has not been updated +#ifdef MAPME_ALLOW_NONEXISTING_FIB_ENTRY +int mapme_create_fib_entry(const mapme_t *mapme, const Name *name, + unsigned ingress_id) { + INFO(" - Re-creating FIB entry with next hop on connection %d", ingress_id); + /* + * This might happen for a node hosting a producer which has moved. + * Destroying the face has led to removing all corresponding FIB + * entries. In that case, we need to correctly restore the FIB entries. + */ + strategy_type fwdStrategy = LAST_STRATEGY_VALUE; /* - * Immediately send an acknowledgement back on the ingress connection - * We always ack, even duplicates. + * It might also be due to the announcement of a more specific prefix. In + * that case we need to perform a FIB lookup to find the next hops to which + * the message should be propagated. */ - Message *ack = mapme_createAckMessage(mapme, msgBuffer, params); - if (!ack) { - name_Release(&name); - return false; +#ifdef WITH_POLICY + entry = fib_entry_Create(name, fwdStrategy, mapme->forwarder); +#else + entry = fib_entry_Create(name, fwdStrategy); +#endif /* WITH_POLICY */ + fib_entry_t *lpm = fib_MatchName(fib, name); + fib_Add(fib, entry); + if (!lpm) { + TFIB(entry)->seq = seq; + fib_entry_AddNexthop(entry, ingress_id); + return true; } - rv = connection_ReSend(conn_in, ack, NOT_A_NOTIFICATION); - message_Release(&ack); - if (!rv) { - name_Release(&name); - return false; + /* + * We make a clone of the FIB entry (zero'ing the sequence number ?) with + * the more specific name, and proceed as usual. Worst case we clone the + * default route... + */ + const NumberSet *lpm_nexthops = fib_entry_nexthops_get(lpm); + for (size_t i = 0; i < numberSet_Length(lpm_nexthops); i++) { + fib_entry_AddNexthop(entry, numberSet_GetItem(lpm_nexthops, i)); } + return 0; +} +#endif - /* EPM on FIB */ - /* only the processor has access to the FIB */ - FIB *fib = forwarder_getFib(mapme->forwarder); +int mapme_on_timeout(void *mapme_arg, int fd, void *data) { + mapme_t *mapme = mapme_arg; + assert(mapme); + assert(!data); + /* Timeout occurred, we have to retransmit IUs for all pending + * prefixes having entries in TFIB + * + * timeouts are slotted + * | | | | + * + * ^ + * +- event occurred + * new face, wait for the second next + * (having two arrays and swapping cur and next) + * retx : put in next + */ + mapme->idle += 1; - FibEntry *fibEntry = fib_Contains(fib, name); + for (uint8_t pos = 0; pos < CURLEN; pos++) { + mapme_retx_t *retx = &CUR[pos]; - name_Release(&name); + if (!retx->entry) /* deleted entry */ + continue; - if (!fibEntry) { - INFO(mapme, "Ignored update with no FIB entry"); - return 0; -#if 0 - INFO(mapme, - "[MAP-Me] - Re-creating FIB entry with next hop on connection %d", - conn_in_id); - /* - * This might happen for a node hosting a producer which has moved. - * Destroying the face has led to removing all corresponding FIB - * entries. In that case, we need to correctly restore the FIB entries. - */ - strategy_type fwdStrategy = LAST_STRATEGY_VALUE; + mapme_tfib_t *tfib = TFIB(retx->entry); + assert(tfib); - /* - * It might also be due to the announcement of a more specific prefix. In - * that case we need to perform a FIB lookup to find the next hops to which - * the message should be propagated. + /* Re-send interest for all entries */ + mapme_update_adjacencies(mapme, retx->entry, false); + + retx->retx_count++; + /* If we exceed the numver of retransmittion it means that all tfib + * entries have seens at least HICN_PARAM_RETX_MAX of retransmission */ -#ifdef WITH_POLICY - fibEntry = fibEntry_Create(name, fwdStrategy, mapme->forwarder); -#else - fibEntry = fibEntry_Create(name, fwdStrategy); -#endif /* WITH_POLICY */ - FibEntry *lpm = fib_MatchName(fib, name); - mapme_CreateTFIB(mapme, fibEntry); - fib_Add(fib, fibEntry); - if (!lpm) { - TFIB(fibEntry)->seq = seq; - fibEntry_AddNexthop(fibEntry, conn_in_id); - return true; + if (retx->retx_count < MAPME_MAX_RETX) { + /* + * We did some retransmissions, so let's reschedule a check in the + * next slot + */ + NXT[NXTLEN++] = CUR[pos]; + mapme->idle = 0; + } else { + WARN("Maximum retransmissions exceeded"); + /* If we exceed the numver of retransmission it means that all TFIB + * entries have seens at least HICN_PARAM_RTX_MAX retransmissions. + * (Deletion might be slightly late). + * + * XXX document: when adding an entry in TFIB, we might exceed max + * retransmissions for previous entries that started retransmitting + * beforehand. + */ + nexthops_clear(&tfib->nexthops); } + } - /* - * We make a clone of the FIB entry (zero'ing the sequence number ?) with - * the more specific name, and proceed as usual. Worst case we clone the - * default route... - */ - const NumberSet *lpm_nexthops = fibEntry_GetNexthops(lpm); - for (size_t i = 0; i < numberSet_Length(lpm_nexthops); i++) { - fibEntry_AddNexthop(fibEntry, numberSet_GetItem(lpm_nexthops, i)); + /* Reset events in this slot and prepare for next one */ + CURLEN = 0; + mapme->cur = NEXT_SLOT(mapme->cur); + + /* After two empty slots, we disable the timer */ + if (mapme->idle > 1) { + loop_event_unregister(mapme->timer); + } + + return 0; +} + +static void mapme_on_event(mapme_t *mapme, mapme_event_t event, + fib_entry_t *entry, unsigned ingress_id) { + switch (event) { +#if 0 + case HICN_MAPME_EVENT_FACE_ADD: + { + /* + * A face has been added: + * - In case of a local app face, we need to advertise a new prefix + * - For another local face type, we need to advertise local + * prefixes and schedule retransmissions + */ + mapme_retx_t *retx_events = event_data; + for (uint8_t i = 0; i < vec_len (retx_events); i++) { + hicn_mapme_on_face_added(mapme, retx_events[i].dpo); + } + + if (mapme->timer_fd == -1) + mapme->timer_fd = loop_register_timer(MAIN_LOOP, + mapme->retx, mapme, mapme_on_timeout, NULL); + mapme->idle = 0; + break; + } + case HICN_MAPME_EVENT_FACE_DEL: + if (mapme->timer_fd == -1) + mapme->timer_fd = loop_register_timer(MAIN_LOOP, + DEFAULT_TIMEOUT, mapme, mapme_on_timeout, NULL); + mapme->idle = 0; + break; +#endif + + case MAPME_EVENT_NH_SET: + /* + * An hICN FIB entry has been modified. All operations so far + * have been procedded in the nodes. Here we need to track + * retransmissions upon timeout: we mark the FIB entry as pending in + * the second-to-next slot + */ + + /* + * XXX Move this in doc + * + * The FIB entry has a new next hop, and its TFIB section has: + * - eventually previous prev hops for which a IU with a + * lower seqno has been sent + * - the prev hops that have just been added. + * + * We don't distinguish any and just send an updated IU to all + * of them. The retransmission of the latest IU to all + * facilitates the matching of ACKs to a single seqno which is + * the one stored in the FIB. + * + * Since we retransmit to all prev hops, we can remove this + * (T)FIB entry for the check at the end of the current slot. + */ + + /* Mark FIB entry as pending for second-to-next slot */ + /* + * Transmit IU for all TFIB entries with latest seqno (we have + * at least one for sure!) + */ + mapme_update_adjacencies(mapme, entry, false); + + /* Delete entry_id from retransmissions in the current slot (if present) + * ... */ + /* ... and schedule it for next slot (if not already) */ + uint8_t j; + for (j = 0; j < CURLEN; j++) { + if (CUR[j].entry == entry) CUR[j].entry = NULL; /* sufficient */ + } + for (j = 0; j < NXTLEN; j++) { + if (NXT[j].entry == entry) break; + } + if (j == NXTLEN) /* not found */ + NXT[NXTLEN++] = (mapme_retx_t){ + .entry = entry, + .retx_count = 0, + }; + + if (!loop_timer_is_enabled(mapme->timer)) { + if (loop_timer_register(mapme->timer, mapme->retx) < 0) { + ERROR("Error setting mapme timer."); + break; + } + } + mapme->idle = 0; + break; + + case MAPME_EVENT_NH_ADD: + /* + * XXX move this in doc + * + * As per the description of states, this event should add the face + * to the list of next hops, and eventually remove it from TFIB. + * This corresponds to the multipath case. + * + * In all cases, we assume the propagation was already done when the first + * interest with the same sequence number was received, so we stop here + * No change in TFIB = no IU to send + * + * No change in timers. + */ + + // XXX useless +#if 0 + /* Add ingress face as next hop */ + idle = 0; +#endif + break; + + case MAPME_EVENT_PH_ADD: + /* Back-propagation, interesting even for IN (desync) */ + mapme_send_to_nexthop(mapme, entry, ingress_id); + + mapme->idle = 0; + if (!loop_timer_is_enabled(mapme->timer)) + loop_timer_register(mapme->timer, mapme->retx); + break; + + case MAPME_EVENT_PH_DEL: + /* Ack : remove an element from TFIB */ + break; + + case MAPME_EVENT_FACE_ADD: + case MAPME_EVENT_FACE_DEL: + + case MAPME_EVENT_UNDEFINED: + case MAPME_EVENT_N: + ERROR("Unexpected event"); + break; + } +} + +static void mapme_on_interest(mapme_t *mapme, msgbuf_t *msgbuf, + unsigned ingress_id, hicn_prefix_t *prefix, + mapme_params_t *params) { + connection_table_t *table = forwarder_get_connection_table(mapme->forwarder); + + /* The cast is needed since connectionTable_FindById miss the + * const qualifier for the first parameter */ + const connection_t *conn_in = connection_table_get_by_id(table, ingress_id); + + /* + * Immediately send an acknowledgement back on the ingress connection + * We always ack, even duplicates. Clone mgsbuf to avoid to overwrite the + * received message + */ + msgbuf_t *ack; + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(mapme->forwarder); + off_t interest_offset = msgbuf_pool_get_id(msgbuf_pool, (msgbuf_t *)msgbuf); + msgbuf_pool_clone(msgbuf_pool, &ack, interest_offset); + + uint8_t *ack_packet = msgbuf_get_packet(ack); + size_t size = hicn_mapme_create_ack(ack_packet, params); + if (connection_send_packet(conn_in, ack_packet, size) < 0) { + /* We accept the packet knowing we will get a retransmit */ + ERROR("Failed to send ACK packet"); + } + + msgbuf_pool_put(msgbuf_pool, ack); + + /* process received interest */ + uint8_t *packet = msgbuf_get_packet(msgbuf); + name_create_from_interest(packet, msgbuf_get_name(msgbuf)); + Name name = EMPTY_NAME; + name_Copy(msgbuf_get_name(msgbuf), &name); + name_setLen(&name, prefix->len); + + WITH_DEBUG({ + char *name_str = name_ToString(&name); + DEBUG("Ack'ed interest : connection=%d prefix=%s seq=%d", ingress_id, + name_str, params->seq); + free(name_str); + }); + + /* EPM on FIB */ + const fib_t *fib = forwarder_get_fib(mapme->forwarder); + fib_entry_t *entry = fib_contains(fib, &name); + if (!entry) { +#ifdef HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY + if (mapme_create_fib_entry(mapme, &name, ingress_id) < 0) { + ERROR("Failed to create FIB entry"); + return; } +#else + INFO("Ignored update with no FIB entry"); + return; #endif + } - } else if (!TFIB(fibEntry)) { - /* Create TFIB associated to FIB entry */ - INFO(mapme, - "[MAP-Me] - Creating TFIB entry with default sequence number"); - mapme_CreateTFIB(mapme, fibEntry); + mapme_tfib_t *tfib = TFIB(entry); + if (tfib == NULL) { + mapme_create_tfib(mapme, entry); + tfib = TFIB(entry); } /* @@ -767,102 +861,40 @@ static bool mapme_onSpecialInterest(const MapMe *mapme, * Detection: we receive a message initially sent by ourselves, ie a message * for which the prefix has a local next hop in the FIB. */ - if (mapme_hasLocalNextHops(mapme, fibEntry)) { - INFO(mapme, "[MAP-Me] - Received original interest... Update complete"); - return true; + // XXX NOT IN VPP ? + if (fib_entry_has_local_nexthop(entry)) { + INFO("Received original interest... Update complete"); + return; } - fibSeq = TFIB(fibEntry)->seq; - if (seq > fibSeq) { - INFO(mapme, - "[MAP-Me] - Higher sequence number than FIB %d, updating seq and " - "next hops", - fibSeq); - /* This has to be done first to allow processing SpecialInterestAck's */ - TFIB(fibEntry)->seq = seq; - - /* Reliably forward the IU on all prevHops */ - INFO(mapme, "[MAP-Me] - (1/3) processing prev hops"); - if (params->type == UPDATE) { - PARCIterator *iterator = mapmeTFIB_CreateKeyIterator(TFIB(fibEntry)); - if (iterator) { - /* No iterator is created if the TFIB is empty */ - while (parcIterator_HasNext(iterator)) { - PARCUnsigned *cid = parcIterator_Next(iterator); - unsigned conn_id = parcUnsigned_GetUnsigned(cid); - INFO(mapme, "[MAP-Me] - Re-sending IU to pending connection %d", - conn_id); - mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, - conn_id, false, false, false, 0); - } - parcIterator_Release(&iterator); - } - } - - /* nextHops -> prevHops - * - * We add to the list of pendingUpdates the current next hops, and - * eventually forward them an IU too. - * - * Exception: nextHops -> nextHops - * Because of retransmission issues, it is possible that a second interest - * (with same of higher sequence number) is receive from a next-hop - * interface. In that case, the face remains a next hop. - */ - const NumberSet *nexthops_old = fibEntry_GetNexthops(fibEntry); - - /* We make a copy to be able to send IU _after_ updating next hops */ - NumberSet *nexthops = numberSet_Create(); - numberSet_AddSet(nexthops, nexthops_old); + mapme_event_t event = MAPME_EVENT_UNDEFINED; + if (params->seq > tfib->seq) { + INFO( + "MAPME IU seq %d > fib_seq %d, updating seq and next hops, new " + "nexthop=%d", + params->seq, tfib->seq, ingress_id); + /* This has to be done first to allow processing ack */ + // XXX this should even be done before sending ack, as in VPP. + tfib->seq = params->seq; - /* We are considering : * -> nextHops - * - * If inFace was a previous hop, we need to cancel the timer and remove - * the entry. Also, the face should be added to next hops. + /* + * Move nexthops to TFIB... but ingress_id that lands in nexthops * - * Optimization : nextHops -> nextHops - * - no next hop to add - * - we know that inFace was not a previous hop since it was a next hop and - * this forms a partition. No need for a search - */ - - INFO(mapme, "[MAP-Me] - (3/3) next hops ~~> prev hops"); - mapmeTFIB_Remove(mapme, TFIB(fibEntry), conn_in_id); + * This could might optimized for situations where nothing changes, but + * this is very unlikely if not impossible... + * */ + unsigned prevhop; + nexthops_foreach(&entry->nexthops, prevhop, + { nexthops_add(&tfib->nexthops, prevhop); }); + nexthops_remove(&tfib->nexthops, ingress_id); + nexthops_clear(&entry->nexthops); + nexthops_add(&entry->nexthops, ingress_id); - /* Remove all next hops */ - for (size_t k = 0; k < numberSet_Length(nexthops); k++) { - unsigned conn_id = numberSet_GetItem(nexthops, k); - INFO(mapme, "[MAP-Me] - Replaced next hops by connection %d", conn_id); - fibEntry_RemoveNexthopByConnectionId(fibEntry, conn_id); - } - fibEntry_AddNexthop(fibEntry, conn_in_id); - - INFO(mapme, "[MAP-Me] - (2/3) processing next hops"); - bool complete = true; - for (size_t k = 0; k < numberSet_Length(nexthops); k++) { - unsigned conn_id = numberSet_GetItem(nexthops, k); - INFO(mapme, " - Next hop connection %d", conn_id); - if (conn_id == conn_in_id) { - INFO(mapme, " . Ignored this next hop since equal to ingress face"); - continue; - } + event = MAPME_EVENT_NH_SET; - INFO(mapme, "[MAP-Me] - Sending IU on current next hop connection %d", - conn_id); - mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, - conn_id, send, false, false, 0); - complete = false; - } + // XXX tell things are complete if we have no IU to send - /* - * The update is completed when the IU could not be sent to any - * other next hop. - */ - if (complete) INFO(mapme, "[MAP-Me] - Update completed !"); - - numberSet_Release(&nexthops); - - } else if (seq == fibSeq) { + } else if (params->seq == tfib->seq) { /* * Multipath, multihoming, multiple producers or duplicate interest * @@ -873,142 +905,83 @@ static bool mapme_onSpecialInterest(const MapMe *mapme, * producer and that we received back our own IU. In that case, we just * need to Ack and ignore it. */ -#if 0 - if (mapme_hasLocalNextHops(mapme, fibEntry)) { - INFO(mapme, "[MAP-Me] - Received original interest... Update complete"); - return true; - } -#endif + DEBUG("params.seq %d == fib_seq %d, adding nethop %d", params->seq, + tfib->seq, ingress_id); + + /* Move ingress to nexthops (and eventually remove it from TFIB) */ + nexthops_add(&entry->nexthops, ingress_id); + nexthops_remove(&tfib->nexthops, ingress_id); - INFO(mapme, "[MAP-Me] - Adding multipath next hop on connection %d", - conn_in_id); - fibEntry_AddNexthop(fibEntry, conn_in_id); + event = MAPME_EVENT_NH_ADD; - } else { // seq < fibSeq + } else { // params->seq < tfib->seq /* * Face is propagating outdated information, we can just * consider it as a prevHops. Send the special interest backwards with * the new sequence number to reconciliate this outdated part of the * arborescence. */ - INFO( - mapme, - "[MAP-Me] - Update interest %d -> %d sent backwards on connection %d", - seq, fibSeq, conn_in_id); - mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, - conn_in_id, send, false, false, 0); - } - - return true; -} - -void mapme_onSpecialInterestAck(const MapMe *mapme, const uint8_t *msgBuffer, - unsigned conn_in_id, hicn_prefix_t *prefix, - mapme_params_t *params) { - INFO(mapme, "[MAP-Me] Receive IU/IN Ack on connection %d", conn_in_id); + if (nexthops_contains(&entry->nexthops, ingress_id)) { + INFO("Ignored seq %d < fib_seq %d from current nexthop on face %d", + params->seq, tfib->seq, ingress_id); + return; + } else { + DEBUG("Received seq %d < fib_seq %d, sending backwards on face %d", + params->seq, tfib->seq, ingress_id); + nexthops_add(&tfib->nexthops, ingress_id); + } - Name * name = - name_CreateFromPacket(msgBuffer, MessagePacketType_ContentObject); - name_setLen((Name*) name, prefix->len); - char * name_str = name_ToString(name); - INFO(mapme, "[MAP-Me] Received ack for name prefix=%s seq=%d on conn id=%d", - name_str, params->seq, conn_in_id); - free(name_str); + event = MAPME_EVENT_PH_ADD; + } - FIB *fib = forwarder_getFib(mapme->forwarder); - FibEntry *fibEntry = fib_Contains(fib, name); + /* Don't trigger events for notification unless we need to send interests + * backwards */ + if ((params->type != UPDATE) && (event != MAPME_EVENT_PH_ADD)) return; - name_Release(&name); + mapme_on_event(mapme, event, entry, ingress_id); +} - if (!fibEntry) { +static void mapme_on_data(mapme_t *mapme, msgbuf_t *msgbuf, unsigned ingress_id, + hicn_prefix_t *prefix, mapme_params_t *params) { + INFO("Receive IU/IN Ack on connection %d", ingress_id); + + uint8_t *packet = msgbuf_get_packet(msgbuf); + name_create_from_data(packet, msgbuf_get_name(msgbuf)); + Name name = EMPTY_NAME; + name_Copy(msgbuf_get_name(msgbuf), &name); + name_setLen(&name, prefix->len); + + WITH_DEBUG({ + char *name_str = name_ToString(&name); + DEBUG("Received ack for name prefix=%s seq=%d on conn id=%d", name_str, + params->seq, ingress_id); + free(name_str); + }) + + const fib_t *fib = forwarder_get_fib(mapme->forwarder); + fib_entry_t *entry = fib_contains(fib, &name); + if (!entry) { + INFO("Ignored ACK with no corresponding FIB entry"); return; } - parcAssertNotNull(fibEntry, - "No corresponding FIB entry for name contained in IU Ack"); - - /* Test if the latest pending update has been ack'ed, otherwise just ignore */ - seq_t seq = params->seq; - if (seq != INVALID_SEQ) { - seq_t fibSeq = TFIB(fibEntry)->seq; - - if (seq < fibSeq) { - - /* If we receive an old ack: - * - either the connection is still a next hop and we have to ignore - * the ack until we receive a further update with higher seqno - * - or the connection is no more to be informed and the ack is - * sufficient and we can remove future retransmissions - */ - - INFO(mapme, - "[MAP-Me] - Ignored special interest Ack with seq=%u, expected %u", - seq, fibSeq); - return; - } - } + mapme_tfib_t *tfib = TFIB(entry); /* - * Ignore the Ack if no TFIB is present, or it has no corresponding entry - * with the ingress face. - * Note: previously, we were creating the TFIB entry + * As we always retransmit IU with the latest seq, we are not interested in + * ACKs with inferior seq */ - if (!TFIB(fibEntry)) { - INFO(mapme, "[MAP-Me] - Ignored ACK for prefix with no TFIB entry"); - return; - } - - PARCEventTimer *timer = - (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_in_id); - if (!timer) { - INFO(mapme, - "[MAP-Me] - Ignored ACK for prefix not having the Connection in " - "TFIB entry. Possible duplicate ?"); + if (params->seq < tfib->seq) { + INFO("Ignored ACK with seq %d < %d", params->seq, tfib->seq); return; } - /* Stop timer and remove entry from TFIB */ - mapmeTFIB_Remove(mapme, TFIB(fibEntry), conn_in_id); - - INFO(mapme, "[MAP-Me] - Removing TFIB entry for ack on connection %d", - conn_in_id); + nexthops_remove(&tfib->nexthops, ingress_id); + mapme_on_event(mapme, MAPME_EVENT_PH_DEL, entry, ingress_id); /* We need to update the timestamp only for IU Acks, not for IN Acks */ if (params->type == UPDATE_ACK) { - INFO(mapme, "[MAP-Me] - Updating LastAckedUpdate"); - TFIB(fibEntry)->lastAckedUpdate = forwarder_GetTicks(mapme->forwarder); - } -} - -/*----------------------------------------------------------------------------- - * Overloaded functions - *----------------------------------------------------------------------------*/ - -/* - * @abstract returns where to forward a normal interests(nexthops) defined by - * mapme, it also set the sequnence number properly if needed - */ - -/****************************************************************************** - * Public functions (exposed in the .h) - ******************************************************************************/ - -/* - * Returns true iif the message corresponds to a MAP-Me packet - */ -bool mapme_isMapMe(const uint8_t *packet) { - hicn_mapme_header_t * mapme = (hicn_mapme_header_t*)packet; - - switch(HICN_IP_VERSION(packet)) { - case 4: - if (mapme->v4.ip.protocol != IPPROTO_ICMP) - return false; - return HICN_IS_MAPME(mapme->v4.icmp_rd.type, mapme->v4.icmp_rd.code); - case 6: - if (mapme->v6.ip.nxt != IPPROTO_ICMPV6) - return false; - return HICN_IS_MAPME(mapme->v6.icmp_rd.type, mapme->v6.icmp_rd.code); - default: - return false; + INFO(" - Updating LastAckedUpdate"); + tfib->last_acked_update = ticks_now(); } } @@ -1023,25 +996,68 @@ bool mapme_isMapMe(const uint8_t *packet) { * MAP-Me (eg. ICMP packets) and return higher level messages that can be * processed by MAP-Me core. */ -void mapme_Process(const MapMe *mapme, const uint8_t *msgBuffer, - unsigned conn_id) { +void mapme_process(mapme_t *mapme, msgbuf_t *msgbuf) { + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return; + } + hicn_prefix_t prefix; mapme_params_t params; - hicn_mapme_parse_packet(msgBuffer, &prefix, ¶ms); + uint8_t *packet = msgbuf_get_packet(msgbuf); + unsigned conn_id = msgbuf_get_connection_id(msgbuf); + + int rc = hicn_mapme_parse_packet(packet, &prefix, ¶ms); + if (rc < 0) return; + + // XXX TYPE STR + DEBUG("Received interest type: %d seq: %d len:%d", params.type, params.seq, + prefix.len); + + // XXX RENAME TYPES switch (params.type) { case UPDATE: case NOTIFICATION: - mapme_onSpecialInterest(mapme, msgBuffer, conn_id, &prefix, ¶ms); + mapme_on_interest(mapme, msgbuf, conn_id, &prefix, ¶ms); break; case UPDATE_ACK: case NOTIFICATION_ACK: - mapme_onSpecialInterestAck(mapme, msgBuffer, conn_id, &prefix, ¶ms); + mapme_on_data(mapme, msgbuf, conn_id, &prefix, ¶ms); break; default: - ERR(mapme, "[MAP-Me] Unknown message"); + ERROR("Unknown message"); break; } } +/* + * Returns true iif the message corresponds to a MAP-Me packet + */ +bool mapme_match_packet(const uint8_t *packet) { + hicn_mapme_header_t *mapme = (hicn_mapme_header_t *)packet; + + switch (HICN_IP_VERSION(packet)) { + case 4: + if (mapme->v4.ip.protocol != IPPROTO_ICMP) return false; + return HICN_IS_MAPME(mapme->v4.icmp_rd.type, mapme->v4.icmp_rd.code); + case 6: + if (mapme->v6.ip.nxt != IPPROTO_ICMPV6) return false; + return HICN_IS_MAPME(mapme->v6.icmp_rd.type, mapme->v6.icmp_rd.code); + default: + return false; + } +} + +void mapme_set_enable(mapme_t *mapme, bool enable) { mapme->enabled = enable; } +void mapme_set_discovery(mapme_t *mapme, bool enable) { + mapme->discovery = enable; +} +void mapme_set_timescale(mapme_t *mapme, uint32_t time) { + mapme->timescale = time; +} +void mapme_set_retransmision(mapme_t *mapme, uint32_t time) { + mapme->retx = time; +} + #endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/core/mapme.h b/hicn-light/src/hicn/core/mapme.h index 72f8d536a..8c2ca477f 100644 --- a/hicn-light/src/hicn/core/mapme.h +++ b/hicn-light/src/hicn/core/mapme.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -26,29 +26,30 @@ #include <stdbool.h> #include <stdint.h> +#include <hicn/ctrl/hicn-light-ng.h> #include <hicn/hicn.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/connection.h> -#include <hicn/utils/commands.h> -struct mapme; -typedef struct mapme MapMe; +#include "connection.h" +#include "fib_entry.h" +#include "msgbuf.h" + +typedef struct mapme_s mapme_t; /** * @function mapme_create * @abstract Initializes MAP-Me state in the forwarder. * @return bool - Boolean informing about the success of MAP-Me initialization. */ -bool mapme_create(MapMe **mapme, Forwarder *Forwarder); +mapme_t *mapme_create(void *Forwarder); /** * @function mapme_free * @abstract Free MAP-Me state in the forwarder. */ -void mapme_free(MapMe *mapme); +void mapme_free(mapme_t *mapme); /** - * @function messageHandler_isMapMe + * @function messageHandler_is_mapme * @abstract Identifies MAP-Me messages * @discussion This function can be used by the forwarder to dispatch MAP-Me * message to the appropriate processing function. Ideally this would be @@ -56,48 +57,53 @@ void mapme_free(MapMe *mapme); * @param [in] msgBuffer - The buffer to match * @return A boolean indicating whether message is a MAP-Me control message. */ -bool mapme_isMapMe(const uint8_t *msgBuffer); +bool mapme_match_packet(const uint8_t *msgBuffer); /** - * @function mapme_handleMapMeMessage + * @function mapme_handlemapme_tMessage * @abstract Process a MAP-Me message. * @param [in] mapme - Pointer to the MAP-Me data structure. * @param [in] message - MAP-Me buffer * @param [in] conn_id - Ingress connection id */ -void mapme_Process(const MapMe *mapme, const uint8_t *msgBuffer, - unsigned conn_id); +void mapme_process(mapme_t *mapme, msgbuf_t *msgbuf); +/* mapme API */ /** * @function mapme_send_updates - * @abstract Trigger (if needed) the update for specified FIB entry and nexthops + * @abstract sends an update to all adjacencies. Used for face + * add/delete/changes (priority.tag) and policy * @param [in] mapme - Pointer to the MAP-Me data structure. - * @param [in] fibEntry - The FIB entry to consider - * @param [in] nexthops - NumberSet holding the next hops on which to send the - * update. + * @param [in] fib_entry - The FIB entry to consider */ -void mapme_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops); +int mapme_set_all_adjacencies(const mapme_t *mapme, fib_entry_t *entry); /** - * @function mapme_send_updates - * @abstract Trigger the update for specified FIB entry and nexthops, only if needed + * @function mapme_set_adjacencies + * @abstract sends an update to the specified adjacencies. Used by forwarding + * strategies * @param [in] mapme - Pointer to the MAP-Me data structure. - * @param [in] fibEntry - The FIB entry to consider - * @param [in] nexthops - NumberSet holding the next hops on which to send the - * update. + * @param [in] fib_entry - The FIB entry to consider + * @param [in] nexthops - next hops on which to send the update. */ -void mapme_maybe_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops); +int mapme_set_adjacencies(const mapme_t *mapme, fib_entry_t *entry, + nexthops_t *nexthops, bool force); /** - * @function mapme_reconsiderFibEntry - * @abstract Process a fib entry for changes that might trigger new updates + * @function mapme_update_adjacencies + * @abstract sends an update on previuos adjacencies. Used for IU forwarding, + * NAT and timeouts + * strategies * @param [in] mapme - Pointer to the MAP-Me data structure. - * @param [in] fibEntry - The FIB entry to consider + * @param [in] fib_entry - The FIB entry to consider + * @param [in] inc_iu_seq - if true, the seq number of the tfib/mapme iu will be + * increased by one */ -void mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry); +int mapme_update_adjacencies(const mapme_t *mapme, fib_entry_t *entry, + bool inc_iu_seq); /** - * @function mapme_onConnectionEvent + * @function mapme_on_connection_event * @abstract Callback following the addition of the face though the control * protocol. * @discussion This callback triggers the sending of control packets by MAP-Me. @@ -105,19 +111,21 @@ void mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry); * @param [in] conn - The newly added connection. * @param [in] event - Connection event */ -void mapme_onConnectionEvent(const MapMe *mapme, const Connection *conn, connection_event_t event); +void mapme_on_connection_event(const mapme_t *mapme, const connection_t *conn, + connection_event_t event); /** - * @function mapme_getNextHops + * @function mapme_get_nexthops * @abstract return the nexthops to forward interests defined by mapme, it * covers also the case where local discovery mechanisms are trriggered. */ -NumberSet *mapme_getNextHops(const MapMe *mapme, FibEntry *fibEntry, - const Message *interest); - -hicn_mapme_type_t mapme_PktType_To_LibHicnPktType(MessagePacketType type); +// nexthops_t * mapme_get_nexthops(const mapme_t *mapme, fib_entry_t *fib_entry, +// const msgbuf_t *interest); -MessagePacketType mapme_LibHicnPktType_To_PktType(hicn_mapme_type_t type); +void mapme_set_enable(mapme_t *mapme, bool enable); +void mapme_set_discovery(mapme_t *mapme, bool enable); +void mapme_set_timescale(mapme_t *mapme, uint32_t time); +void mapme_set_retransmision(mapme_t *mapme, uint32_t time); #endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/core/message.c b/hicn-light/src/hicn/core/message.c deleted file mode 100644 index c28938320..000000000 --- a/hicn-light/src/hicn/core/message.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <string.h> - -#include <hicn/core/forwarder.h> -#include <hicn/core/message.h> -#include <hicn/core/wldr.h> - -#include <hicn/core/messageHandler.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> -#include <hicn/core/messagePacketType.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_EventBuffer.h> - -struct message { - Logger *logger; - - Ticks receiveTime; - unsigned ingressConnectionId; - - Name *name; - - uint8_t *messageHead; - - unsigned length; - - uint8_t packetType; - - unsigned refcount; -}; - -Message *message_Acquire(const Message *message) { - Message *copy = (Message *)message; - copy->refcount++; - return copy; -} - -Message *message_CreateFromEventBuffer(PARCEventBuffer *data, size_t dataLength, - unsigned ingressConnectionId, - Ticks receiveTime, Logger *logger) { - // used by applications, we can get only interest or data packets - Message *message = parcMemory_AllocateAndClear(sizeof(Message)); - parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Message)); - - message->logger = logger_Acquire(logger); - message->receiveTime = receiveTime; - message->ingressConnectionId = ingressConnectionId; - message->length = (unsigned int)dataLength; - - message->messageHead = parcMemory_AllocateAndClear(dataLength); - parcAssertNotNull(message->messageHead, - "parcMemory_AllocateAndClear(%zu) returned NULL", - dataLength); - - // copy the data because *data is destroyed in the connection. - int res = parcEventBuffer_Read(data, message->messageHead, dataLength); - if (res == -1) { - return NULL; - } - - if (messageHandler_IsInterest(message->messageHead)) { - message->packetType = MessagePacketType_Interest; - } else if (messageHandler_IsData(message->messageHead)) { - message->packetType = MessagePacketType_ContentObject; - } else { - printf("Got a packet that is not a data nor an interest, drop it!\n"); - return NULL; - } - message->name = - name_CreateFromPacket(message->messageHead, message->packetType); - - message->refcount = 1; - - return message; -} - -Message *message_CreateFromByteArray(unsigned connid, uint8_t *pckt, - MessagePacketType type, Ticks receiveTime, - Logger *logger) { - Message *message = parcMemory_AllocateAndClear(sizeof(Message)); - parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Message)); - - message->logger = logger_Acquire(logger); - message->receiveTime = receiveTime; - message->ingressConnectionId = connid; - message->messageHead = pckt; - message->length = messageHandler_GetTotalPacketLength(pckt); - message->packetType = type; - - if (messageHandler_IsWldrNotification(pckt)) { - message->name = NULL; - } else { - message->name = - name_CreateFromPacket(message->messageHead, message->packetType); - } - - message->refcount = 1; - - return message; -} - -void message_Release(Message **messagePtr) { - parcAssertNotNull(messagePtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*messagePtr, - "Parameter must dereference to non-null pointer"); - - Message *message = *messagePtr; - parcAssertTrue( - message->refcount > 0, - "Invalid state: message_Release called on message with 0 references %p", - (void *)message); - - message->refcount--; - if (message->refcount == 0) { - if (logger_IsLoggable(message->logger, LoggerFacility_Message, - PARCLogLevel_Debug)) { - logger_Log(message->logger, LoggerFacility_Message, PARCLogLevel_Debug, - __func__, "Message %p destroyed", (void *)message); - } - - logger_Release(&message->logger); - if (message->name != NULL) name_Release(&message->name); - parcMemory_Deallocate((void **)&message->messageHead); - parcMemory_Deallocate((void **)&message); - } - *messagePtr = NULL; -} - -bool message_Write(PARCEventQueue *parcEventQueue, const Message *message) { - parcAssertNotNull(message, "Message parameter must be non-null"); - parcAssertNotNull(parcEventQueue, "Buffer parameter must be non-null"); - - return parcEventQueue_Write(parcEventQueue, message->messageHead, - message_Length(message)); -} - -size_t message_Length(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return message->length; -} - -bool message_HasWldr(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return messageHandler_HasWldr(message->messageHead); -} - -bool message_IsWldrNotification(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return messageHandler_IsWldrNotification(message->messageHead); -} - -void message_ResetWldrLabel(Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - messageHandler_ResetWldrLabel(message->messageHead); -} - -unsigned message_GetWldrLabel(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return messageHandler_GetWldrLabel(message->messageHead); -} - -unsigned message_GetWldrExpectedLabel(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return messageHandler_GetExpectedWldrLabel(message->messageHead); -} - -unsigned message_GetWldrLastReceived(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return messageHandler_GetWldrLastReceived(message->messageHead); -} - -void message_SetWldrLabel(Message *message, uint16_t label) { - parcAssertNotNull(message, "Parameter must be non-null"); - messageHandler_SetWldrLabel(message->messageHead, label); -} - -Message *message_CreateWldrNotification(Message *original, uint16_t expected, - uint16_t lastReceived) { - parcAssertNotNull(original, "Parameter original must be non-null"); - Message *message = parcMemory_AllocateAndClear(sizeof(Message)); - parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Message)); - message->receiveTime = original->receiveTime; - message->ingressConnectionId = original->ingressConnectionId; - message->refcount = 1; - message->logger = logger_Acquire(original->logger); - - message->length = (unsigned int)messageHandler_GetICMPPacketSize( - messageHandler_GetIPPacketType(original->messageHead)); - message->messageHead = parcMemory_AllocateAndClear(message->length); - parcAssertNotNull(message->messageHead, - "parcMemory_AllocateAndClear returned NULL"); - - message->packetType = MessagePacketType_WldrNotification; - message->name = NULL; // nobody will use the name in a notification packet, - // so we can simply set it to NULL - - // set notification stuff. - messageHandler_SetWldrNotification( - message->messageHead, original->messageHead, expected, lastReceived); - return message; -} - -unsigned message_GetIngressConnectionId(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return message->ingressConnectionId; -} - -void message_SetIngressConnectionId(Message *message, unsigned conn) { - parcAssertNotNull(message, "Parameter must be non-null"); - message->ingressConnectionId = conn; -} - -Ticks message_GetReceiveTime(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return message->receiveTime; -} - -uint32_t message_GetPathLabel(const Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - return messageHandler_GetPathLabel(message->messageHead); -} - -void message_SetPathLabel(Message *message, uint32_t label) { - parcAssertNotNull(message, "Parameter must be non-null"); - messageHandler_SetPathLabel(message->messageHead, - messageHandler_GetPathLabel(message->messageHead), label); -} - -void message_UpdatePathLabel(Message *message, uint8_t outFace) { - parcAssertNotNull(message, "Parameter must be non-null"); - messageHandler_UpdatePathLabel(message->messageHead, outFace); -} - -void message_ResetPathLabel(Message *message) { - parcAssertNotNull(message, "Parameter must be non-null"); - messageHandler_ResetPathLabel(message->messageHead); -} - -MessagePacketType message_GetType(const Message *message) { - parcAssertNotNull(message, "Parameter message must be non-null"); - return message->packetType; -} - -Name *message_GetName(const Message *message) { - parcAssertNotNull(message, "Parameter message must be non-null"); - return message->name; -} - -bool message_HasInterestLifetime(const Message *message) { - parcAssertNotNull(message, "Parameter message must be non-null"); - return messageHandler_HasInterestLifetime(message->messageHead); -} - -uint64_t message_GetInterestLifetimeTicks(const Message *message) { - parcAssertNotNull(message, "Parameter message must be non-null"); - uint64_t lifetime = messageHandler_GetInterestLifetime(message->messageHead); - return forwarder_NanosToTicks(lifetime * 1000000ULL); -} - -bool message_HasContentExpiryTime(const Message *message) { - parcAssertNotNull(message, "Parameter message must be non-null"); - return messageHandler_HasContentExpiryTime(message->messageHead); -} - -uint64_t message_GetContentExpiryTimeTicks(const Message *message) { - parcAssertNotNull(message, "Parameter message must be non-null"); - uint64_t expire = messageHandler_GetContentExpiryTime(message->messageHead); - if(expire == 0) - return message->receiveTime; - return message->receiveTime + forwarder_NanosToTicks(expire * 1000000ULL); -} - -const uint8_t *message_FixedHeader(const Message *message) { - parcAssertNotNull(message, "Parameter message must be non-null"); - return message->messageHead; -} diff --git a/hicn-light/src/hicn/core/message.h b/hicn-light/src/hicn/core/message.h deleted file mode 100644 index e77dab2b5..000000000 --- a/hicn-light/src/hicn/core/message.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file message.h - * @brief Message is the unit of forwarding, i.e. the packets being switched - * - */ -#ifndef message_h -#define message_h - -#include <hicn/hicn-light/config.h> -#include <hicn/core/logger.h> -#include <hicn/core/messagePacketType.h> -#include <hicn/core/streamBuffer.h> - -#include <hicn/core/name.h> - -#include <parc/algol/parc_EventBuffer.h> -#include <parc/algol/parc_EventQueue.h> - -#include <hicn/utils/address.h> - -#include <hicn/core/ticks.h> - -struct message; -typedef struct message Message; - -/** - * @function message_CreateFromBuffer - * @abstract Takes ownership of the input buffer, which comprises one complete - * message - */ - -Message *message_CreateFromEventBuffer(PARCEventBuffer *data, size_t dataLength, - unsigned ingressConnectionId, - Ticks receiveTime, Logger *logger); - -/** - * @function message_CreateFromByteArray - * @abstract create a message from a byte array - */ - -Message *message_CreateFromByteArray(unsigned connid, uint8_t *pckt, - MessagePacketType type, Ticks receiveTime, - Logger *logger); - -/** - * @function message_Copy - * @abstract Get a reference counted copy - */ - -Message *message_Acquire(const Message *message); - -/** - * Releases the message and frees the memory - */ -void message_Release(Message **messagePtr); - -/** - * Writes the message to the queue - */ - -bool message_Write(PARCEventQueue *parcEventQueue, const Message *message); - -/** - * Returns the total byte length of the message - */ -size_t message_Length(const Message *message); - -bool message_HasWldr(const Message *message); - -bool message_IsWldrNotification(const Message *message); - -void message_ResetWldrLabel(Message *message); - -unsigned message_GetWldrLabel(const Message *message); - -unsigned message_GetWldrExpectedLabel(const Message *message); - -unsigned message_GetWldrLastReceived(const Message *message); - -void message_SetWldrLabel(Message *message, uint16_t label); - -Message *message_CreateWldrNotification(Message *original, uint16_t expected, - uint16_t lastReceived); -/** - * Returns the connection id of the packet input - */ -unsigned message_GetIngressConnectionId(const Message *message); - -void message_SetIngressConnectionId(Message *message, unsigned conn); - -/** - * Returns the receive time (in router ticks) of the message - */ -Ticks message_GetReceiveTime(const Message *message); - -/** - * Returns the PacketType - */ -MessagePacketType message_GetType(const Message *message); - -uint32_t message_GetPathLabel(const Message *message); -void message_SetPathLabel(Message *message, uint32_t label); -void message_UpdatePathLabel(Message *message, uint8_t outFace); -void message_ResetPathLabel(Message *message); - -// =========================================================== -// Accessors used to index and compare messages - -/** - * @function message_GetName - * @abstract The name in the message - * @discussion - * The name of the Interest or Content Object. If the caller will store the - * name, he should make a reference counted copy. - * @return The name as stored in the message object. - */ - -Name *message_GetName(const Message *message); - -/** - * Determines if the message has an Interest Lifetime parameter - * - * @param [in] message An allocated and parsed Message - * - * @retval true If an Intrerest Lifetime field exists - * @retval false If no Interest Lifetime exists - */ - -bool message_HasInterestLifetime(const Message *message); - -/** - * Returns the Interest lifetime in hicn-light Ticks - * - * the interest expires after now + returned ticks - * - * @param [in] message An allocated and parsed Message - * - * @retval integer Lifetime in forwarder Ticks - * - */ - -uint64_t message_GetInterestLifetimeTicks(const Message *message); - -/** - * checks if the expiry time is set inside the content object - */ -bool message_HasContentExpiryTime(const Message *message); - -/** - * returns the moment (in hicn-light ticks) when the content object will expire - */ -uint64_t message_GetContentExpiryTimeTicks(const Message *message); - -/** - * Returns a pointer to the beginning of the FixedHeader - * - * @param [in] message An allocated and parsed Message - * - * @return non-null The fixed header memory - * @return null No fixed header or an error - */ - -const uint8_t *message_FixedHeader(const Message *message); - -#endif // message_h diff --git a/hicn-light/src/hicn/core/messageHandler.h b/hicn-light/src/hicn/core/messageHandler.h index b41c9a7f0..fe26d0579 100644 --- a/hicn-light/src/hicn/core/messageHandler.h +++ b/hicn-light/src/hicn/core/messageHandler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,16 +13,17 @@ * limitations under the License. */ -#ifndef messageHandler -#define messageHandler +#ifndef HICNLIGHT_MESSAGE_HANDLER_H +#define HICNLIGHT_MESSAGE_HANDLER_H #include <stdlib.h> #ifndef _WIN32 -#include <unistd.h> // close -#endif +#include <unistd.h> // close +#endif /* _WIN32 */ #include <hicn/hicn.h> -#include <hicn/core/messagePacketType.h> + +//#include <hicn/core/connection_table.h> #define H(packet) ((hicn_header_t *)packet) #define H6(packet) (H(packet)->v6.ip) @@ -49,21 +50,21 @@ #define CONTROL_PORT 9695 #define HTTP_PORT 8080 +#define MIN_PROBE_SUFFIX 0xefffffff +#define MAX_PROBE_SUFFIX 0xffffffff - 1 + +// XXX Hardcoded packet format HF_INET6_TCP + #define IPV6_DEFAULT_VERSION 6 #define IPV6_DEFAULT_TRAFFIC_CLASS 0 #define IPV6_DEFAULT_FLOW_LABEL 0 -#define expected_lbl wldr_notification_lbl.expected_lbl -#define received_lbl wldr_notification_lbl.received_lbl +//#include <hicn/core/forwarder.h> -#include <hicn/core/forwarder.h> - -#ifdef WITH_MAPME -#include <hicn/core/mapme.h> -#include <hicn/socket/api.h> -#endif /* WITH_MAPME */ - -#define CONNECTION_ID_UNDEFINED -1 +//#ifdef WITH_MAPME +//#include <hicn/core/mapme.h> +//#include <hicn/socket/api.h> +//#endif /* WITH_MAPME */ #define BFD_PORT 3784 @@ -157,6 +158,7 @@ static inline size_t messageHandler_GetIPHeaderLength(unsigned ipVersion) { return 0; } +#if 0 static inline bool messageHandler_IsValidHicnPacket(const uint8_t *message) { uint8_t version = messageHandler_GetIPPacketType(message); if (version == IPv6_TYPE || version == IPv4_TYPE) { @@ -164,6 +166,7 @@ static inline bool messageHandler_IsValidHicnPacket(const uint8_t *message) { } return false; } +#endif static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) { switch (messageHandler_GetIPPacketType(message)) { @@ -176,155 +179,6 @@ static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) { } } -/* Forward declarations */ -static inline void * messageHandler_GetSource(const uint8_t *message); -static inline void *messageHandler_GetDestination(const uint8_t *message); - -static const -AddressPair * -_createRecvAddressPairFromPacket(const uint8_t *msgBuffer) { - Address *packetSrcAddr = NULL; /* This one is in the packet */ - Address *localAddr = NULL; /* This one is to be determined */ - - if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) { - struct sockaddr_in6 addr_in6; - addr_in6.sin6_family = AF_INET6; - addr_in6.sin6_port = htons(1234); - addr_in6.sin6_flowinfo = 0; - addr_in6.sin6_scope_id = 0; - memcpy(&addr_in6.sin6_addr, - (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16); - packetSrcAddr = addressCreateFromInet6(&addr_in6); - - /* We now determine the local address used to reach the packet src address */ - int sock = (int)socket (AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) - goto ERR; - - struct sockaddr_in6 remote, local; - memset(&remote, 0, sizeof(remote)); - remote.sin6_family = AF_INET6; - remote.sin6_addr = addr_in6.sin6_addr; - remote.sin6_port = htons(1234); - - socklen_t locallen = sizeof(local); - if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1) - goto ERR; - if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1) - goto ERR; - - local.sin6_port = htons(1234); - localAddr = addressCreateFromInet6(&local); - - close(sock); - - } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) { - struct sockaddr_in addr_in; - addr_in.sin_family = AF_INET; - addr_in.sin_port = htons(1234); - memcpy(&addr_in.sin_addr, - (struct in_addr *)messageHandler_GetSource(msgBuffer), 4); - packetSrcAddr = addressCreateFromInet(&addr_in); - - /* We now determine the local address used to reach the packet src address */ - - int sock = (int)socket (AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - perror("Socket error"); - goto ERR; - } - - struct sockaddr_in remote, local; - memset(&remote, 0, sizeof(remote)); - remote.sin_family = AF_INET; - remote.sin_addr = addr_in.sin_addr; - remote.sin_port = htons(1234); - - socklen_t locallen = sizeof(local); - if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1) - goto ERR; - if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1) - goto ERR; - - local.sin_port = htons(1234); - localAddr = addressCreateFromInet(&local); - - close(sock); - } - /* As this is a receive pair, we swap src and dst */ - return addressPair_Create(localAddr, packetSrcAddr); - -ERR: - perror("Socket error"); - return NULL; -} - -/* Main hook handler */ - -/** - * \brief Handle incoming messages - * \param [in] forwarder - Reference to the Forwarder instance - * \param [in] packet - Packet buffer - * \param [in] conn_id - A hint on the connection ID on which the packet - * was received - * \return Flag indicating whether the packet matched a hook and was - * (successfully or not) processed. - */ -static inline bool messageHandler_handleHooks(Forwarder * forwarder, - const uint8_t * packet, ListenerOps * listener, int fd, AddressPair * pair) -{ - bool is_matched = false; - - /* BEGIN Match */ - -#ifdef WITH_MAPME - bool is_mapme = mapme_isMapMe(packet); - is_matched |= is_mapme; -#endif /* WITH_MAPME */ - - /* ... */ - - /* END Match */ - - if (!is_matched) - return false; - - /* - * Find existing connection or create a new one (we assume all processing - * requires a valid connection. - */ - - if (!pair) { - /* The hICN listener does not provide any address pair while UDP does */ - const AddressPair * pair = _createRecvAddressPairFromPacket(packet); - if (!pair) - return false; - } - - /* Find connection and eventually create it */ - const Connection * conn = connectionTable_FindByAddressPair( - forwarder_GetConnectionTable(forwarder), pair); - unsigned conn_id; - if (conn == NULL) { - conn_id = listener->createConnection(listener, fd, pair); - } else { - conn_id = connection_GetConnectionId(conn); - } - - /* BEGIN Process */ - -#ifdef WITH_MAPME - if (mapme_isMapMe(packet)) - forwarder_ProcessMapMe(forwarder, packet, conn_id); -#endif /* WITH_MAPME */ - - /* ... */ - - /* END Process */ - parcMemory_Deallocate((void **)&packet); - return true; -} - static inline bool messageHandler_IsTCP(const uint8_t *message) { if (messageHandler_NextHeaderType(message) != IPPROTO_TCP) return false; return true; @@ -432,7 +286,8 @@ static inline uint16_t messageHandler_GetExpectedWldrLabel( return 0; } - return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->expected_lbl); + return ntohs( + ((_icmp_wldr_header_t *)icmp_ptr)->wldr_notification_lbl.expected_lbl); } static inline uint16_t messageHandler_GetWldrLastReceived( @@ -449,7 +304,8 @@ static inline uint16_t messageHandler_GetWldrLastReceived( return 0; } - return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->received_lbl); + return ntohs( + ((_icmp_wldr_header_t *)icmp_ptr)->wldr_notification_lbl.received_lbl); } static inline uint16_t messageHandler_GetWldrLabel(const uint8_t *message) { @@ -524,6 +380,7 @@ static inline void messageHandler_UpdatePathLabel(uint8_t *message, uint32_t pl_new_32bit = (uint32_t)((((pl_old_8bit << 1) | (pl_old_8bit >> 7)) ^ outFace) << 24UL); + // XXX path label should be 8 bits now ? messageHandler_SetPathLabel(message, pl_old_32bit, pl_new_32bit); } @@ -531,7 +388,7 @@ static inline void messageHandler_ResetPathLabel(uint8_t *message) { messageHandler_SetPathLabel(message, messageHandler_GetPathLabel(message), 0); } -static inline uint16_t messageHandler_GetInterestLifetime( +static inline uint32_t messageHandler_GetInterestLifetime( const uint8_t *message) { if (!messageHandler_IsTCP(message)) return 0; @@ -541,6 +398,24 @@ static inline uint16_t messageHandler_GetInterestLifetime( return lifetime; } +static inline bool messageHandler_SetInterestLifetime(uint8_t *message, + u32 lifetime) { + if (!messageHandler_IsTCP(message)) return false; + + int res = hicn_interest_set_lifetime((hicn_header_t *)message, lifetime); + if (res < 0) return false; + return true; +} + +static inline bool messageHandler_SetDataExpiryTime(uint8_t *message, + u32 lifetime) { + if (!messageHandler_IsTCP(message)) return false; + + int res = hicn_data_set_expiry_time((hicn_header_t *)message, lifetime); + if (res < 0) return false; + return true; +} + static inline bool messageHandler_HasInterestLifetime(const uint8_t *message) { if (!messageHandler_IsTCP(message)) return false; @@ -650,7 +525,7 @@ static inline void messageHandler_SetWldrNotification(uint8_t *notification, case IPv6_TYPE: { *h = (hicn_header_t){.v6 = { .ip = - { + (_ipv6_header_t){ .version_class_flow = htonl( (IPV6_DEFAULT_VERSION << 28) | (IPV6_DEFAULT_TRAFFIC_CLASS << 20) | @@ -659,13 +534,17 @@ static inline void messageHandler_SetWldrNotification(uint8_t *notification, .nxt = IPPROTO_ICMPV6, .hlim = 5, }, + /* .wldr = { .type = ICMP_WLDR_TYPE, .code = ICMP_WLDR_CODE, - .expected_lbl = htons(expected), - .received_lbl = htons(received), - }, + .wldr_notification_lbl = + { + .expected_lbl = htons(expected), + .received_lbl = htons(received), + }, + },*/ }}; messageHandler_SetSource_IPv6( notification, @@ -682,56 +561,78 @@ static inline void messageHandler_SetWldrNotification(uint8_t *notification, } } -static inline uint8_t * messageHandler_CreateProbePacket(hicn_format_t format, - uint32_t probe_lifetime){ +static inline void messageHandler_ModifySuffix(uint8_t *packet, + uint32_t new_suffix) { + hicn_format_t format; + hicn_name_t name; + hicn_packet_get_format((hicn_header_t *)packet, &format); + hicn_interest_get_name(format, (hicn_header_t *)packet, &name); + hicn_name_set_seq_number(&name, new_suffix); + hicn_interest_set_name(format, (hicn_header_t *)packet, &name); +} + +static inline uint8_t *messageHandler_CreateProbePacket( + hicn_format_t format, uint32_t probe_lifetime) { size_t header_length; hicn_packet_get_header_length_from_format(format, &header_length); - uint8_t *pkt = parcMemory_AllocateAndClear(header_length); + uint8_t *pkt = (uint8_t *)calloc(header_length, 1); - hicn_packet_init_header(format, (hicn_header_t *) pkt); + hicn_packet_init_header(format, (hicn_header_t *)pkt); - hicn_packet_set_dst_port(format, (hicn_header_t *) pkt, BFD_PORT); - hicn_interest_set_lifetime ((hicn_header_t *) pkt, probe_lifetime); + hicn_packet_set_dst_port(format, (hicn_header_t *)pkt, BFD_PORT); + hicn_interest_set_lifetime((hicn_header_t *)pkt, probe_lifetime); return pkt; } -static inline void messageHandler_CreateProbeReply(uint8_t * probe, - hicn_format_t format){ - +static inline void messageHandler_CreateProbeReply(uint8_t *probe, + hicn_format_t format) { hicn_name_t probe_name; - hicn_interest_get_name (format, - (const hicn_header_t *) probe, &probe_name); + hicn_interest_get_name(format, (const hicn_header_t *)probe, &probe_name); ip_address_t probe_locator; - hicn_interest_get_locator (format, - (const hicn_header_t *) probe, &probe_locator); + hicn_interest_get_locator(format, (const hicn_header_t *)probe, + &probe_locator); uint16_t src_prt; uint16_t dst_prt; - hicn_packet_get_src_port(format, (const hicn_header_t *) probe, &src_prt); - hicn_packet_get_dst_port(format, (const hicn_header_t *) probe, &dst_prt); - hicn_packet_set_src_port(format, (hicn_header_t *) probe, dst_prt); - hicn_packet_set_dst_port(format, (hicn_header_t *) probe, src_prt); + hicn_packet_get_src_port(format, (const hicn_header_t *)probe, &src_prt); + hicn_packet_get_dst_port(format, (const hicn_header_t *)probe, &dst_prt); + hicn_packet_set_src_port(format, (hicn_header_t *)probe, dst_prt); + hicn_packet_set_dst_port(format, (hicn_header_t *)probe, src_prt); - hicn_data_set_name (format, (hicn_header_t *) probe, &probe_name); - hicn_data_set_locator (format, (hicn_header_t *) probe, &probe_locator); - hicn_data_set_expiry_time ((hicn_header_t *) probe, 0); + hicn_data_set_name(format, (hicn_header_t *)probe, &probe_name); + hicn_data_set_locator(format, (hicn_header_t *)probe, &probe_locator); + hicn_data_set_expiry_time((hicn_header_t *)probe, 0); } -static inline hicn_name_t * messageHandler_CreateProbeName(const ip_prefix_t *address){ - hicn_name_t * name = parcMemory_AllocateAndClear(sizeof(hicn_name_t)); +static inline hicn_name_t *messageHandler_CreateProbeName( + const ip_prefix_t *address) { + hicn_name_t *name = (hicn_name_t *)calloc(sizeof(hicn_name_t), 1); hicn_name_create_from_ip_prefix(address, 0, name); return name; } -static inline void messageHandler_SetProbeName(uint8_t * probe, hicn_format_t format, - hicn_name_t * name, uint32_t seq){ - hicn_name_set_seq_number (name, seq); - hicn_interest_set_name(format, (hicn_header_t *) probe, name); +static inline void messageHandler_SetProbeName(uint8_t *probe, + hicn_format_t format, + hicn_name_t *name, + uint32_t seq) { + hicn_name_set_seq_number(name, seq); + hicn_interest_set_name(format, (hicn_header_t *)probe, name); } -static inline bool messageHandler_IsAProbe(const uint8_t *packet){ +static inline bool messageHandler_IsAProbe(const uint8_t *packet) { + hicn_format_t format; + hicn_name_t name; + uint32_t seq; + hicn_packet_get_format((hicn_header_t *)packet, &format); + hicn_data_get_name(format, (hicn_header_t *)packet, &name); + hicn_name_get_seq_number(&name, &seq); + if (seq >= MIN_PROBE_SUFFIX && seq <= MAX_PROBE_SUFFIX) return true; + return false; + +#if 0 + // old probe version uint16_t src_prt; uint16_t dst_prt; hicn_packet_get_src_port (HF_INET6_TCP, (const hicn_header_t *) packet, &src_prt); @@ -753,6 +654,7 @@ static inline bool messageHandler_IsAProbe(const uint8_t *packet){ } return false; +#endif } -#endif // Metis_metis_MessageHandler +#endif /* HICNLIGHT_MESSAGE_HANDLER_H */ diff --git a/hicn-light/src/hicn/core/messagePacketType.h b/hicn-light/src/hicn/core/messagePacketType.h deleted file mode 100644 index dfbb12342..000000000 --- a/hicn-light/src/hicn/core/messagePacketType.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file message_packet_type_h - * @brief Defines the packet type for a HICN message - * - */ - -#ifndef message_packet_type_h -#define message_packet_type_h - -typedef enum message_type { - MessagePacketType_Unknown, - MessagePacketType_Interest, - MessagePacketType_ContentObject, - MessagePacketType_WldrNotification -} MessagePacketType; - -#endif // message_packet_type_h diff --git a/hicn-light/src/hicn/strategies/rnd.h b/hicn-light/src/hicn/core/msgbuf.c index 78fb34758..299b20f9b 100644 --- a/hicn-light/src/hicn/strategies/rnd.h +++ b/hicn-light/src/hicn/core/msgbuf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -14,14 +14,8 @@ */ /** - * Forward randomly + * \file msgbuf.c + * \brief Implementation hICN message buffer */ -#ifndef rnd_h -#define rnd_h - -#include <hicn/strategies/strategyImpl.h> - -StrategyImpl* strategyRnd_Create(); - -#endif // rnd_h +#include "msgbuf.h" diff --git a/hicn-light/src/hicn/core/msgbuf.h b/hicn-light/src/hicn/core/msgbuf.h new file mode 100644 index 000000000..e437f1d09 --- /dev/null +++ b/hicn-light/src/hicn/core/msgbuf.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file msgbuf.h + * \brief hICN message buffer + */ + +#ifndef HICNLIGHT_MSGBUF +#define HICNLIGHT_MSGBUF + +#include "name.h" +#include "ticks.h" +#include "messageHandler.h" +#include <hicn/ctrl/hicn-light-ng.h> + +#define MTU 1500 +#define INVALID_MSGBUF_ID ~0ul + +#define msgbuf_id_is_valid(msgbuf_id) \ + ((unsigned long)msgbuf_id != INVALID_MSGBUF_ID) + +#define foreach_msg_type \ + _(UNDEFINED) \ + _(INTEREST) \ + _(DATA) \ + _(WLDR_NOTIFICATION) \ + _(MAPME) \ + _(COMMAND) \ + _(N) + +typedef enum { +#define _(x) MSGBUF_TYPE_##x, + foreach_msg_type +#undef _ +} msgbuf_type_t; +#undef foreach_msg_type + +typedef struct { + unsigned length; + msgbuf_type_t type; + unsigned connection_id; + Ticks recv_ts; + unsigned refs; + unsigned path_label; + union { + /* Interest or data packet */ + struct { + Name name; + } id; + /* Command packet */ + struct { + command_type_t type; + } command; + }; + uint8_t packet[MTU]; +} msgbuf_t; + +#define msgbuf_get_name(M) (&((M)->id.name)) +#define msgbuf_get_connection_id(M) ((M)->connection_id) +#define msgbuf_get_type(M) ((M)->type) +#define msgbuf_has_wldr(M) (messageHandler_HasWldr((M)->packet)) +#define msgbuf_get_len(M) ((M)->length) +#define msgbuf_get_packet(M) ((M)->packet) +#define msgbuf_get_command_type(M) ((M)->command.type) + +// XXX TODO EXPLAIN THE CONSTANT +#define msgbuf_get_lifetime(M) \ + (NSEC_TO_TICKS(messageHandler_GetInterestLifetime((M)->packet) * 1000000ULL)) + +// Lifetimes/expiry times in milliseconds +#define msgbuf_get_interest_lifetime(M) \ + (messageHandler_GetInterestLifetime((M)->packet)) +#define msgbuf_get_data_expiry_time(M) \ + (messageHandler_GetContentExpiryTime((M)->packet)) + +static inline bool msgbuf_set_interest_lifetime(msgbuf_t *msgbuf, + u32 lifetime) { + return messageHandler_SetInterestLifetime(msgbuf->packet, lifetime); +} +static inline bool msgbuf_set_data_expiry_time(msgbuf_t *msgbuf, u32 lifetime) { + return messageHandler_SetDataExpiryTime(msgbuf->packet, lifetime); +} + +#define msgbuf_is_probe(M) messageHandler_IsAProbe((M)->packet) + +/* Path label */ + +#define msgbuf_init_pathlabel(M) \ + ((M)->path_label = messageHandler_GetPathLabel((M)->packet)) +#define msgbuf_update_pathlabel(M, outface) \ + { \ + messageHandler_SetPathLabel((M)->packet, \ + messageHandler_GetPathLabel((M)->packet), \ + (M)->path_label); \ + messageHandler_UpdatePathLabel((M)->packet, outface); \ + } +#define msgbuf_reset_pathlabel(M) \ + { \ + (M)->path_label = 0; \ + messageHandler_ResetPathLabel((M)->packet); \ + } + +/* WLDR */ + +#define msgbuf_reset_wldr_label(M) (messageHandler_ResetWldrLabel((M)->packet)) +#define msgbuf_get_wldr_label(M) (messageHandler_GetWldrLabel((M)->packet)) +#define msgbuf_get_wldr_expected_label(M) \ + (messageHandler_GetWldrExpectedLabel((M)->packet)) +#define msgbuf_get_wldr_last_received(M) \ + (messageHandler_GetWldrLastReceived((M)->packet)) +#define msgbuf_set_wldr_label(M, label) \ + (messageHandler_GetWldrLabel((M)->packet, label)) + +#endif /* HICNLIGHT_MSGBUF */ diff --git a/hicn-light/src/hicn/core/msgbuf_pool.c b/hicn-light/src/hicn/core/msgbuf_pool.c new file mode 100644 index 000000000..fb5d0a07c --- /dev/null +++ b/hicn-light/src/hicn/core/msgbuf_pool.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file msgbuf_pool.c + * @brief Implementation of hICN packet pool. + */ + +#include "../base/pool.h" +#include "msgbuf_pool.h" +#include "../core/name.h" // name_Release + +msgbuf_pool_t *_msgbuf_pool_create(size_t init_size, size_t max_size) { + msgbuf_pool_t *msgbuf_pool = malloc(sizeof(msgbuf_pool_t)); + + if (init_size == 0) init_size = PACKET_POOL_DEFAULT_INIT_SIZE; + + pool_init(msgbuf_pool->buffers, init_size, 0); + + return msgbuf_pool; +} + +void msgbuf_pool_free(msgbuf_pool_t *msgbuf_pool) { + pool_free(msgbuf_pool->buffers); + free(msgbuf_pool); +} + +off_t msgbuf_pool_get(msgbuf_pool_t *msgbuf_pool, msgbuf_t **msgbuf) { + return pool_get(msgbuf_pool->buffers, *msgbuf); +} + +void msgbuf_pool_put(msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf) { + pool_put(msgbuf_pool->buffers, msgbuf); +} + +int msgbuf_pool_getn(msgbuf_pool_t *msgbuf_pool, msgbuf_t **msgbuf, size_t n) { + // CAVEAT: Resize at the beginning otherwise the resize can be + // triggered by an intermediate msgbuf_pool_put, making the + // buffers previously retrieved invalid + uint64_t remaining_pool_space = + pool_get_free_indices_size(msgbuf_pool->buffers); + while (remaining_pool_space < n) { + _pool_resize((void **)&(msgbuf_pool->buffers), sizeof(msgbuf_t)); + + remaining_pool_space = pool_get_free_indices_size(msgbuf_pool->buffers); + } + + for (unsigned i = 0; i < n; i++) { + // If not able to get the msgbuf + if (msgbuf_pool_get(msgbuf_pool, &msgbuf[i]) < 0) { + // Release all the msgbufs retrieved so far + for (unsigned j = 0; j < i; j++) { + msgbuf_pool_put(msgbuf_pool, msgbuf[j]); + } + return -1; + } + } + return 0; +} + +off_t msgbuf_pool_get_id(msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf) { + return msgbuf - msgbuf_pool->buffers; +} + +msgbuf_t *msgbuf_pool_at(const msgbuf_pool_t *msgbuf_pool, off_t id) { + assert(msgbuf_id_is_valid(id)); + return msgbuf_pool->buffers + id; +} + +void msgbuf_pool_acquire(msgbuf_t *msgbuf) { msgbuf->refs++; }; + +void msgbuf_pool_release(msgbuf_pool_t *msgbuf_pool, msgbuf_t **msgbuf_ptr) { + msgbuf_t *msgbuf = *msgbuf_ptr; + assert(msgbuf->refs > 0); + msgbuf->refs--; + + if (msgbuf->refs == 0) { + WITH_TRACE({ + off_t msgbuf_id = msgbuf_pool_get_id(msgbuf_pool, msgbuf); + if (msgbuf->type != MSGBUF_TYPE_INTEREST && + msgbuf->type != MSGBUF_TYPE_DATA) { + TRACE("Msgbuf %d (%p) - put to msgbuf pool", msgbuf_id, msgbuf); + } else { + char *name_str = name_ToString(msgbuf_get_name(msgbuf)); + const char *msgbuf_type_str = + msgbuf->type == MSGBUF_TYPE_INTEREST ? "interest" : "data"; + TRACE("Msgbuf %d (%p) - %s (%s) put to msgbuf pool", msgbuf_id, msgbuf, + name_str, msgbuf_type_str); + free(name_str); + } + }) + + msgbuf_pool_put(msgbuf_pool, msgbuf); + *msgbuf_ptr = NULL; + } +}; + +off_t msgbuf_pool_clone(msgbuf_pool_t *msgbuf_pool, msgbuf_t **new_msgbuf, + off_t orginal_msg_id) { + msgbuf_t *original_msgbuf = msgbuf_pool_at(msgbuf_pool, orginal_msg_id); + off_t offset = pool_get(msgbuf_pool->buffers, *new_msgbuf); + memcpy(*new_msgbuf, original_msgbuf, sizeof(msgbuf_t)); + (*new_msgbuf)->refs = 0; + return offset; +} diff --git a/hicn-light/src/hicn/core/msgbuf_pool.h b/hicn-light/src/hicn/core/msgbuf_pool.h new file mode 100644 index 000000000..b8a15fd84 --- /dev/null +++ b/hicn-light/src/hicn/core/msgbuf_pool.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file msgbuf_pool.h + * @brief hICN msgbuf pool. + * + * The msgbuf pool is used to store packet payloads while the packets are in + * transit, as well as holding them into the packet cache (PIT, CSS), WLDR, + * mapme, etc. + * + * Control packets might receive a special treatment in that they are eventually + * transformed into a ack/nack, but this should not affect any part of this + * design. + * + * Do we need a reference count, or simply a lock ? + * What about weak references ? + * We need to be sure that a pool element is never referenced ever again after + * it is deleted from the pool as its ID might be reaffected. + * + * It might even be better to store references to msgbuf's as they might hold + * additional information of interest about the packet... a bit like a skbuff in + * linux. Is this relevant for the packet cache ? + */ + +#ifndef HICNLIGHT_MSGBUF_POOL_H +#define HICNLIGHT_MSGBUF_POOL_H + +#include "msgbuf.h" + +#define MTU 1500 +#define PACKET_POOL_DEFAULT_INIT_SIZE 1024 + +typedef struct { + msgbuf_t *buffers; +} msgbuf_pool_t; + +/** + * @brief Allocate and initialize a msgbuf pool structure (helper). + * + * @param[in] init_size Number of buffers that can be stored in msgbuf pool. + * @param[in] max_size Maximum size. + * @return msgbuf_pool_t* Pointer to the msgbuf pool created. + * + * @note + * - 0 for init size means a default value (of 1024) + * - 0 for max_size means no limit + */ +msgbuf_pool_t *_msgbuf_pool_create(size_t init_size, size_t max_size); + +/** + * @brief Allocate and initialize a msgbuf pool data structure. + * + * @return msgbuf_pool_t* Pointer to the msgbuf pool created. + */ +#define msgbuf_pool_create() _msgbuf_pool_create(0, 0) + +/** + * @brief Free a msgbuf pool data structure. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to free. + */ +void msgbuf_pool_free(msgbuf_pool_t *msgbuf_pool); + +/** + * @brief Get a free msgbuf from the msgbuf pool data structure. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in, out] msgbuf Empty msgbuf that will be used to return the + * allocated one from the msgbuf pool. + * @return off_t ID of the msgbuf requested. + */ +off_t msgbuf_pool_get(msgbuf_pool_t *msgbuf_pool, msgbuf_t **msgbuf); + +/** + * @brief Release a msgbuf previously obtained, making it available to the + * msgbuf pool. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in] msgbuf Pointer to the msgbuf to release. + */ +void msgbuf_pool_put(msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf); + +/** + * @brief Get multiple free msgbufs from the msgbuf pool data structure. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in, out] msgbuf Pointer to the first empty msgbuf that will be used to + * allocate the msgbufs. + * @param[in] n Number of msgbufs requested. + * @retval 0 Success. + * @retval -1 Error. + */ +int msgbuf_pool_getn(msgbuf_pool_t *msgbuf_pool, msgbuf_t **msgbuf, size_t n); + +/** + * @brief Get the ID corresponding to the msgbuf requested. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in] msgbuf Pointer to the msgbuf to retrieve the ID for. + * @return off_t ID of the msgbuf requested. + */ +off_t msgbuf_pool_get_id(msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf); + +/** + * @brief Get the msgbuf corresponding to the ID requested. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in] id Index of the msgbuf to retrieve. + * @return msgbuf_t* Pointer to the msgbuf corresponding to the ID requested. + */ +msgbuf_t *msgbuf_pool_at(const msgbuf_pool_t *msgbuf_pool, off_t id); + +/** + * @brief Acquire a buffer (by increasing its reference count). + * + * @param[in] msgbuf Pointer to the msgbuf to acquire + */ +void msgbuf_pool_acquire(msgbuf_t *msgbuf); + +/** + * @brief Release a buffer. The buffer is also put back into the msgbuf + * pool if everyone who acquired it has released its possession. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use + * @param[in, out] msgbuf Pointer that holds the pointer to the msgbuf + * to release; the double indirection is used to set the msgbuf pointer + * to NULL in case it is put into the msgbuf pool. + */ +void msgbuf_pool_release(msgbuf_pool_t *msgbuf_pool, msgbuf_t **msgbuf_ptr); + +/** + * @brief Copy the original msgbuf in new msgbuf taken from the pool. The ref + * count on new msgbuf is set to 0 + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use + * @param[in,out] new__msgbuf Pointer that holds the replicatate msgbuf + * @param[in] original_msgbuf id. use id instead of the pointer becasue the + * pointer may becose invalid if the msgbuf_pool requires a resize + * @return off_t ID of the msgbuf requested. + */ +off_t msgbuf_pool_clone(msgbuf_pool_t *msgbuf_pool, msgbuf_t **new_msgbuf, + off_t orginal_msg_id); + +#endif /* HICNLIGHT_MSGBUF_POOL_H */ diff --git a/hicn-light/src/hicn/core/name.c b/hicn-light/src/hicn/core/name.c index b4a5e8d1b..8886cc929 100644 --- a/hicn-light/src/hicn/core/name.c +++ b/hicn-light/src/hicn/core/name.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,201 +13,133 @@ * limitations under the License. */ +#include <assert.h> #include <limits.h> #include <hicn/hicn-light/config.h> #include <stdbool.h> #include <stdio.h> #include <string.h> -#include <parc/algol/parc_BufferComposer.h> -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> - +#include <hicn/common.h> // cumulative_hash32 #include <hicn/core/messageHandler.h> #include <hicn/core/name.h> - -#include <parc/algol/parc_Hash.h> - -#include <parc/assert/parc_Assert.h> +#include <hicn/util/log.h> +#include <hicn/base/hash.h> #define IPv6_TYPE 6 #define IPv4_TYPE 4 -// assumption: the IPv6 address is the name, the TCP segment number is the ICN -// segment - -struct name { - NameBitvector *content_name; - uint32_t segment; - uint32_t name_hash; - // the refcount is shared between all copies - unsigned *refCountPtr; -}; - -// ===================================================== - -static unsigned _getRefCount(const Name *name) { return *name->refCountPtr; } - -static void _incrementRefCount(Name *name) { - parcAssertTrue(*name->refCountPtr > 0, - "Illegal State: Trying to increment a 0 refcount!"); - (*name->refCountPtr)++; -} - -static void _decrementRefCount(Name *name) { - parcAssertTrue(*name->refCountPtr > 0, - "Illegal State: Trying to decrement a 0 refcount!"); - (*name->refCountPtr)--; -} - static uint32_t _computeHash(Name *name) { - parcAssertNotNull(name, "Parameter must be non-null pointer"); + assert(name); - uint32_t hash1 = nameBitvector_GetHash32(name->content_name); - return parcHash32_Data_Cumulative((const uint8_t *)&name->segment, 4, hash1); + uint32_t hash1 = nameBitvector_GetHash32(&(name->content_name)); + return hashlittle(&name->segment, sizeof(name->segment), hash1); } // ============================================================================ -Name *name_CreateFromPacket(const uint8_t *packet, MessagePacketType type) { - Name *name = parcMemory_AllocateAndClear(sizeof(Name)); - parcAssertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Name)); +void name_create_from_interest(const uint8_t *packet, Name *name) { + assert(packet); + assert(name); if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) { - if (type == MessagePacketType_Interest) { - name->content_name = nameBitvector_CreateFromIn6Addr( - (struct in6_addr *)messageHandler_GetDestination(packet), 128); - } else if (type == MessagePacketType_ContentObject) { - name->content_name = nameBitvector_CreateFromIn6Addr( - (struct in6_addr *)messageHandler_GetSource(packet), 128); - } else { - parcMemory_Deallocate((void **)&name); - return NULL; - } + nameBitvector_CreateFromIn6Addr( + &(name->content_name), + (struct in6_addr *)messageHandler_GetDestination(packet), 128); } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) { - if (type == MessagePacketType_Interest) { - name->content_name = nameBitvector_CreateFromInAddr( - *((uint32_t *)messageHandler_GetDestination(packet)), 32); - } else if (type == MessagePacketType_ContentObject) { - name->content_name = nameBitvector_CreateFromInAddr( - *((uint32_t *)messageHandler_GetSource(packet)), 32); - } else { - parcMemory_Deallocate((void **)&name); - return NULL; - } + nameBitvector_CreateFromInAddr( + &(name->content_name), + *((uint32_t *)messageHandler_GetDestination(packet)), 32); } else { - printf("Error: unknown message type\n"); - parcMemory_Deallocate((void **)&name); - return NULL; + ERROR("Error: unknown message type\n"); + return; } name->segment = messageHandler_GetSegment(packet); name->name_hash = _computeHash(name); - - name->refCountPtr = parcMemory_Allocate(sizeof(unsigned)); - parcAssertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL", - sizeof(unsigned)); - *name->refCountPtr = 1; - return name; } -Name *name_CreateFromAddress(address_type addressType, ip_address_t addr, - uint8_t len) { - Name *name = parcMemory_AllocateAndClear(sizeof(Name)); - parcAssertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Name)); - if (addressType == ADDR_INET) { - name->content_name = nameBitvector_CreateFromInAddr(addr.v4.as_u32, len); - } else if (addressType == ADDR_INET6) { - name->content_name = nameBitvector_CreateFromIn6Addr(&addr.v6.as_in6addr, len); +void name_create_from_data(const uint8_t *packet, Name *name) { + assert(packet); + assert(name); + + if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) { + nameBitvector_CreateFromIn6Addr( + &(name->content_name), + (struct in6_addr *)messageHandler_GetSource(packet), 128); + } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) { + nameBitvector_CreateFromInAddr( + &(name->content_name), *((uint32_t *)messageHandler_GetSource(packet)), + 32); } else { - parcTrapNotImplemented("Unkown packet type"); + printf("Error: unknown message type\n"); + return; } - name->segment = 0; + name->segment = messageHandler_GetSegment(packet); name->name_hash = _computeHash(name); - - name->refCountPtr = parcMemory_Allocate(sizeof(unsigned)); - parcAssertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL", - sizeof(unsigned)); - *name->refCountPtr = 1; - - return name; } -void name_Release(Name **namePtr) { - parcAssertNotNull(namePtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*namePtr, "Parameter must dereference to non-null pointer"); - - Name *name = *namePtr; - _decrementRefCount(name); - if (_getRefCount(name) == 0) { - parcMemory_Deallocate((void **)&(name->refCountPtr)); - nameBitvector_Destroy(&(name->content_name)); +void name_CreateFromAddress(Name *name, int family, ip_address_t addr, + uint8_t len) { + assert(name); + + switch (family) { + case AF_INET: + nameBitvector_CreateFromInAddr(&(name->content_name), addr.v4.as_u32, + len); + break; + case AF_INET6: + nameBitvector_CreateFromIn6Addr(&(name->content_name), + &addr.v6.as_in6addr, len); + break; + default: + return; } - parcMemory_Deallocate((void **)&name); - *namePtr = NULL; -} - -Name *name_Acquire(const Name *original) { - parcAssertNotNull(original, "Parameter must be non-null"); - Name *copy = parcMemory_AllocateAndClear(sizeof(Name)); - parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Name)); - memcpy(copy, original, sizeof(Name)); - _incrementRefCount(copy); - - return copy; + name->segment = 0; + name->name_hash = _computeHash(name); } -Name *name_Copy(const Name *original) { - parcAssertNotNull(original, "Parameter must be non-null"); - Name *copy = parcMemory_AllocateAndClear(sizeof(Name)); - parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Name)); +void name_Copy(const Name *original, Name *copy) { + assert(original); + assert(copy); - copy->content_name = nameBitvector_Copy(original->content_name); + nameBitvector_Copy(&(original->content_name), &(copy->content_name)); copy->segment = original->segment; copy->name_hash = original->name_hash; - - copy->refCountPtr = parcMemory_Allocate(sizeof(unsigned)); - parcAssertNotNull(copy->refCountPtr, "parcMemory_Allocate(%zu) returned NULL", - sizeof(unsigned)); - *copy->refCountPtr = 1; - - return copy; } uint32_t name_HashCode(const Name *name) { - parcAssertNotNull(name, "Parameter must be non-null"); + assert(name); return name->name_hash; } NameBitvector *name_GetContentName(const Name *name) { - parcAssertNotNull(name, "Parameter must be non-null"); - return name->content_name; + assert(name); + return (NameBitvector *)&(name->content_name); } -bool name_Equals(const Name *a, const Name *b) { - parcAssertNotNull(a, "Parameter a must be non-null"); - parcAssertNotNull(b, "Parameter b must be non-null"); +uint32_t name_GetSegment(const Name *name) { + assert(name); + return name->segment; +} - /* BEGIN: Workaround for HICN-400 */ - if ((!a->content_name) || (!b->content_name)) - return false; - /* END: Workaround for HICN-400 */ +void name_SetSegment(Name *name, uint32_t segment) { name->segment = segment; } - if ((nameBitvector_Equals(a->content_name, b->content_name) && +bool name_Equals(const Name *a, const Name *b) { + assert(a); + assert(b); + + if ((nameBitvector_Equals(&(a->content_name), &(b->content_name)) && a->segment == b->segment)) return true; return false; } int name_Compare(const Name *a, const Name *b) { - parcAssertNotNull(a, "Parameter a must be non-null"); - parcAssertNotNull(b, "Parameter b must be non-null"); + assert(a); + assert(b); if (a == NULL && b == NULL) { return 0; @@ -219,7 +151,7 @@ int name_Compare(const Name *a, const Name *b) { return +1; } - int res = nameBitvector_Compare(a->content_name, b->content_name); + int res = nameBitvector_Compare(&(a->content_name), &(b->content_name)); if (res != 0) { return res; @@ -235,30 +167,30 @@ int name_Compare(const Name *a, const Name *b) { } char *name_ToString(const Name *name) { - char *output = malloc(128); + char *output = malloc(NI_MAXHOST * 2); + address_t address; + nameBitvector_ToAddress(name_GetContentName(name), &address); - Address *packetAddr = nameBitvector_ToAddress(name_GetContentName(name)); + char addr_str[NI_MAXHOST]; + int err = address_to_string(&address, addr_str, NULL); + _ASSERT(!err); - char * address_str = addressToString(packetAddr); - sprintf(output, "name: %s seq: %u", address_str, name->segment); - parcMemory_Deallocate((void **)&address_str); - - addressDestroy(&packetAddr); + int chars_written = + snprintf(output, NI_MAXHOST * 2, "name=%s|%u", addr_str, name->segment); + _ASSERT(chars_written > 0); return output; } void name_setLen(Name *name, uint8_t len) { - nameBitvector_setLen(name->content_name, len); + nameBitvector_setLen(&(name->content_name), len); name->name_hash = _computeHash(name); } #ifdef WITH_POLICY -uint32_t name_GetSuffix(const Name * name) { - return name->segment; -} +uint32_t name_GetSuffix(const Name *name) { return name->segment; } -uint8_t name_GetLen(const Name * name) { - return nameBitvector_GetLength(name->content_name); +uint8_t name_GetLen(const Name *name) { + return nameBitvector_GetLength(&(name->content_name)); } #endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/core/name.h b/hicn-light/src/hicn/core/name.h index db9438150..23505243b 100644 --- a/hicn-light/src/hicn/core/name.h +++ b/hicn-light/src/hicn/core/name.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -19,50 +19,52 @@ #include <stdbool.h> #include <stdlib.h> -#include <hicn/core/messagePacketType.h> -#include <hicn/core/nameBitvector.h> -#include <hicn/utils/address.h> +#include "nameBitvector.h" -#include <hicn/utils/commands.h> +typedef struct { + NameBitvector content_name; + uint32_t segment; + uint32_t name_hash; +} Name; -struct name; -typedef struct name Name; +#define EMPTY_NAME \ + (Name) { .content_name = EMPTY_NAME_BITVECTOR, .segment = 0, .name_hash = 0, } /** * Creates a name from packet * */ -Name *name_CreateFromPacket(const uint8_t *memory, MessagePacketType type); +void name_create_from_interest(const uint8_t *packet, Name *name); +void name_create_from_data(const uint8_t *packet, Name *name); /** - * Releases one reference count, and frees memory after last reference + * returns a copy of the name */ -void name_Release(Name **namePtr); +void name_Copy(const Name *original, Name *copy); /** - * Acquires a reference to the name so that a reference count increments. - * Notice however that this * function is used only when a new fib entry is - * created (mostly configuration time) probably here performance are not - * critical. + * A hash value for use in hash tables + * */ -Name *name_Acquire(const Name *original); +uint32_t name_HashCode(const Name *name); /** - * returns a copy of the name + * Returns the content name without the segment value + * */ -Name *name_Copy(const Name *original); +NameBitvector *name_GetContentName(const Name *name); /** - * A hash value for use in hash tables + * Returns the segment value * */ -uint32_t name_HashCode(const Name *name); +uint32_t name_GetSegment(const Name *name); /** - * Returns the content name without the segment value + * Set the sequence number of the name provided * */ -NameBitvector *name_GetContentName(const Name *name); +void name_SetSegment(Name *name, uint32_t segment); /** * Determine if two HicnName instances are equal. @@ -93,12 +95,12 @@ void name_setLen(Name *name, uint8_t len); * Creates a name from a Address * */ -Name *name_CreateFromAddress(address_type addressType, ip_address_t addr, - uint8_t len); +void name_CreateFromAddress(Name *name, int family, ip_address_t addr, + uint8_t len); #ifdef WITH_POLICY -uint32_t name_GetSuffix(const Name * name); -uint8_t name_GetLen(const Name * name); +uint32_t name_GetSuffix(const Name *name); +uint8_t name_GetLen(const Name *name); #endif /* WITH_POLICY */ #endif // name_h diff --git a/hicn-light/src/hicn/core/nameBitvector.c b/hicn-light/src/hicn/core/nameBitvector.c index 653560750..1314671db 100644 --- a/hicn-light/src/hicn/core/nameBitvector.c +++ b/hicn-light/src/hicn/core/nameBitvector.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -17,17 +17,13 @@ #include <stdio.h> #include <stdlib.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> - #include <hicn/core/messageHandler.h> #include <hicn/core/nameBitvector.h> -#include <parc/algol/parc_Hash.h> - -#include <hicn/utils/commands.h> +#include <hicn/base/hash.h> +#include <hicn/ctrl/hicn-light-ng.h> -#define NAME_LEN 2 +#define DEFAULT_PORT 1234 const uint64_t BV_SIZE = 64; const uint64_t WIDTH = 128; @@ -37,19 +33,12 @@ const uint64_t ONE = 0x1; // [bits[0] uint64_t ] [bits[1] unit64_t ] // ^ ^ ^ ^ // 63 0 127 64 -// [1000 0000 ... 0000 1101] [1000 0000 ... 0000 0011] //binary +// [1000 0000 ... 0000 1011] [1000 0000 ... 0000 0011] //binary // 1 b 1 c //hex -struct name_bitvector { - uint64_t bits[NAME_LEN]; - uint8_t len; - uint8_t IPversion; -}; - -NameBitvector *nameBitvector_CreateFromInAddr(uint32_t addr, uint8_t len) { - NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector)); - parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(NameBitvector)); +void nameBitvector_CreateFromInAddr(NameBitvector *bitvector, uint32_t addr, + uint8_t len) { + assert(bitvector); bitvector->bits[0] = 0; bitvector->bits[1] = 0; @@ -68,17 +57,12 @@ NameBitvector *nameBitvector_CreateFromInAddr(uint32_t addr, uint8_t len) { bitvector->len = len; bitvector->IPversion = IPv4_TYPE; - - return bitvector; } -NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr, - uint8_t len) { - parcAssertNotNull(addr, "addr cannot be null"); - - NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector)); - parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(NameBitvector)); +void nameBitvector_CreateFromIn6Addr(NameBitvector *bitvector, + struct in6_addr *addr, uint8_t len) { + assert(addr); + assert(bitvector); bitvector->bits[0] = 0; bitvector->bits[1] = 0; @@ -94,69 +78,26 @@ NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr, bitvector->len = len; bitvector->IPversion = IPv6_TYPE; - - return bitvector; } -NameBitvector *nameBitvector_CreateFromAddress(const Address *prefix, - uint8_t len) { - parcAssertNotNull(prefix, "prefix cannot be null"); - - NameBitvector *bitvector = NULL; - switch (addressGetType(prefix)) { - case ADDR_INET: { - struct sockaddr_in addr; - addressGetInet(prefix, &addr); - bitvector = nameBitvector_CreateFromInAddr(addr.sin_addr.s_addr, len); - break; - } - case ADDR_INET6: { - struct sockaddr_in6 addr; - addressGetInet6(prefix, &addr); - bitvector = nameBitvector_CreateFromIn6Addr(&addr.sin6_addr, len); - break; - } - default: - parcTrapNotImplemented("Unkown packet type"); - break; - } - - return bitvector; -} - -NameBitvector *nameBitvector_Copy(const NameBitvector *original) { - parcAssertNotNull(original, "original cannot be null"); - - NameBitvector *copy = parcMemory_AllocateAndClear(sizeof(NameBitvector)); - parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(NameBitvector)); +void nameBitvector_Copy(const NameBitvector *original, NameBitvector *copy) { + assert(original); + assert(copy); copy->bits[0] = original->bits[0]; copy->bits[1] = original->bits[1]; copy->len = original->len; - - return copy; -} - -void nameBitvector_Destroy(NameBitvector **bitvectorPtr) { - parcAssertNotNull(bitvectorPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*bitvectorPtr, - "Parameter must dereference to non-null pointer"); - - NameBitvector *bv = *bitvectorPtr; - parcMemory_Deallocate((void **)&(bv)); - *bitvectorPtr = NULL; + copy->IPversion = original->IPversion; } uint8_t nameBitvector_GetLength(const NameBitvector *name) { return name->len; } uint32_t nameBitvector_GetHash32(const NameBitvector *name) { - return parcHash32_Data_Cumulative((const uint8_t *)name->bits, 16, 0); + return hash(&name->bits, 16); } bool nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b) { - if (a->bits[0] == b->bits[0] && a->bits[1] == b->bits[1] && a->len == b->len) - return true; + if (nameBitvector_Compare(a, b) == 0) return true; return false; } @@ -189,14 +130,15 @@ int nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b) { } int nameBitvector_testBit(const NameBitvector *name, uint8_t pos, bool *bit) { - if(pos >= name->len || pos > (WIDTH -1)) - return -1; + if (pos >= name->len || pos > (WIDTH - 1)) return -1; - *bit = (name->bits[pos / BV_SIZE] & (ONE << ((BV_SIZE - 1) - (pos % BV_SIZE)))); + *bit = + (name->bits[pos / BV_SIZE] & (ONE << ((BV_SIZE - 1) - (pos % BV_SIZE)))); return 0; } +// TODO XXX use ffs(ll) uint64_t _diff_bit_log2(uint64_t val) { // base 2 log of an uint64_t. This is the same as get the position of // the highest bit set (or most significant bit set, MSB) @@ -229,8 +171,7 @@ uint64_t _diff_bit_log2(uint64_t val) { return result; } -uint32_t nameBitvector_lpm(const NameBitvector *a, - const NameBitvector *b) { +uint32_t nameBitvector_lpm(const NameBitvector *a, const NameBitvector *b) { uint32_t limit; uint32_t prefix_len; if (a->len < b->len) @@ -239,32 +180,30 @@ uint32_t nameBitvector_lpm(const NameBitvector *a, limit = b->len; uint64_t diff = a->bits[0] ^ b->bits[0]; - if(diff){ + if (diff) { prefix_len = (uint32_t)(BV_SIZE - (_diff_bit_log2(diff) + 1)); - //printf("if 1 diff = %lu plen = %d\n", diff, prefix_len); - }else{ - prefix_len = (uint32_t)BV_SIZE; + // printf("if 1 diff = %lu plen = %d\n", diff, prefix_len); + } else { + prefix_len = BV_SIZE; diff = a->bits[1] ^ b->bits[1]; - if(diff){ - prefix_len += (uint32_t)(BV_SIZE - (_diff_bit_log2(diff) + 1)); - //printf("if 2 diff = %lu plen = %d\n", diff, prefix_len); - }else{ - prefix_len += (uint32_t)BV_SIZE; + if (diff) { + prefix_len += (BV_SIZE - (_diff_bit_log2(diff) + 1)); + // printf("if 2 diff = %lu plen = %d\n", diff, prefix_len); + } else { + prefix_len += BV_SIZE; } } - if(prefix_len < limit) - return prefix_len; + if (prefix_len < limit) return prefix_len; return limit; } -void nameBitvector_clear(NameBitvector *a, uint8_t start_from){ - for(uint8_t pos = start_from; pos < WIDTH; pos++) - a->bits[pos / BV_SIZE] &= ~(ONE << ((BV_SIZE - 1) - (pos % BV_SIZE))); +void nameBitvector_clear(NameBitvector *a, uint8_t start_from) { + for (uint8_t pos = start_from; pos < WIDTH; pos++) + a->bits[pos / BV_SIZE] &= ~(ONE << ((BV_SIZE - 1) - (pos % BV_SIZE))); } -int nameBitvector_ToIPAddress(const NameBitvector *name, - ip_prefix_t *prefix) { +int nameBitvector_ToIPAddress(const NameBitvector *name, ip_prefix_t *prefix) { if (name->IPversion == IPv4_TYPE) { struct in_addr *addr = (struct in_addr *)(&prefix->address.v4.buffer); prefix->family = AF_INET; @@ -302,11 +241,11 @@ int nameBitvector_ToIPAddress(const NameBitvector *name, void nameBitvector_setLen(NameBitvector *name, uint8_t len) { name->len = len; } -Address *nameBitvector_ToAddress(const NameBitvector *name) { +void nameBitvector_ToAddress(const NameBitvector *name, address_t *address) { if (name->IPversion == IPv4_TYPE) { - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(1234); + struct sockaddr_in *sin = address4(address); + sin->sin_family = AF_INET; + sin->sin_port = htons(DEFAULT_PORT); uint32_t tmp_addr = name->bits[0] >> 32ULL; uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24; @@ -314,51 +253,44 @@ Address *nameBitvector_ToAddress(const NameBitvector *name) { uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8; uint8_t addr_4 = (tmp_addr & 0x000000ff); - addr.sin_addr.s_addr = 0; - addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_4) << 8; - addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_3) << 8; - addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_2) << 8; - addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_1); - - Address *packetAddr = addressCreateFromInet(&addr); - - return packetAddr; - + sin->sin_addr.s_addr = 0; + sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_4) << 8; + sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_3) << 8; + sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_2) << 8; + sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_1); } else { - struct sockaddr_in6 addr; - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(1234); - addr.sin6_scope_id = 0; - addr.sin6_flowinfo = 0; + struct sockaddr_in6 *sin6 = address6(address); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(DEFAULT_PORT); + sin6->sin6_scope_id = 0; + sin6->sin6_flowinfo = 0; for (int i = 0; i < 8; i++) { - addr.sin6_addr.s6_addr[i] = + sin6->sin6_addr.s6_addr[i] = (uint8_t)((name->bits[0] >> 8 * (7 - i)) & 0xFF); } int x = 0; for (int i = 8; i < 16; ++i) { - addr.sin6_addr.s6_addr[i] = + sin6->sin6_addr.s6_addr[i] = (uint8_t)((name->bits[1] >> 8 * (7 - x)) & 0xFF); x++; } - - Address *packetAddr = addressCreateFromInet6(&addr); - - return packetAddr; } } char *nameBitvector_ToString(const NameBitvector *name) { char *output = malloc(WIDTH); - Address *packetAddr = nameBitvector_ToAddress(name); - - char * str = addressToString(packetAddr); - sprintf(output, "prefix: %s len: %u", str, name->len); - parcMemory_Deallocate((void **)&str); + address_t address; + nameBitvector_ToAddress(name, &address); - addressDestroy(&packetAddr); + // XXX TODO +#if 0 + sprintf(output, "prefix: %s len: %u", addressToString(packetAddr), name->len); +#else + snprintf(output, WIDTH, "%s", "ENOIMPL"); +#endif return output; } diff --git a/hicn-light/src/hicn/core/nameBitvector.h b/hicn-light/src/hicn/core/nameBitvector.h index 19944778c..e3cc108ac 100644 --- a/hicn-light/src/hicn/core/nameBitvector.h +++ b/hicn-light/src/hicn/core/nameBitvector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -20,19 +20,25 @@ #include <stdint.h> #include <stdlib.h> -#include <hicn/utils/address.h> +#include "address.h" -struct name_bitvector; -typedef struct name_bitvector NameBitvector; +#define NAME_LEN 2 +typedef struct { + uint64_t bits[NAME_LEN]; + uint8_t len; + uint8_t IPversion; +} NameBitvector; -NameBitvector *nameBitvector_CreateFromInAddr(uint32_t addr, uint8_t len); +#define EMPTY_NAME_BITVECTOR \ + (NameBitvector) { .bits[0] = 0, .bits[1] = 0, .len = 0, .IPversion = 0, } -NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr, - uint8_t len); +void nameBitvector_CreateFromInAddr(NameBitvector *bitvector, uint32_t addr, + uint8_t len); -NameBitvector *nameBitvector_Copy(const NameBitvector *original); +void nameBitvector_CreateFromIn6Addr(NameBitvector *bitvector, + struct in6_addr *addr, uint8_t len); -void nameBitvector_Destroy(NameBitvector **bitvectorPtr); +void nameBitvector_Copy(const NameBitvector *original, NameBitvector *copy); uint8_t nameBitvector_GetLength(const NameBitvector *name); @@ -51,7 +57,7 @@ void nameBitvector_clear(NameBitvector *a, uint8_t start_from); int nameBitvector_ToIPAddress(const NameBitvector *name, ip_prefix_t *prefix); void nameBitvector_setLen(NameBitvector *name, uint8_t len); -Address *nameBitvector_ToAddress(const NameBitvector *name); +void nameBitvector_ToAddress(const NameBitvector *name, address_t *address); char *nameBitvector_ToString(const NameBitvector *name); diff --git a/hicn-light/src/hicn/core/nexthops.c b/hicn-light/src/hicn/core/nexthops.c new file mode 100644 index 000000000..190f09ab0 --- /dev/null +++ b/hicn-light/src/hicn/core/nexthops.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file nexthops.c + * \brief Nexthops implementation + */ + +#include "nexthops.h" + +int nexthops_disable(nexthops_t *nexthops, off_t offset) { + if (offset >= nexthops->num_elts) return -1; + nexthops->flags |= (1 << offset); + nexthops->cur_elts--; + return 0; +} + +void nexthops_reset(nexthops_t *nexthops) { + nexthops->flags = 0; + nexthops->cur_elts = nexthops->num_elts; +} + +off_t nexthops_add(nexthops_t *nexthops, nexthop_t nexthop) { + off_t id; + unsigned i, n; + nexthops_enumerate(nexthops, i, n, { + if (n == nexthop) return i; + }); + id = nexthops->num_elts++; + nexthops->elts[id] = nexthop; + nexthops_reset(nexthops); + return id; +} + +off_t nexthops_remove(nexthops_t *nexthops, nexthop_t nexthop) { + unsigned i, n; + nexthops_enumerate(nexthops, i, n, { + if (n == nexthop) { + nexthops->num_elts--; + nexthops->elts[i] = nexthops->elts[nexthops->num_elts]; + nexthops->state[i] = nexthops->state[nexthops->num_elts]; + nexthops_reset(nexthops); + return i; + } + }); + return INVALID_NEXTHOP; +} + +bool nexthops_contains(nexthops_t *nexthops, unsigned nexthop) { + unsigned n; + nexthops_foreach(nexthops, n, { + if (n == nexthop) return true; + }); + return false; +} + +off_t nexthops_find(nexthops_t *nexthops, unsigned nexthop) { + unsigned i, n; + nexthops_enumerate(nexthops, i, n, { + if (n == nexthop) return i; + }); + return INVALID_NEXTHOP; +} + +unsigned nexthops_get_one(nexthops_t *nexthops) { + unsigned n; + nexthops_foreach(nexthops, n, { return n; }); + return INVALID_NEXTHOP; +} + +int nexthops_select(nexthops_t *nexthops, off_t i) { + if (i >= nexthops->num_elts) return -1; + nexthops->flags = ~0; /* all 1, could be limited to num_elts */ + nexthops->flags &= ~(1 << (i)); + nexthops->cur_elts = 1; + return 0; +} + +#ifdef WITH_POLICY + +void nexthops_set_priority(nexthops_t *nexthops, nexthop_t nexthop, + int priority) { + unsigned i; + nexthop_t nh; + nexthops_enumerate(nexthops, i, nh, { + if (nexthop == nh) nexthops_set_priority_by_id(nexthops, i, priority); + }); +} + +void nexthops_set_priority_by_id(nexthops_t *nexthops, off_t i, int priority) { + nexthops->state[i].priority = priority; +} + +void nexthops_reset_priority(nexthops_t *nexthops, nexthop_t nexthop) { + nexthops_set_priority(nexthops, nexthop, DEFAULT_PRIORITY); +} + +void nexthops_reset_priority_by_id(nexthops_t *nexthops, off_t i) { + nexthops_set_priority_by_id(nexthops, i, DEFAULT_PRIORITY); +} + +void nexthops_reset_priorities(nexthops_t *nexthops) { + unsigned i; + nexthop_t nh; + nexthops_enumerate(nexthops, i, nh, { + (void)nh; + nexthops_reset_priority(nexthops, i); + }); +} + +bool nexthops_equal(nexthops_t *a, nexthops_t *b) { + unsigned n; + if (nexthops_get_len(a) != nexthops_get_len(b)) return false; + nexthops_foreach(a, n, { + if (!nexthops_contains(b, n)) return false; + }); + return true; +} + +void nexthops_copy(nexthops_t *src, nexthops_t *dst) { + for (unsigned i = 0; i < MAX_NEXTHOPS; i++) { + dst->elts[i] = src->elts[i]; + dst->state[i] = src->state[i]; + } + dst->num_elts = src->num_elts; + dst->flags = src->flags; + dst->cur_elts = src->cur_elts; +} + +#endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/core/nexthops.h b/hicn-light/src/hicn/core/nexthops.h new file mode 100644 index 000000000..2a7fc0b32 --- /dev/null +++ b/hicn-light/src/hicn/core/nexthops.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file nexthops.h + * \brief Nexthops + * + * An implementation of the nexthop data structure for the FIB entry. + * + * Note that the position of nexthops in this structure can be reordered. This + * is not an issue for the strategy state since the state if bound to the + * nexthop information, but an external module should not keep any reference to + * the offset of the nexthop. + */ + +#ifndef HICNLIGHT_NEXTHOPS_H +#define HICNLIGHT_NEXTHOPS_H + +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <hicn/util/log.h> + +#include "connection.h" +#include "strategy_vft.h" + +#define _nexthops_var(x) _nexthops_##x + +typedef unsigned nexthop_t; +#define NEXTHOP(x) ((nexthop_t)x) + +#define INVALID_NEXTHOP NEXTHOP(CONNECTION_ID_UNDEFINED) + +/* + * This allows storage within a single integer + * 32 or 64 nexthops should be sufficient + * Eventually replace this with a resizeable vector + */ +#define MAX_NEXTHOPS (sizeof(uint_fast32_t) * 8) + +typedef struct nexthops_s { + unsigned elts[MAX_NEXTHOPS]; + strategy_nexthop_state_t state[MAX_NEXTHOPS]; + size_t num_elts; + + /* + * flags is used during the processing of nexthops by the policy framework, + * and its meaning is local to the related functions. + * It is a mask where a bit set to 1 in position N indicates that the Nth + * elements in the elts array (elts[N]) is disabled. + * The number of enabled next hops is reflected in cur_elts, and it is equal + * to num_elts if no nexthop is disabled. This could be replaced by an + * efficient function counting the number of 1 bits in flags. + */ + uint_fast32_t flags; + size_t cur_elts; +} nexthops_t; + +#define NEXTHOPS_EMPTY \ + (nexthops_t) { \ + .elts = {0}, .state = {STRATEGY_NEXTHOP_STATE_EMPTY}, .num_elts = 0, \ + .flags = 0, .cur_elts = 0, \ + } + +#define nexthops_state(NH, i) ((NH)->state[(i)]) + +#define nexthops_get_len(NH) ((NH)->num_elts) + +#define nexthops_set_len(NH, LEN) \ + do { \ + (NH)->num_elts = LEN; \ + (NH)->cur_elts = LEN; \ + } while (0) + +#define nexthops_get_curlen(NH) ((NH)->cur_elts) + +#define nexthops_inc(NH) \ + do { \ + (NH)->num_elts++; \ + (NH)->cur_elts++; \ + } while (0) + +int nexthops_disable(nexthops_t *nexthops, off_t offset); + +#define nexthops_disable_if(NH, i, condition) \ + do { \ + if (condition) { \ + nexthops_disable((NH), (i)); \ + } \ + } while (0) + +#define nexthops_is_disabled(NH, i) ((NH)->flags & (1 << (i))) + +void nexthops_reset(nexthops_t *nexthops); + +#define nexthops_enumerate(NH, i, X, BODY) \ + do { \ + for ((i) = 0; (i) < nexthops_get_len(NH); (i)++) { \ + if (nexthops_is_disabled((NH), (i))) continue; \ + X = (NH)->elts[(i)]; \ + do { \ + BODY \ + } while (0); \ + } \ + } while (0) + +#define nexthops_foreach(NH, X, BODY) \ + do { \ + unsigned _nexthops_var(i); \ + nexthops_enumerate((NH), _nexthops_var(i), (X), {BODY}); \ + } while (0) + +off_t nexthops_add(nexthops_t *nexthops, nexthop_t nexthop); + +off_t nexthops_remove(nexthops_t *nexthops, nexthop_t nexthop); + +#define nexthops_clear(NH) \ + do { \ + nexthops_set_len(NH, 0); \ + (NH)->flags = 0; \ + } while (0) + +bool nexthops_contains(nexthops_t *nexthops, unsigned nexthop); + +off_t nexthops_find(nexthops_t *nexthops, unsigned nexthop); + +unsigned nexthops_get_one(nexthops_t *nexthops); + +int nexthops_select(nexthops_t *nexthops, off_t i); + +/* + * This selects the first available element, irrespective of the current state + * of flags + */ +#define nexthops_select_first(NH) nexthops_select((NH), 0) + +#ifdef WITH_POLICY + +#define DEFAULT_PRIORITY 0 +#define DISABLED_PRIORITY -1 + +void nexthops_set_priority(nexthops_t *nexthops, nexthop_t nexthop, + int priority); + +void nexthops_set_priority_by_id(nexthops_t *nexthops, off_t i, int priority); + +void nexthops_reset_priority_by_id(nexthops_t *nexthops, off_t i); + +void nexthops_reset_priority(nexthops_t *nexthops, nexthop_t nexthop); + +void nexthops_reset_priorities(nexthops_t *nexthops); + +/* + * returns true if the list of next hops contained in a is the same of b + * returns false otherwise + */ +bool nexthops_equal(nexthops_t *a, nexthops_t *b); + +void nexthops_copy(nexthops_t *src, nexthops_t *dst); + +#endif /* WITH_POLICY */ + +#endif /* HICNLIGHT_NEXTHOPS_H */ diff --git a/hicn-light/src/hicn/core/numberSet.c b/hicn-light/src/hicn/core/numberSet.c deleted file mode 100644 index 106e13be6..000000000 --- a/hicn-light/src/hicn/core/numberSet.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Memory.h> -#include <hicn/hicn-light/config.h> -#include <hicn/core/numberSet.h> -#include <stdio.h> - -#include <parc/assert/parc_Assert.h> - -struct number_set { - Number *arrayOfNumbers; - size_t length; - size_t limit; - unsigned refcount; -}; - -static void numberSet_Expand(NumberSet *set); - -NumberSet *numberSet_Create() { - NumberSet *set = parcMemory_AllocateAndClear(sizeof(NumberSet)); - parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(NumberSet)); - set->arrayOfNumbers = parcMemory_AllocateAndClear(sizeof(Number) * 16); - parcAssertNotNull((set->arrayOfNumbers), - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Number) * 16); - set->length = 0; - set->limit = 16; - set->refcount = 1; - return set; -} - -NumberSet *numberSet_Acquire(const NumberSet *original) { - parcAssertNotNull(original, "Parameter original must be non-null"); - NumberSet *copy = (NumberSet *)original; - copy->refcount++; - return copy; -} - -void numberSet_Release(NumberSet **setPtr) { - parcAssertNotNull(setPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer"); - - NumberSet *set = *setPtr; - parcAssertTrue( - set->refcount > 0, - "Invalid state: calling destroy on an object with 0 reference count"); - set->refcount--; - - if (set->refcount == 0) { - parcMemory_Deallocate((void **)&(set->arrayOfNumbers)); - parcMemory_Deallocate((void **)&set); - *setPtr = NULL; - } -} - -/** - * @function numberSet_AddNoChecks - * @abstract Add a number we know is not already in the set - * @discussion - * Used by other functions that already know the number is unique in the set, - * Does not do the expensive Contains check. - */ -static void numberSet_AddNoChecks(NumberSet *set, Number number) { - if (set->length == set->limit) { - numberSet_Expand(set); - } - - set->arrayOfNumbers[set->length] = number; - set->length++; -} - -bool numberSet_Add(NumberSet *set, Number number) { - parcAssertNotNull(set, "Parameter set must be non-null"); - if (numberSet_Contains(set, number)) { - return false; - } - - numberSet_AddNoChecks(set, number); - return true; -} - -size_t numberSet_Length(const NumberSet *set) { - parcAssertNotNull(set, "Parameter set must be non-null"); - return set->length; -} - -Number numberSet_GetItem(const NumberSet *set, size_t ordinalIndex) { - parcAssertNotNull(set, "Parameter set must be non-null"); - parcAssertTrue(ordinalIndex < set->length, - "Limit beyond end of set, length %zu got %zu", set->length, - ordinalIndex); - - return set->arrayOfNumbers[ordinalIndex]; -} - -bool numberSet_Contains(const NumberSet *set, Number number) { - parcAssertNotNull(set, "Parameter set must be non-null"); - for (size_t i = 0; i < set->length; i++) { - if (set->arrayOfNumbers[i] == number) { - return true; - } - } - return false; -} - -void numberSet_AddSet(NumberSet *destinationSet, const NumberSet *setToAdd) { - parcAssertNotNull(destinationSet, - "Parameter destinationSet must be non-null"); - parcAssertNotNull(setToAdd, "Parameter setToAdd must be non-null"); - - for (size_t i = 0; i < setToAdd->length; i++) { - numberSet_Add(destinationSet, setToAdd->arrayOfNumbers[i]); - } -} - -NumberSet *numberSet_Subtract(const NumberSet *minuend, - const NumberSet *subtrahend) { - // because the underlying ADT is not sorted, this is pretty ineffient, could - // be O(n^2). - - NumberSet *difference = numberSet_Create(); - - for (size_t i = 0; i < minuend->length; i++) { - bool unique = true; - for (size_t j = 0; j < subtrahend->length && unique; j++) { - if (minuend->arrayOfNumbers[i] == subtrahend->arrayOfNumbers[j]) { - unique = false; - } - } - - if (unique) { - numberSet_AddNoChecks(difference, minuend->arrayOfNumbers[i]); - } - } - return difference; -} - -bool numberSet_Equals(const NumberSet *a, const NumberSet *b) { - if (a == NULL && b == NULL) { - return true; - } - - if (a == NULL || b == NULL) { - return false; - } - - if (a->length == b->length) { - for (size_t i = 0; i < a->length; i++) { - bool found = false; - for (size_t j = 0; j < b->length && !found; j++) { - if (a->arrayOfNumbers[i] == b->arrayOfNumbers[j]) { - found = true; - } - } - if (!found) { - return false; - } - } - return true; - } - - return false; -} - -void numberSet_Remove(NumberSet *set, Number number) { - parcAssertNotNull(set, "Parameter set must be non-null"); - for (size_t i = 0; i < set->length; i++) { - if (set->arrayOfNumbers[i] == number) { - set->length--; - if (set->length > 0) { - // move the last element to the removed element to keep the array - // packed. - set->arrayOfNumbers[i] = set->arrayOfNumbers[set->length]; - } - return; - } - } -} - -// ===================================================== - -static void numberSet_Expand(NumberSet *set) { - size_t newlimit = set->limit * 2; - size_t newbytes = newlimit * sizeof(Number); - - set->arrayOfNumbers = parcMemory_Reallocate(set->arrayOfNumbers, newbytes); - set->limit = newlimit; -} diff --git a/hicn-light/src/hicn/core/numberSet.h b/hicn-light/src/hicn/core/numberSet.h deleted file mode 100644 index 91a965d7b..000000000 --- a/hicn-light/src/hicn/core/numberSet.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @brief Stores a set of numbers. - * - * Useful for things like the reverse path of a PIT - * or the forward paths of a FIB. Does not allow duplicates. - * - */ - -#ifndef numberSet_h -#define numberSet_h - -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> - -struct number_set; -typedef struct number_set NumberSet; - -typedef uint32_t Number; - -/** - * @function numberList_Create - * @abstract A new list of numbers - */ -NumberSet *numberSet_Create(void); - -/** - * Obtains a reference counted copy of the original - * The reference count is increased by one. It must be released with - * NumberSet_Release(). - * @param [in] original An allocated NumberSet - * @return non-null The reference counted copy - */ -NumberSet *numberSet_Acquire(const NumberSet *original); - -/** - * Releases one reference count and destroys the memory after last release - * The pointer will be NULLed after release regardless if the memory was - * destroyed. - * @param [in,out] setPtr A pointer to a NumberSet. Will be NULL'd after - * release. - */ -void numberSet_Release(NumberSet **setPtr); - -/** - * @function numberList_Append - * @abstract Add a number to the end of the list - * @discussion - * No check for duplicates is done - * @return true if added, false if a duplicate - */ -bool numberSet_Add(NumberSet *set, Number number); - -/** - * @function numberList_Length - * @abstract The count of numbers in the list - */ -size_t numberSet_Length(const NumberSet *set); - -/** - * @function numberSet_GetItem - * @abstract Retrieves an item based on the ordinal index - * @discussion - * Will assert if the ordinalIndex is out of bounds. - */ -Number numberSet_GetItem(const NumberSet *set, size_t ordinalIndex); - -/** - * @function numberSet_Contains - * @abstract Checks for set membership - * @return true if the set contains the number, false otherwise - */ -bool numberSet_Contains(const NumberSet *set, Number number); - -/** - * @function numberSet_AddSet - * @abstract Adds one set to another set - * @discussion - * Adds <code>setToAdd</code> to <code>destinationSet</code> - * @return true if the set contains the number, false otherwise - */ -void numberSet_AddSet(NumberSet *destinationSet, const NumberSet *setToAdd); - -/** - * @function numberSet_Subtract - * @abstract Computes set difference <code>difference = minuend - - * subtrahend</code>, returns a new number set. - * @discussion - * <code>minuend</code> and <code>subtrahend</code> are not modified. A new - * difference set is created. - * - * Returns the elements in <code>minuend</code> that are not in - * <code>subtrahend</code>. - * - * @param minuend The set from which to subtract - * @param subrahend The set begin removed from minuend - * @return The set difference. May be empty, but will not be NULL. - */ -NumberSet *numberSet_Subtract(const NumberSet *minuend, - const NumberSet *subtrahend); - -/** - * Determine if two NumberSet instances are equal. - * - * Two NumberSet instances are equal if, and only if, - * they are the same size and contain the same elements. Empty sets are - * equal. NULL equals NULL, but does not equal non-NULL. - * - * The following equivalence relations on non-null `NumberSet` instances are - * maintained: - * - * * It is reflexive: for any non-null reference value x, `NumberSet_Equals(x, - * x)` must return true. - * - * * It is symmetric: for any non-null reference values x and y, - * `numberSet_Equals(x, y)` must return true if and only if - * `numberSet_Equals(y, x)` returns true. - * - * * It is transitive: for any non-null reference values x, y, and z, if - * `numberSet_Equals(x, y)` returns true and - * `numberSet_Equals(y, z)` returns true, - * then `numberSet_Equals(x, z)` must return true. - * - * * It is consistent: for any non-null reference values x and y, multiple - * invocations of `numberSet_Equals(x, y)` consistently return true or - * consistently return false. - * - * * For any non-null reference value x, `numberSet_Equals(x, NULL)` must - * return false. - * - * @param a A pointer to a `NumberSet` instance. - * @param b A pointer to a `NumberSet` instance. - * @return true if the two `NumberSet` instances are equal. - */ -bool numberSet_Equals(const NumberSet *a, const NumberSet *b); - -/** - * @function numberSet_Remove - * @abstract Removes the number from the set - */ -void numberSet_Remove(NumberSet *set, Number number); -#endif // numberSet_h diff --git a/hicn-light/src/hicn/core/packet_cache.c b/hicn-light/src/hicn/core/packet_cache.c new file mode 100644 index 000000000..203ad4a63 --- /dev/null +++ b/hicn-light/src/hicn/core/packet_cache.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file packet_cache.c + * \brief Implementation of hICN packet cache + */ + +#include "packet_cache.h" + +pkt_cache_t *pkt_cache_create(size_t cs_size) { + pkt_cache_t *pkt_cache = (pkt_cache_t *)malloc(sizeof(pkt_cache_t)); + + pkt_cache->pit = pit_create(); + if (!pkt_cache->pit) return NULL; + pkt_cache->cs = cs_create(cs_size); + if (!pkt_cache->cs) return NULL; + + pkt_cache->index_by_name = kh_init(pkt_cache_name); + pool_init(pkt_cache->entries, DEFAULT_PKT_CACHE_SIZE, 0); + + return pkt_cache; +} + +void pkt_cache_free(pkt_cache_t *pkt_cache) { + assert(pkt_cache); + + // Free hashmap + const Name *k_name; + unsigned v; + (void)v; + kh_foreach(pkt_cache->index_by_name, k_name, v, { free((Name *)k_name); }); + kh_destroy(pkt_cache_name, pkt_cache->index_by_name); + + // Free pool + pool_free(pkt_cache->entries); + + // Free PIT and CS + pit_free(pkt_cache->pit); + cs_free(pkt_cache->cs); + + free(pkt_cache); +} + +pit_t *pkt_cache_get_pit(pkt_cache_t *pkt_cache) { return pkt_cache->pit; } + +cs_t *pkt_cache_get_cs(pkt_cache_t *pkt_cache) { return pkt_cache->cs; } + +pkt_cache_entry_t *pkt_cache_lookup(pkt_cache_t *pkt_cache, const Name *name, + msgbuf_pool_t *msgbuf_pool, + pkt_cache_lookup_t *lookup_result, + off_t *entry_id, + bool is_serve_from_cs_enabled) { + Name name_key = name_key_factory(name); + khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); + if (k == kh_end(pkt_cache->index_by_name)) { + *lookup_result = PKT_CACHE_LU_NONE; + return NULL; + } + + off_t index = kh_val(pkt_cache->index_by_name, k); + pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, index); + assert(entry); + bool expired = false; + if (entry->has_expire_ts && ticks_now() >= entry->expire_ts) { + expired = true; + } + + if (entry->entry_type == PKT_CACHE_CS_TYPE) { + if (expired) + *lookup_result = PKT_CACHE_LU_DATA_EXPIRED; + else + *lookup_result = PKT_CACHE_LU_DATA_NOT_EXPIRED; + } else { // PKT_CACHE_PIT_TYPE + if (expired) + *lookup_result = PKT_CACHE_LU_INTEREST_EXPIRED; + else + *lookup_result = PKT_CACHE_LU_INTEREST_NOT_EXPIRED; + } + + *entry_id = index; + return entry; +} + +void pkt_cache_cs_remove_entry(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + msgbuf_pool_t *msgbuf_pool, bool is_evicted) { + assert(pkt_cache); + assert(entry); + assert(entry->entry_type == PKT_CACHE_CS_TYPE); + + off_t msgbuf_id = entry->u.cs_entry.msgbuf_id; + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + + Name name_key = name_key_factory(msgbuf_get_name(msgbuf)); + khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); + assert(k != kh_end(pkt_cache->index_by_name)); + free((Name *)kh_key(pkt_cache->index_by_name, k)); + kh_del(pkt_cache_name, pkt_cache->index_by_name, k); + + // Do not update the LRU cache for evicted entries + if (!is_evicted) cs_vft[pkt_cache->cs->type]->remove_entry(pkt_cache, entry); + + pkt_cache->cs->num_entries--; + pool_put(pkt_cache->entries, entry); + + WITH_DEBUG({ + char *name_str = name_ToString(msgbuf_get_name(msgbuf)); + DEBUG("Packet %s removed from CS", name_str); + free(name_str); + }) + + msgbuf_pool_release(msgbuf_pool, &msgbuf); +} + +void pkt_cache_pit_remove_entry(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *entry, const Name *name) { + assert(pkt_cache); + assert(entry); + assert(entry->entry_type == PKT_CACHE_PIT_TYPE); + + Name name_key = name_key_factory(name); + khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); + assert(k != kh_end(pkt_cache->index_by_name)); + free((Name *)kh_key(pkt_cache->index_by_name, k)); + kh_del(pkt_cache_name, pkt_cache->index_by_name, k); + + pool_put(pkt_cache->entries, entry); + + WITH_DEBUG({ + char *name_str = name_ToString(name); + DEBUG("Packet %s removed from PIT", name_str); + free(name_str); + }) +} + +void _pkt_cache_add_to_cs(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf, + off_t msgbuf_id, off_t entry_id) { + entry->u.cs_entry = + (cs_entry_t){.msgbuf_id = msgbuf_id, + .lru = {.prev = INVALID_ENTRY_ID, .next = INVALID_ENTRY_ID}}; + entry->create_ts = ticks_now(); + entry->expire_ts = ticks_now() + msgbuf_get_data_expiry_time(msgbuf); + entry->has_expire_ts = true; + entry->entry_type = PKT_CACHE_CS_TYPE; + + pkt_cache->cs->num_entries++; + + int tail_id = pkt_cache->cs->lru.tail; + int result = cs_vft[pkt_cache->cs->type]->add_entry(pkt_cache, entry_id); + if (result == LRU_EVICTION) { + // Remove tail (already removed from LRU cache) + pkt_cache_entry_t *tail = pkt_cache_entry_at(pkt_cache, tail_id); + assert(tail->entry_type == PKT_CACHE_CS_TYPE); + pkt_cache_cs_remove_entry(pkt_cache, tail, msgbuf_pool, true); + } + + // Acquired by CS + msgbuf_pool_acquire(msgbuf); +} + +void pkt_cache_pit_to_cs(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *interest_entry, + msgbuf_pool_t *msgbuf_pool, msgbuf_t *data_msgbuf, + off_t data_msgbuf_id, off_t entry_id) { + assert(pkt_cache); + assert(interest_entry); + assert(interest_entry->entry_type == PKT_CACHE_PIT_TYPE); + + _pkt_cache_add_to_cs(pkt_cache, interest_entry, msgbuf_pool, data_msgbuf, + data_msgbuf_id, entry_id); +} + +void _pkt_cache_add_to_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + const msgbuf_t *msgbuf) { + entry->u.pit_entry = (pit_entry_t){ + .ingressIdSet = NEXTHOPS_EMPTY, + .egressIdSet = NEXTHOPS_EMPTY, + .fib_entry = NULL, + }; + pit_entry_ingress_add(&entry->u.pit_entry, msgbuf_get_connection_id(msgbuf)); + + entry->create_ts = ticks_now(); + entry->expire_ts = ticks_now() + msgbuf_get_interest_lifetime(msgbuf); + entry->has_expire_ts = true; + entry->entry_type = PKT_CACHE_PIT_TYPE; +} + +void pkt_cache_cs_to_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + msgbuf_pool_t *msgbuf_pool, const msgbuf_t *msgbuf, + off_t msgbuf_id, off_t entry_id) { + assert(pkt_cache); + assert(entry); + assert(entry->entry_type == PKT_CACHE_CS_TYPE); + + // Release data associated with expired CS entry + off_t cs_entry_msgbuf_id = entry->u.cs_entry.msgbuf_id; + msgbuf_t *cs_entry_msgbuf = msgbuf_pool_at(msgbuf_pool, cs_entry_msgbuf_id); + msgbuf_pool_release(msgbuf_pool, &cs_entry_msgbuf); + + cs_vft[pkt_cache->cs->type]->remove_entry(pkt_cache, entry); + _pkt_cache_add_to_pit(pkt_cache, entry, msgbuf); + pkt_cache->cs->num_entries--; +} + +void pkt_cache_update_cs(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, + pkt_cache_entry_t *entry, msgbuf_t *msgbuf, + off_t msgbuf_id) { + assert(pkt_cache); + assert(entry); + assert(entry->entry_type == PKT_CACHE_CS_TYPE); + + // Release previous msgbuf and acquire new one + msgbuf_t *prev_msgbuf = + msgbuf_pool_at(msgbuf_pool, entry->u.cs_entry.msgbuf_id); + msgbuf_pool_release(msgbuf_pool, &prev_msgbuf); + msgbuf_pool_acquire(msgbuf); + + entry->u.cs_entry.msgbuf_id = msgbuf_id; + entry->create_ts = ticks_now(); + entry->expire_ts = ticks_now() + msgbuf_get_data_expiry_time(msgbuf); + entry->has_expire_ts = true; + + cs_vft[pkt_cache->cs->type]->update_entry(pkt_cache, entry); +} + +pkt_cache_entry_t *pkt_cache_add_to_pit(pkt_cache_t *pkt_cache, + const msgbuf_t *msgbuf) { + assert(pkt_cache); + + pkt_cache_entry_t *entry = + pkt_cache_allocate(pkt_cache, msgbuf_get_name(msgbuf)); + _pkt_cache_add_to_pit(pkt_cache, entry, msgbuf); + return entry; +} + +pkt_cache_entry_t *pkt_cache_add_to_cs(pkt_cache_t *pkt_cache, + msgbuf_pool_t *msgbuf_pool, + msgbuf_t *msgbuf, off_t msgbuf_id) { + assert(pkt_cache); + + pkt_cache_entry_t *entry = + pkt_cache_allocate(pkt_cache, msgbuf_get_name(msgbuf)); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + _pkt_cache_add_to_cs(pkt_cache, entry, msgbuf_pool, msgbuf, msgbuf_id, + entry_id); + + return entry; +} + +void pkt_cache_update_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + const msgbuf_t *msgbuf) { + assert(pkt_cache); + assert(entry); + assert(entry->entry_type == PKT_CACHE_PIT_TYPE); + + pit_entry_t *pit_entry = &entry->u.pit_entry; + fib_entry_t *fib_entry = pit_entry_get_fib_entry(pit_entry); + if (fib_entry) + fib_entry_on_timeout(fib_entry, pit_entry_get_egress(pit_entry)); + + _pkt_cache_add_to_pit(pkt_cache, entry, msgbuf); +} + +bool pkt_cache_try_aggregate_in_pit(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *entry, + const msgbuf_t *msgbuf) { + assert(pkt_cache); + assert(entry); + assert(entry->entry_type == PKT_CACHE_PIT_TYPE); + + pit_entry_t *pit_entry = &entry->u.pit_entry; + + // Extend entry lifetime + Ticks expire_ts = ticks_now() + msgbuf_get_interest_lifetime(msgbuf); + if (expire_ts > entry->expire_ts) entry->expire_ts = expire_ts; + + // Check if the reverse path is already present + // in the PIT entry (i.e. it is a retransmission) + unsigned connection_id = msgbuf_get_connection_id(msgbuf); + bool is_aggregated = !pit_entry_ingress_contains(pit_entry, connection_id); + if (is_aggregated) pit_entry_ingress_add(pit_entry, connection_id); + + WITH_DEBUG({ + char *name_str = name_ToString(msgbuf_get_name(msgbuf)); + if (is_aggregated) { + DEBUG("Interest %s already existing (expiry %lu): aggregate", name_str, + entry->expire_ts); + } else { + DEBUG("Interest %s already existing (expiry %lu): retransmit", name_str, + entry->expire_ts); + } + free(name_str); + }) + + return is_aggregated; +} + +nexthops_t *pkt_cache_on_data(pkt_cache_t *pkt_cache, + msgbuf_pool_t *msgbuf_pool, off_t msgbuf_id, + bool is_cs_store_enabled, + bool is_connection_local, bool *wrong_egress, + pkt_cache_verdict_t *verdict) { + assert(pkt_cache); + assert(msgbuf_id_is_valid(msgbuf_id)); + + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA); + + *wrong_egress = false; + off_t entry_id; + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *entry = + pkt_cache_lookup(pkt_cache, msgbuf_get_name(msgbuf), msgbuf_pool, + &lookup_result, &entry_id, true); + + pit_entry_t *pit_entry; + fib_entry_t *fib_entry; + nexthops_t *nexthops = NULL; + nexthops_t *nexthops_copy; + switch (lookup_result) { + case PKT_CACHE_LU_INTEREST_NOT_EXPIRED: + pit_entry = &entry->u.pit_entry; + fib_entry = pit_entry_get_fib_entry(pit_entry); + if (fib_entry) + fib_entry_on_data(fib_entry, pit_entry_get_egress(pit_entry), msgbuf, + entry->create_ts, ticks_now()); + + // Check if the data is coming from the exepected connection + nexthops_t *egressIdSet = pit_entry_get_egress(pit_entry); + unsigned egress_connection = msgbuf_get_connection_id(msgbuf); + if (!nexthops_contains(egressIdSet, egress_connection)) { + *wrong_egress = true; + return NULL; + } + + // XXX TODO : be sure nexthops are valid b/c pit entry is removed + // XXX TODO eventually pass holding structure as parameter + nexthops = pit_entry_get_ingress(pit_entry); + assert(nexthops); + + nexthops_copy = (nexthops_t *)malloc(sizeof(*nexthops_copy)); + *nexthops_copy = *nexthops; + + if (is_cs_store_enabled) { + pkt_cache_pit_to_cs(pkt_cache, entry, msgbuf_pool, msgbuf, msgbuf_id, + entry_id); + *verdict = PKT_CACHE_VERDICT_FORWARD_DATA; + } else { + pkt_cache_pit_remove_entry(pkt_cache, entry, msgbuf_get_name(msgbuf)); + *verdict = PKT_CACHE_VERDICT_CLEAR_DATA; + } + + return nexthops_copy; + + // Data packets are stored in the content store even in the case + // where there is no match in the PIT, to allow applications to push + // content to the forwarder's CS. This behavior is allowed only for + // local faces. + case PKT_CACHE_LU_INTEREST_EXPIRED: + if (is_cs_store_enabled && is_connection_local) { + pkt_cache_pit_to_cs(pkt_cache, entry, msgbuf_pool, msgbuf, msgbuf_id, + entry_id); + *verdict = PKT_CACHE_VERDICT_STORE_DATA; + } else { + pkt_cache_pit_remove_entry(pkt_cache, entry, msgbuf_get_name(msgbuf)); + *verdict = PKT_CACHE_VERDICT_CLEAR_DATA; + } + return NULL; + + case PKT_CACHE_LU_NONE: + *verdict = PKT_CACHE_VERDICT_IGNORE_DATA; + if (is_cs_store_enabled && is_connection_local) { + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, msgbuf_id); + *verdict = PKT_CACHE_VERDICT_STORE_DATA; + } + return NULL; + + case PKT_CACHE_LU_DATA_EXPIRED: + if (is_cs_store_enabled && is_connection_local) { + pkt_cache_update_cs(pkt_cache, msgbuf_pool, entry, msgbuf, msgbuf_id); + *verdict = PKT_CACHE_VERDICT_UPDATE_DATA; + } else { + pkt_cache_cs_remove_entry(pkt_cache, entry, msgbuf_pool, false); + *verdict = PKT_CACHE_VERDICT_CLEAR_DATA; + } + return NULL; + + case PKT_CACHE_LU_DATA_NOT_EXPIRED: + *verdict = PKT_CACHE_VERDICT_IGNORE_DATA; + if (is_cs_store_enabled && is_connection_local) { + pkt_cache_update_cs(pkt_cache, msgbuf_pool, entry, msgbuf, msgbuf_id); + *verdict = PKT_CACHE_VERDICT_UPDATE_DATA; + } + return NULL; + + default: + ERROR("Inivalid packet cache content"); + return NULL; + } +} + +void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, + off_t msgbuf_id, pkt_cache_verdict_t *verdict, + off_t *data_msgbuf_id, pkt_cache_entry_t **entry_ptr, + bool is_serve_from_cs_enabled) { + assert(pkt_cache); + assert(msgbuf_id_is_valid(msgbuf_id)); + + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST); + + off_t entry_id; + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *entry = + pkt_cache_lookup(pkt_cache, msgbuf_get_name(msgbuf), msgbuf_pool, + &lookup_result, &entry_id, is_serve_from_cs_enabled); + *entry_ptr = entry; + + cs_entry_t *cs_entry = NULL; + bool is_cs_miss = true; + bool is_aggregated; + switch (lookup_result) { + case PKT_CACHE_LU_NONE: + *verdict = PKT_CACHE_VERDICT_FORWARD_INTEREST; + break; + + case PKT_CACHE_LU_DATA_NOT_EXPIRED: + if (!is_serve_from_cs_enabled) goto PKT_CACHE_LU_DATA_EXPIRED; + + cs_entry = &entry->u.cs_entry; + *data_msgbuf_id = cs_entry->msgbuf_id; + + *verdict = PKT_CACHE_VERDICT_FORWARD_DATA; + is_cs_miss = false; + break; + + case PKT_CACHE_LU_INTEREST_NOT_EXPIRED: + is_aggregated = pkt_cache_try_aggregate_in_pit(pkt_cache, entry, msgbuf); + + *verdict = is_aggregated ? PKT_CACHE_VERDICT_AGGREGATE_INTEREST + : PKT_CACHE_VERDICT_RETRANSMIT_INTEREST; + break; + + case PKT_CACHE_LU_INTEREST_EXPIRED: + pkt_cache_update_pit(pkt_cache, entry, msgbuf); + + *verdict = PKT_CACHE_VERDICT_INTEREST_EXPIRED_FORWARD_INTEREST; + break; + + case PKT_CACHE_LU_DATA_EXPIRED: + PKT_CACHE_LU_DATA_EXPIRED: + pkt_cache_cs_to_pit(pkt_cache, entry, msgbuf_pool, msgbuf, msgbuf_id, + entry_id); + + *verdict = PKT_CACHE_VERDICT_DATA_EXPIRED_FORWARD_INTEREST; + break; + + default: + *verdict = PKT_CACHE_VERDICT_ERROR; + } + is_cs_miss ? cs_miss(pkt_cache->cs) : cs_hit(pkt_cache->cs); +} + +void pkt_cache_cs_clear(pkt_cache_t *pkt_cache) { + assert(pkt_cache); + + const Name *k_name; + unsigned v_pool_pos; + kh_foreach(pkt_cache->index_by_name, k_name, v_pool_pos, + { + khiter_t k = + kh_get_pkt_cache_name(pkt_cache->index_by_name, k_name); + assert(k != kh_end(pkt_cache->index_by_name)); + + pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, v_pool_pos); + if (entry->entry_type == PKT_CACHE_CS_TYPE) { + // Remove from hashmap + free((Name *)kh_key(pkt_cache->index_by_name, k)); + kh_del(pkt_cache_name, pkt_cache->index_by_name, k); + + // Remove from pool + pool_put(pkt_cache->entries, entry); + } + }) + + // Re-create CS + cs_clear(pkt_cache->cs); +} + +size_t pkt_cache_get_size(pkt_cache_t *pkt_cache) { + uint64_t hashmap_size = kh_size(pkt_cache->index_by_name); + return hashmap_size; +} + +size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache) { + return pkt_cache->cs->num_entries; +} + +size_t pkt_cache_get_num_cs_stale_entries(pkt_cache_t *pkt_cache) { + size_t num_stale_entries = 0; + Ticks now = ticks_now(); + pkt_cache_entry_t *entry; + + pool_foreach(pkt_cache->entries, entry, { + if (entry->entry_type == PKT_CACHE_CS_TYPE && entry->has_expire_ts && + now >= entry->expire_ts) { + num_stale_entries++; + } + }); + + return num_stale_entries; +} + +int pkt_cache_set_cs_size(pkt_cache_t *pkt_cache, size_t size) { + if (pkt_cache->cs->num_entries > size) return -1; + + pkt_cache->cs->max_size = size; + return 0; +} + +size_t pkt_cache_get_pit_size(pkt_cache_t *pkt_cache) { + uint64_t hashmap_size = kh_size(pkt_cache->index_by_name); + uint64_t pit_size = hashmap_size - pkt_cache->cs->num_entries; + return pit_size; +} + +void pkt_cache_log(pkt_cache_t *pkt_cache) { + uint64_t hashmap_size = kh_size(pkt_cache->index_by_name); + uint64_t pit_size = hashmap_size - pkt_cache->cs->num_entries; + DEBUG("Packet cache: total size = %lu, PIT size = %lu, CS size = %u", + hashmap_size, pit_size, pkt_cache->cs->num_entries); + + cs_log(pkt_cache->cs); +} diff --git a/hicn-light/src/hicn/core/packet_cache.h b/hicn-light/src/hicn/core/packet_cache.h new file mode 100644 index 000000000..ccfc83b97 --- /dev/null +++ b/hicn-light/src/hicn/core/packet_cache.h @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file packet_cache.h + * \brief hICN packet cache + * + * The packet cache is a data structure that merges together the PIT and the CS, + * to which it holds a reference. + * It contains PIT and CS entries, indexed in a hashtable by hICN packet names. + * + * Each entry has shared fields, e.g. entry type (PIT or CS) and timestamps, + * which are used by both PIT and CS entries. In addition, a C union holds + * the PIT or CS specific fields. + * + * Having a single entry that can hold PIT or CS entries allows to reduce + * the number of lookups. + */ + +#ifndef HICNLIGHT_PACKET_CACHE_H +#define HICNLIGHT_PACKET_CACHE_H + +#include "content_store.h" +#include "pit.h" +#include "msgbuf_pool.h" +#include "../base/khash.h" +#include "../content_store/lru.h" + +#define DEFAULT_PKT_CACHE_SIZE 2048 + +typedef enum { PKT_CACHE_PIT_TYPE, PKT_CACHE_CS_TYPE } pkt_cache_entry_type_t; + +/** + * @brief Return a Name that can be used as key for hash table lookups. + * The returned Name is a copy of the input one but it is "memsetted" + * to ensure successful hash calculation. + */ +static inline Name name_key_factory(const Name *name) { + NameBitvector *content_name = name_GetContentName(name); + + Name name_key; + memset(&name_key, 0, sizeof(Name)); + + name_key.content_name = *content_name; + name_key.segment = name_GetSegment(name); + name_key.name_hash = name_HashCode(name); + + return name_key; +} + +KHASH_INIT(pkt_cache_name, const Name *, unsigned, 1, name_HashCode, + name_Equals); + +typedef struct { + pkt_cache_entry_type_t entry_type; + + Ticks create_ts; + Ticks expire_ts; + // TODO(eloparco): Is it necessary? + // Now it is always set to true + bool has_expire_ts; + + union { + pit_entry_t pit_entry; + cs_entry_t cs_entry; + } u; +} pkt_cache_entry_t; + +typedef struct { + pit_t *pit; + cs_t *cs; + pkt_cache_entry_t *entries; + kh_pkt_cache_name_t *index_by_name; +} pkt_cache_t; + +/** + * @brief Create a new packet cache. + * + * @return pkt_cache_t* The newly created packet cache + */ +pkt_cache_t *pkt_cache_create(size_t cs_size); + +#define _pc_var(x) _pkt_cache_##x +/** + * @brief Add an entry with the specified name to the packet cache. + * + * @param[in] pkt_cache Pointer to the msgbuf pool data structure to use. + * @param[in, out] entry Empty entry that will be used to return the + * allocated one from the msgbuf pool. + * * @param[in] name Name to use + */ +static inline pkt_cache_entry_t *pkt_cache_allocate( + const pkt_cache_t *pkt_cache, const Name *name) { + pkt_cache_entry_t *entry = NULL; + pool_get(pkt_cache->entries, entry); + assert(entry); + + off_t id = entry - pkt_cache->entries; + int res; + + // Generate the key (starting from the name) to use in the name hash table + NameBitvector *nb = name_GetContentName(name); + Name *name_copy = (Name *)calloc(1, sizeof(Name)); + name_copy->content_name = *nb; + name_copy->segment = name_GetSegment(name); + name_copy->name_hash = name_HashCode(name); + + // Add in name hash table + khiter_t k = kh_put_pkt_cache_name(pkt_cache->index_by_name, name_copy, &res); + assert(res != -1); + kh_value(pkt_cache->index_by_name, k) = id; + + return entry; +} + +/** + * @brief Free a packet cache data structure. + * + * @param[in] pkt_cache Pointer to packet cache data structure to free. + */ +void pkt_cache_free(pkt_cache_t *pkt_cache); + +/** + * @brief Get a reference to the PIT data structure contained in the packet + * cache. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to get the + * PIT from. + */ +pit_t *pkt_cache_get_pit(pkt_cache_t *pkt_cache); + +/** + * @brief Get a reference to the CS data structure contained in the packet + * cache. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to get the CS + * from. + */ +cs_t *pkt_cache_get_cs(pkt_cache_t *pkt_cache); + +/** + * @brief Return the total packet cache size (i.e. PIT + CS). + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + */ +size_t pkt_cache_get_size(pkt_cache_t *pkt_cache); + +/** + * @brief Return the number of stale entries (i.e. expired) in the CS. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + */ +size_t pkt_cache_get_num_cs_stale_entries(pkt_cache_t *pkt_cache); + +/** + * @brief Change the maximum capacity of the content store (LRU eviction will be + * used after reaching the provided size) + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in] size Maximum size of the content store + * @return int 0 if success, -1 if the provided maximum size is smaller than the + * number of elements currently stored in the CS + */ +int pkt_cache_set_cs_size(pkt_cache_t *pkt_cache, size_t size); + +/** + * @brief Return the content store size. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + */ +size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache); + +/** + * @brief Return the PIT size. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + */ +size_t pkt_cache_get_pit_size(pkt_cache_t *pkt_cache); + +typedef enum { + PKT_CACHE_LU_INTEREST_NOT_EXPIRED, + PKT_CACHE_LU_INTEREST_EXPIRED, + PKT_CACHE_LU_DATA_NOT_EXPIRED, + PKT_CACHE_LU_DATA_EXPIRED, + PKT_CACHE_LU_NONE +} pkt_cache_lookup_t; + +typedef enum { + PKT_CACHE_VERDICT_FORWARD_INTEREST, + PKT_CACHE_VERDICT_AGGREGATE_INTEREST, + PKT_CACHE_VERDICT_RETRANSMIT_INTEREST, + PKT_CACHE_VERDICT_FORWARD_DATA, + PKT_CACHE_VERDICT_INTEREST_EXPIRED_FORWARD_INTEREST, + PKT_CACHE_VERDICT_DATA_EXPIRED_FORWARD_INTEREST, + PKT_CACHE_VERDICT_STORE_DATA, + PKT_CACHE_VERDICT_CLEAR_DATA, + PKT_CACHE_VERDICT_UPDATE_DATA, + PKT_CACHE_VERDICT_IGNORE_DATA, + PKT_CACHE_VERDICT_ERROR +} pkt_cache_verdict_t; + +#define pkt_cache_entry_get_create_ts(E) ((E)->create_ts) +#define pkt_cache_entry_get_expire_ts(E) ((E)->expire_ts) +#define pkt_cache_entry_set_expire_ts(E, EXPIRY_TIME) \ + (entry)->expire_ts = EXPIRY_TIME +#define pkt_cache_get_entry_id(pkt_cache, entry) (entry - pkt_cache->entries) +#define pkt_cache_entry_at(pkt_cache, id) (&(pkt_cache)->entries[id]) +#define pkt_cache_at(pkt_cache, i) (pkt_cache->entries + i) + +/** + * @brief Retrieve from the packet cache the entry associated with the specified + * name. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to retrieve + * the entry from + * @param[in] name Packet name to use for the lookup + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use + * @param[in, out] lookup_result Pointer to store the result of the lookup + * @param[in, out] entry_id Pointer to store the entry_id in case of a lookup + * match + * @param[in] is_serve_from_cs_enabled Boolean to specify if the forwarder is + * allowed to serve contents from the CS + * @return pkt_cache_entry_t* Entry retrieved, NULL if none found + */ +pkt_cache_entry_t *pkt_cache_lookup(pkt_cache_t *pkt_cache, const Name *name, + msgbuf_pool_t *msgbuf_pool, + pkt_cache_lookup_t *lookup_result, + off_t *entry_id, + bool is_serve_from_cs_enabled); + +/** + * @brief Clear the content of the CS. + * + * @param pkt_cache Pointer to the packet cache data structure to use + */ +void pkt_cache_cs_clear(pkt_cache_t *pkt_cache); + +/** + * @brief Log packet cache statistics. + * + * @param pkt_cache Pointer to the packet cache data structure to use + */ +void pkt_cache_log(pkt_cache_t *pkt_cache); + +// TODO(eloparco): To implement +void pkt_cache_print(const pkt_cache_t *pkt_cache); + +/************** Packet cache entry operations *************/ + +/** + * @brief Remove a content store entry from the packet cache. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in] entry Pointer to the content store entry to remove + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use + * @param[in] is_evicted Boolean to specify if the content store entry has + * already been evicted from the LRU cache + */ +void pkt_cache_cs_remove_entry(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + msgbuf_pool_t *msgbuf_pool, bool is_evicted); + +/** + * @brief Remove a PIT entry from the packet cache. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in] entry Pointer to the PITe entry to remove + * @param[in] name Name associated with the PIT entry to remove + */ +void pkt_cache_pit_remove_entry(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *entry, const Name *name); + +/** + * @brief Convert a PIT entry to a CS entry. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in, out] entry Pointer to the PIT entry to replace + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use + * @param[in] msgbuf Pointer to the msgbuf associated with the CS entry to + * insert + * @param[in] msgbuf_id Msgbuf ID (i.e. ID in the msgbuf pool) associated with + * the CS entry to insert + * @param[in] entry_id Entry ID (i.e. ID in the packet cache pool of entries) + * associated with the PIT entry to replace + */ +void pkt_cache_pit_to_cs(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf, + off_t msgbuf_id, off_t entry_id); + +/** + * @brief Convert a CS entry to a PIT entry. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in, out] entry Pointer to the CS entry to replace + * @param[in] msgbuf Pointer to the msgbuf associated with the PIT entry to + * insert + * @param[in] msgbuf_id Msgbuf ID (i.e. ID in the msgbuf pool) associated with + * the PIT entry to insert + * @param[in] entry_id Entry ID (i.e. ID in the packet cache pool of entries) + * associated with the CS entry to replace + */ +void pkt_cache_cs_to_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + msgbuf_pool_t *msgbuf_pool, const msgbuf_t *msgbuf, + off_t msgbuf_id, off_t entry_id); + +/** + * @brief Add PIT entry to the packet cache. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in] msgbuf Pointer to the msgbuf associated with the PIT entry to + * insert + * @return pkt_cache_entry_t* Pointer to the packet cache (PIT) entry created + */ +pkt_cache_entry_t *pkt_cache_add_to_pit(pkt_cache_t *pkt_cache, + const msgbuf_t *msgbuf); + +/** + * @brief Add CS entry to the packet cache. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use + * @param[in] msgbuf Pointer to the msgbuf associated with the CS entry to + * insert + * @param[in] msgbuf_id Msgbuf ID (i.e. ID in the msgbuf pool) associated with + * the CS entry to insert + * @return pkt_cache_entry_t* Pointer to the packet cache (CS) entry created + */ +pkt_cache_entry_t *pkt_cache_add_to_cs(pkt_cache_t *pkt_cache, + msgbuf_pool_t *msgbuf_pool, + msgbuf_t *msgbuf, off_t msgbuf_id); + +/** + * @brief Update PIT entry in the packet cache in case of an expired PIT entry. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in, out] entry Pointer to the PIT entry to update + * @param[in] msgbuf Pointer to the msgbuf associated with the PIT entry to + * update + */ +void pkt_cache_update_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, + const msgbuf_t *msgbuf); + +/** + * @brief Update CS entry in the packet cache. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use + * @param[in, out] entry Pointer to the CS entry to update + * @param[in] msgbuf Pointer to the msgbuf associated with the CS entry to + * update + * @param msgbuf_id Msgbuf ID (i.e. ID in the msgbuf pool) associated with the + * CS entry to update + */ +void pkt_cache_update_cs(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, + pkt_cache_entry_t *entry, msgbuf_t *msgbuf, + off_t msgbuf_id); + +/** + * @brief Update PIT entry in the packet cache in case of retransmission or + * aggregation. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in, out] entry Pointer to the PIT entry to update + * @param[in] msgbuf Pointer to the msgbuf associated with the PIT entry to + * update + * @return true If aggregation (interest sent from a connection not stored in + * the PIT entry) + * @return false If retransmission (interest sent from a connection already + * stored in the PIT entry) + */ +bool pkt_cache_try_aggregate_in_pit(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *entry, + const msgbuf_t *msgbuf); + +/************ Handle data/interest packets received *******/ + +/** + * @brief Handle data packet reception. + * @details Perform packet cache lookup and execute operations based on it. If: + * - INTEREST not expired: Convert PIT entry to CS entry; return the + * nexthops (that can be used to forward the data + * packet now stored in the CS) + * - INTEREST expired: Convert PIT entry to CS entry + * - DATA expired/not expired: Update the CS + * - No match: Add data packet to CS + */ +nexthops_t *pkt_cache_on_data(pkt_cache_t *pkt_cache, + msgbuf_pool_t *msgbuf_pool, off_t msgbuf_id, + bool is_cs_store_enabled, + bool is_connection_local, bool *wrong_egress, + pkt_cache_verdict_t *verdict); + +/** + * @brief Handle interest packet reception. + * @details Perform packet cache lookup and execute operations based on it. If: + * - No match: Do nothing + * - DATA not expired: get data message from CS + * - INTEREST not expired: Aggregate or retransmit the interest received; + * - INTEREST expired: Update the PIT; + * - DATA expired: Convert CS entry to PIT entry; + */ +void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, + off_t msgbuf_id, pkt_cache_verdict_t *verdict, + off_t *data_msgbuf_id, pkt_cache_entry_t **entry_ptr, + bool is_serve_from_cs_enabled); + +/************** Content Store *****************************/ + +typedef struct { + const char *name; + void (*initialize)(cs_t *cs); + void (*finalize)(cs_t *cs); + int (*add_entry)(pkt_cache_t *pkt_cache, off_t entry_id); + void (*update_entry)(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry); + int (*remove_entry)(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry); +} cs_ops_t; +extern const cs_ops_t *const cs_vft[]; + +/** + * @brief Initialize the virtual function table used for the + * CS cache strategy (e.g. LRU). + * + */ +#define DECLARE_CS(NAME) \ + const cs_ops_t cs_##NAME = { \ + .name = #NAME, \ + .initialize = cs_##NAME##_initialize, \ + .finalize = cs_##NAME##_finalize, \ + .add_entry = cs_##NAME##_add_entry, \ + .update_entry = cs_##NAME##_update_entry, \ + .remove_entry = cs_##NAME##_remove_entry, \ + } + +#endif /* HICNLIGHT_PACKET_CACHE_H */ diff --git a/hicn-light/src/hicn/core/pit.c b/hicn-light/src/hicn/core/pit.c new file mode 100644 index 000000000..322e53674 --- /dev/null +++ b/hicn-light/src/hicn/core/pit.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * The pending interest table. + * + * Interest aggregation strategy: + * - The first Interest for a name is forwarded + * - A second Interest for a name from a different reverse path may be + * aggregated + * - A second Interest for a name from an existing Interest is forwarded + * - The Interest Lifetime is like a subscription time. A reverse path entry is + * removed once the lifetime is exceeded. + * - Whan an Interest arrives or is aggregated, the Lifetime for that reverse + * hop is extended. As a simplification, we only keep a single lifetime not per + * reverse hop. + * + */ + +#include "pit.h" + +Ticks pit_calculate_lifetime(pit_t* pit, const msgbuf_t* msgbuf) { + uint64_t lifetime = msgbuf_get_lifetime(msgbuf); + if (lifetime == 0) lifetime = NSEC_TO_TICKS(DEFAULT_INTEREST_LIFETIME); + + return ticks_now() + lifetime; +} + +/* This is only used as a hint for first allocation, as the table is resizeable + */ +#define DEFAULT_PIT_SIZE 65535 + +pit_t* _pit_create(size_t init_size, size_t max_size) { + pit_t* pit = malloc(sizeof(pit_t)); + if (!pit) return NULL; + + if (init_size == 0) init_size = DEFAULT_PIT_SIZE; + + pit->max_size = max_size; + return pit; +} + +void pit_free(pit_t* pit) { + assert(pit); + free(pit); +} + +// void pit_print(const pit_t *pit) { +// const Name *k; +// unsigned v; +// pit_entry_t * entry; +// Ticks expire_ts; + +// printf("*** PIT ***\n"); +// kh_foreach(pit->index_by_name, k, v, { +// char *name_str = name_ToString(k); +// entry = pit_at(pit, v); +// expire_ts = pit_entry_get_expire_ts(entry); +// printf("%s\t\t\texpire=%lu\n", name_str, expire_ts); +// free(name_str); +// }) +// } diff --git a/hicn-light/src/hicn/core/pit.h b/hicn-light/src/hicn/core/pit.h new file mode 100644 index 000000000..f2e901490 --- /dev/null +++ b/hicn-light/src/hicn/core/pit.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file pit.h + * @brief hICN Pending Interest Table (PIT) + */ + +#ifndef HICNLIGHT_PIT_H +#define HICNLIGHT_PIT_H + +#include <hicn/core/fib.h> + +typedef struct { + nexthops_t ingressIdSet; + nexthops_t egressIdSet; + fib_entry_t* fib_entry; +} pit_entry_t; + +#define pit_entry_get_ingress(E) (&((E)->ingressIdSet)) +#define pit_entry_get_egress(E) (&((E)->egressIdSet)) +#define pit_entry_get_fib_entry(E) ((E)->fib_entry) +#define pit_entry_set_fib_entry(E, FIB_ENTRY) ((E)->fib_entry = FIB_ENTRY) + +#define pit_entry_ingress_add(E, NH) \ + nexthops_add(pit_entry_get_ingress(E), (NH)) + +#define pit_entry_ingress_contains(E, NH) \ + nexthops_contains(pit_entry_get_ingress(E), (NH)) + +#define pit_entry_egress_add(E, NH) nexthops_add(pit_entry_get_egress(E), (NH)) + +typedef struct { + // TODO(eloparco): How to handle PIT size? + size_t max_size; +} pit_t; + +#define DEFAULT_INTEREST_LIFETIME 4000000000ULL + +Ticks pit_calculate_lifetime(pit_t* pit, const msgbuf_t* msgbuf); + +/** + * @brief Allocate a new PIT data structure (extended parameters) + * + * @param init_size Initial size (0 = default) + * @param max_size Maximum size (0 = unbounded) + * + * @return pit_t* Newly allocated PIT data structure + */ +pit_t* _pit_create(size_t init_size, size_t max_size); + +/** + * @brief Allocate a new PIT data structure + * + * @return pit_t* Newly allocated PIT data structure + */ +#define pit_create() _pit_create(0, 0) + +void pit_free(pit_t* pit); + +#endif /* HICNLIGHT_PIT_H */ diff --git a/hicn-light/src/hicn/core/policy_stats.c b/hicn-light/src/hicn/core/policy_stats.c new file mode 100644 index 000000000..1acbccf69 --- /dev/null +++ b/hicn-light/src/hicn/core/policy_stats.c @@ -0,0 +1,189 @@ +#ifdef WITH_POLICY_STATS + +// This has to be included first because of _GNU_SOURCE +#include <hicn/core/forwarder.h> + +#include <hicn/core/connection_table.h> +#include <hicn/base/loop.h> +#include <hicn/util/log.h> +#include <hicn/core/ticks.h> +#include <hicn/policy.h> +#include <hicn/core/fib.h> + +#include "policy_stats.h" + +#define ALPHA 0.9 +#define STATS_INTERVAL 1000 /* ms */ + +static int policy_stats_mgr_tick(void* mgr_arg, int fd, void* data) { + policy_stats_mgr_t* mgr = mgr_arg; + assert(mgr); + assert(!data); + + uint64_t now = ticks_now(); + + /* Loop over FIB entries to compute statistics from counters */ + const fib_t* fib = forwarder_get_fib(mgr->forwarder); + fib_entry_t* entry; + + fib_foreach_entry(fib, entry, { + policy_stats_update(&entry->policy_stats, &entry->policy_counters, now); + }); + + return 0; +} + +int policy_stats_mgr_initialize(policy_stats_mgr_t* mgr, void* forwarder) { + mgr->forwarder = forwarder; + + loop_timer_create(&mgr->timer, MAIN_LOOP, mgr, policy_stats_mgr_tick, NULL); + if (!mgr->timer) { + ERROR("Error allocating prefix stats mgr timer."); + return -1; + } + + if (loop_timer_register(mgr->timer, STATS_INTERVAL) < 0) { + ERROR("Error registering prefix stats mgr timer."); + return -1; + } + + return 0; +} + +void policy_stats_mgr_finalize(policy_stats_mgr_t* mgr) { + loop_event_unregister(mgr->timer); + loop_event_free(mgr->timer); +} + +void policy_stats_on_retransmission(const policy_stats_mgr_t* mgr, + policy_counters_t* counters, + const nexthops_t* nexthops) { + connection_table_t* table = forwarder_get_connection_table(mgr->forwarder); + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { +#ifdef WITH_POLICY + const connection_t* conn = connection_table_at(table, nexthop); + + if (connection_has_tag(conn, POLICY_TAG_WIRED)) + counters->wired.num_losses++; + if (connection_has_tag(conn, POLICY_TAG_WIFI)) counters->wifi.num_losses++; + if (connection_has_tag(conn, POLICY_TAG_CELLULAR)) + counters->cellular.num_losses++; +#endif /* WITH_POLICY */ + counters->all.num_losses++; + }); +} + +#define UPDATE_TAG_STATS(TAG, NAME) \ + do { \ + if (connection_has_tag(conn, TAG)) { \ + counters->NAME.num_packets++; \ + counters->NAME.num_bytes += msg_size; \ + stats->NAME.latency = \ + ALPHA * stats->NAME.latency + (1 - ALPHA) * (double)rtt; \ + counters->NAME.latency_idle = 0; \ + } \ + } while (0) + +/* Update statistic counters upon Data packet reception */ +void policy_stats_on_data(const policy_stats_mgr_t* mgr, policy_stats_t* stats, + policy_counters_t* counters, + const nexthops_t* nexthops, const msgbuf_t* msgbuf, + Ticks rtt) { +#ifdef WITH_POLICY + forwarder_t* forwarder = mgr->forwarder; + connection_table_t* table = forwarder_get_connection_table(forwarder); +#endif /* WITH_POLICY */ + + size_t msg_size = msgbuf_get_len(msgbuf); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { +#ifdef WITH_POLICY + const connection_t* conn = connection_table_at(table, nexthop); + if (!conn) continue; + + UPDATE_TAG_STATS(POLICY_TAG_WIRED, wired); + UPDATE_TAG_STATS(POLICY_TAG_WIFI, wifi); + UPDATE_TAG_STATS(POLICY_TAG_CELLULAR, cellular); +#endif /* WITH_POLICY */ + }); + + stats->all.latency = ALPHA * stats->all.latency + (1 - ALPHA) * (double)rtt; + counters->all.latency_idle = 0; + counters->all.num_packets++; + counters->all.num_bytes += msg_size; +} + +void policy_stats_on_timeout(const policy_stats_mgr_t* mgr, + policy_counters_t* counters, + const nexthops_t* nexthops) { +#ifdef WITH_POLICY + connection_table_t* table = forwarder_get_connection_table(mgr->forwarder); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + const connection_t* conn = connection_table_at(table, nexthop); + if (!conn) continue; + if (connection_has_tag(conn, POLICY_TAG_WIRED)) + counters->wired.num_losses++; + if (connection_has_tag(conn, POLICY_TAG_WIFI)) counters->wifi.num_losses++; + if (connection_has_tag(conn, POLICY_TAG_CELLULAR)) + counters->cellular.num_losses++; + }); +#endif /* WITH_POLICY */ + + counters->all.num_losses++; +} + +#define UPDATE_TYPE(TYPE) \ + do { \ + /* (a) throughput */ \ + if (counters->TYPE.num_bytes > 0) { \ + throughput = counters->TYPE.num_bytes / (now - counters->last_update); \ + throughput = throughput * 8 / 1024; \ + if (throughput < 0) throughput = 0; \ + } else { \ + throughput = 0; \ + } \ + stats->TYPE.throughput = \ + ALPHA * stats->TYPE.throughput + (1 - ALPHA) * throughput; \ + \ + /* (b) loss rate */ \ + if ((counters->TYPE.num_losses > 0) && (counters->TYPE.num_packets > 0)) { \ + loss_rate = counters->TYPE.num_losses / counters->TYPE.num_packets; \ + loss_rate *= 100; \ + } else { \ + loss_rate = 0; \ + } \ + stats->TYPE.loss_rate = \ + ALPHA * stats->TYPE.loss_rate + (1 - ALPHA) * loss_rate; \ + \ + /* (c) latency */ \ + counters->TYPE.latency_idle++; \ + if (counters->TYPE.latency_idle > 1) stats->TYPE.latency = 0; \ + \ + /* (d) Reset counters */ \ + counters->TYPE.num_bytes = 0; \ + counters->TYPE.num_losses = 0; \ + counters->TYPE.num_packets = 0; \ + } while (0) + +void policy_stats_update(policy_stats_t* stats, policy_counters_t* counters, + uint64_t now) { + double throughput; + double loss_rate; + + if (now == counters->last_update) return; + +#ifdef WITH_POLICY + UPDATE_TYPE(wired); + UPDATE_TYPE(wifi); + UPDATE_TYPE(cellular); +#endif /* WITH_POLICY */ + UPDATE_TYPE(all); + + counters->last_update = now; +} + +#endif /* WITH_POLICY_STATS */ diff --git a/hicn-light/src/hicn/core/policy_stats.h b/hicn-light/src/hicn/core/policy_stats.h new file mode 100644 index 000000000..fa12b51cb --- /dev/null +++ b/hicn-light/src/hicn/core/policy_stats.h @@ -0,0 +1,93 @@ + +#ifndef HICNLIGHT_POLICY_STATS_H +#define HICNLIGHT_POLICY_STATS_H + +#ifdef WITH_POLICY_STATS + +#include <hicn/policy.h> +#include "../base/loop.h" + +typedef struct policy_stats_mgr_s { + void* forwarder; + event_t* timer; +} policy_stats_mgr_t; + +#if 0 + +/* PER-INTERFACE POLICY STATS */ + +typedef struct { + float throughput; + float latency; + float loss_rate; +} interface_stats_t; + +/* POLICY STATS */ + +typedef struct { + interface_stats_t wired; + interface_stats_t wifi; + interface_stats_t cellular; + interface_stats_t all; +} policy_stats_t; + +typedef struct { + uint32_t num_packets; + uint32_t num_bytes; + uint32_t num_losses; + uint32_t latency_idle; +} interface_counters_t; + +typedef struct { + interface_counters_t wired; + interface_counters_t wifi; + interface_counters_t cellular; + interface_counters_t all; + uint64_t last_update; +} policy_counters_t; + +#define INTERFACE_STATS_EMPTY \ + (interface_stats_t) { .throughput = 0, .latency = 0, .loss_rate = 0, } + +#define POLICY_STATS_EMPTY \ + (policy_stats_t) { \ + .wired = INTERFACE_STATS_EMPTY, .wifi = INTERFACE_STATS_EMPTY, \ + .cellular = INTERFACE_STATS_EMPTY, .all = INTERFACE_STATS_EMPTY, \ + } + +#define INTERFACE_COUNTERS_EMPTY \ + (interface_counters_t) { \ + .num_packets = 0, .num_bytes = 0, .num_losses = 0, .latency_idle = 0, \ + } + +#define POLICY_COUNTERS_EMPTY \ + (policy_counters_t) { \ + .wired = INTERFACE_COUNTERS_EMPTY, .wifi = INTERFACE_COUNTERS_EMPTY, \ + .cellular = INTERFACE_COUNTERS_EMPTY, .all = INTERFACE_COUNTERS_EMPTY, \ + .last_update = 0, \ + } +#endif + +int policy_stats_mgr_initialize(policy_stats_mgr_t* mgr, void* forwarder); + +void policy_stats_mgr_finalize(policy_stats_mgr_t* mgr); + +void policy_stats_on_retransmission(const policy_stats_mgr_t* mgr, + policy_counters_t* countrs, + const nexthops_t* nexthops); + +void policy_stats_on_data(const policy_stats_mgr_t* mgr, policy_stats_t* stats, + policy_counters_t* counters, + const nexthops_t* nexthops, const msgbuf_t* msgbuf, + Ticks rtt); + +void policy_stats_on_timeout(const policy_stats_mgr_t* mgr, + policy_counters_t* counters, + const nexthops_t* nexthops); + +void policy_stats_update(policy_stats_t* stats, policy_counters_t* counters, + uint64_t now); + +#endif /* WITH_POLICY_STATS */ + +#endif /* HICNLIGHT_POLICY_STATS_H */ diff --git a/hicn-light/src/hicn/core/strategy.c b/hicn-light/src/hicn/core/strategy.c new file mode 100644 index 000000000..3716cd585 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file strategy.c + * \brief Implementation of hICN forwarding strategy + */ + +#include "nexthops.h" +#include "strategy.h" +#include "strategy_vft.h" + +int strategy_initialize(strategy_entry_t *entry, const void *forwarder) { + return strategy_vft[entry->type]->initialize(entry, forwarder); +} + +nexthops_t *strategy_lookup_nexthops(strategy_entry_t *entry, + nexthops_t *nexthops, + const msgbuf_t *msgbuf) { + return strategy_vft[entry->type]->lookup_nexthops(entry, nexthops, msgbuf); +} + +int strategy_add_nexthop(strategy_entry_t *entry, nexthops_t *nexthops, + off_t offset) { + return strategy_vft[entry->type]->add_nexthop(entry, nexthops, offset); +} + +int strategy_remove_nexthop(strategy_entry_t *entry, nexthops_t *nexthops, + off_t offset) { + return strategy_vft[entry->type]->remove_nexthop(entry, nexthops, offset); +} + +int strategy_on_data(strategy_entry_t *entry, nexthops_t *nexthops, + const nexthops_t *data_nexthops, const msgbuf_t *msgbuf, + Ticks pitEntryCreation, Ticks objReception) { + return strategy_vft[entry->type]->on_data( + entry, nexthops, data_nexthops, msgbuf, pitEntryCreation, objReception); +} + +int strategy_on_timeout(strategy_entry_t *entry, nexthops_t *nexthops, + const nexthops_t *timeout_nexthops) { + return strategy_vft[entry->type]->on_timeout(entry, nexthops, + timeout_nexthops); +} diff --git a/hicn-light/src/hicn/core/strategy.h b/hicn-light/src/hicn/core/strategy.h new file mode 100644 index 000000000..9ce75c51d --- /dev/null +++ b/hicn-light/src/hicn/core/strategy.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file strategy.h + * \brief hICN forwarding strategy + */ +#ifndef HICNLIGHT_STRATEGY_H +#define HICNLIGHT_STRATEGY_H + +/* + * Forwarding strategy + * + * The forwarding strategy decides to elect one or several next hops among those + * available in the FIB entry, after an eventual application of the policy. This + * means it should be aware of the different flags set in the nexthops_t data + * structure by previous forwarding steps, that might have excluded certain + * nexthops. + * + * A strategy is defined by its type and comes with : + * - options, initialized at setup and that might eventually be updated (this + * is allowed on a per-strategy basis. + * - a state (eventually) empty, that is used to inform its decisions, and + * might be updated for each interest sent (lookup_nexthops), data received + * (on_data) or timeout event (on_timeout). + * + * All this information (type, options, state) is made available through a + * strategy_entry_t which is stored together with nexthops in the FIB entry. + * + * Per-nexthop strategy informaton is stored in the nexthops table itself. As it + * would be difficult and suboptimal to provide a correct strategy-dependent + * initialization in the FIB nad nexthops data structures, it is thus the + * responsibility of the forwarding strategy to initialize its state and nexthop + * related state when appropriate (eg. at initialization, or when a nexthop is + * added). + */ + +#include "nexthops.h" +#include "strategy_vft.h" + +typedef struct strategy_entry_s { + const void *forwarder; + strategy_type_t type; + strategy_options_t options; + strategy_state_t state; +} strategy_entry_t; + +int strategy_initialize(strategy_entry_t *entry, const void *forwarder); + +nexthops_t *strategy_lookup_nexthops(strategy_entry_t *entry, + nexthops_t *nexthops, + const msgbuf_t *msgbuf); + +int strategy_add_nexthop(strategy_entry_t *entry, nexthops_t *nexthops, + off_t offset); + +int strategy_remove_nexthop(strategy_entry_t *entry, nexthops_t *nexthops, + off_t offset); + +int strategy_on_data(strategy_entry_t *entry, nexthops_t *nexthops, + const nexthops_t *data_nexthops, const msgbuf_t *msgbuf, + Ticks pitEntryCreation, Ticks objReception); + +int strategy_on_timeout(strategy_entry_t *entry, nexthops_t *nexthops, + const nexthops_t *timeout_nexthops); + +#endif /* HICNLIGHT_STRATEGY_H */ diff --git a/hicn-light/src/hicn/core/strategy_vft.c b/hicn-light/src/hicn/core/strategy_vft.c new file mode 100644 index 000000000..dcfda5c78 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy_vft.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file strategy_vft.c + * \brief Implementation of hICN forwarding strategy VFT + */ + +#include "strategy_vft.h" + +extern const strategy_ops_t strategy_load_balancer; +extern const strategy_ops_t strategy_random; +extern const strategy_ops_t strategy_replication; +extern const strategy_ops_t strategy_bestpath; +extern const strategy_ops_t strategy_low_latency; + +const strategy_ops_t *const strategy_vft[] = { + [STRATEGY_TYPE_LOADBALANCER] = &strategy_load_balancer, + [STRATEGY_TYPE_RANDOM] = &strategy_random, + [STRATEGY_TYPE_REPLICATION] = &strategy_replication, + [STRATEGY_TYPE_BESTPATH] = &strategy_bestpath, +#if 0 + [STRATEGY_TYPE_LOW_LATENCY] = &strategy_low_latency, +#endif +}; diff --git a/hicn-light/src/hicn/core/strategy_vft.h b/hicn-light/src/hicn/core/strategy_vft.h new file mode 100644 index 000000000..0256cba57 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy_vft.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * \file strategy_vft.h + * \brief hICN forwarding strategy VFT + */ +#ifndef HICNLIGHT_STRATEGY_VFT_H +#define HICNLIGHT_STRATEGY_VFT_H + +#include "msgbuf.h" + +#include "../strategies/best_path.h" +#include "../strategies/load_balancer.h" +#include "../strategies/low_latency.h" +#include "../strategies/random.h" +#include "../strategies/replication.h" + +typedef union { + strategy_load_balancer_options_t load_balancer; + strategy_low_latency_options_t low_latency; + strategy_random_options_t random; + strategy_replication_options_t replication; + strategy_bestpath_options_t bestpath; +} strategy_options_t; + +typedef struct { +#ifdef WITH_POLICY + int priority; +#endif /* WITH_POLICY */ + union { + strategy_load_balancer_nexthop_state_t load_balancer; + strategy_low_latency_nexthop_state_t low_latency; + strategy_random_nexthop_state_t random; + strategy_replication_nexthop_state_t replication; + strategy_bestpath_nexthop_state_t bestpath; + }; +} strategy_nexthop_state_t; + +#define STRATEGY_NEXTHOP_STATE_EMPTY \ + { \ + 0, { \ + { 0 } \ + } \ + } + +typedef union { + strategy_load_balancer_state_t load_balancer; + strategy_low_latency_state_t low_latency; + strategy_random_state_t random; + strategy_replication_state_t replication; + strategy_bestpath_state_t bestpath; +} strategy_state_t; +// XXX This has to be merged with nexthops +// XXX How to avoid errors due to pool id reuse (eg on_data) ? + +/** + * @typedef strategy_ops_t + * @abstract Forwarding strategy implementation + * @constant receiveObject is called when we receive an object and have a + * measured round trip time. This allows a strategy to update its performance + * data. + * @constant lookupNexthop Find the set of nexthops to use for the Interest. + * May be empty, should not be NULL. Must be destroyed. + * @constant addNexthop Add a nexthop to the list of available nexthops with a + * routing protocol-specific cost. + * @constant destroy cleans up the strategy, freeing all memory and state. A + * strategy is reference counted, so the final destruction only happens after + * the last reference is released. + * @discussion <#Discussion#> + */ + +struct strategy_entry_s; +struct nexthops_s; + +typedef struct { + const char *name; + + int (*initialize)(struct strategy_entry_s *entry, const void *forwarder); + + int (*finalize)(struct strategy_entry_s *entry); + + struct nexthops_s *(*lookup_nexthops)(struct strategy_entry_s *entry, + struct nexthops_s *nexthops, + const msgbuf_t *msgbuf); + + int (*add_nexthop)(struct strategy_entry_s *strategy, + struct nexthops_s *nexthops, off_t offset); + + int (*remove_nexthop)(struct strategy_entry_s *entry, + struct nexthops_s *nexthops, off_t offset); + + int (*on_data)(struct strategy_entry_s *entry, struct nexthops_s *nexthops, + const struct nexthops_s *data_nexthops, const msgbuf_t *msgbuf, + Ticks pitEntryCreation, Ticks objReception); + + int (*on_timeout)(struct strategy_entry_s *entry, struct nexthops_s *nexthops, + const struct nexthops_s *timeout_nexthops); + +} strategy_ops_t; + +extern const strategy_ops_t *const strategy_vft[]; + +#define DECLARE_STRATEGY(NAME) \ + const strategy_ops_t strategy_##NAME = { \ + .name = #NAME, \ + .initialize = strategy_##NAME##_initialize, \ + .finalize = strategy_##NAME##_finalize, \ + .add_nexthop = strategy_##NAME##_add_nexthop, \ + .remove_nexthop = strategy_##NAME##_remove_nexthop, \ + .lookup_nexthops = strategy_##NAME##_lookup_nexthops, \ + .on_data = strategy_##NAME##_on_data, \ + .on_timeout = strategy_##NAME##_on_timeout, \ + } + +#endif /* HICNLIGHT_STRATEGY_VFT_H */ diff --git a/hicn-light/src/hicn/core/streamBuffer.c b/hicn-light/src/hicn/core/streamBuffer.c index c30139498..401b7c873 100644 --- a/hicn-light/src/hicn/core/streamBuffer.c +++ b/hicn-light/src/hicn/core/streamBuffer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: diff --git a/hicn-light/src/hicn/core/streamBuffer.h b/hicn-light/src/hicn/core/streamBuffer.h index 27e793176..0caa10bea 100644 --- a/hicn-light/src/hicn/core/streamBuffer.h +++ b/hicn-light/src/hicn/core/streamBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: diff --git a/hicn-light/src/hicn/core/subscription.c b/hicn-light/src/hicn/core/subscription.c new file mode 100644 index 000000000..0c4949f26 --- /dev/null +++ b/hicn-light/src/hicn/core/subscription.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + */ + +#include "subscription.h" +#include <hicn/base/vector.h> +#include <hicn/util/log.h> + +/*----------------------------------------------------------------------------* + * Topics and events + *----------------------------------------------------------------------------*/ + +bool topics_contains(hc_topics_t topic_list, hc_topic_t topic) { + return ((topic_list) & (topic)); +} + +#define topic_is_set(topic_list, topic_index) \ + ((topic_list) & (1 << (topic_index))) + +const char *event_str[] = { +#define _(x) [EVENT_##x] = #x, + foreach_event_type +#undef _ +}; + +/*----------------------------------------------------------------------------* + * Subscriptions + *----------------------------------------------------------------------------*/ + +struct subscription_table_s { + unsigned *table[TOPIC_N]; +}; + +subscription_table_t *subscription_table_create() { + subscription_table_t *subscriptions = malloc(sizeof(subscription_table_t)); + for (int i = 0; i < NUM_TOPICS; i++) + vector_init(subscriptions->table[i], 0, 0); + + return subscriptions; +} + +void subscription_table_free(subscription_table_t *subscriptions) { + for (int i = 0; i < NUM_TOPICS; i++) vector_free(subscriptions->table[i]); + free(subscriptions); +} + +int subscription_table_add_topics_for_connection( + subscription_table_t *subscriptions, hc_topics_t topics, + unsigned connection_id) { + bool is_subscription_already_present = false; + for (int topic_index = 0; topic_index < NUM_TOPICS; topic_index++) { + if (topic_is_set(topics, topic_index)) { + int num_duplicates = vector_remove_unordered( + subscriptions->table[topic_index], connection_id); + + int ret = vector_push(subscriptions->table[topic_index], connection_id); + if (ret < 0) { + ERROR("Unable to perform subscription for connection %d, topic %s", + connection_id, object_str(topic_index)); + return -1; + } + + if (num_duplicates > 0) { + DEBUG("Connection %d had already a subscription for topic %s", + connection_id, object_str(topic_index)); + is_subscription_already_present = true; + } + } + } + return is_subscription_already_present ? -2 : 0; +} + +int subscription_table_remove_topics_for_connection( + subscription_table_t *subscriptions, hc_topics_t topics, + unsigned connection_id) { + int num_subscriptions_removed = 0; + for (int topic_index = 0; topic_index < NUM_TOPICS; topic_index++) { + if (topic_is_set(topics, topic_index)) { + int num_duplicates = vector_remove_unordered( + subscriptions->table[topic_index], connection_id); + if (num_duplicates <= 0) { + continue; + } + num_subscriptions_removed++; + } + } + return num_subscriptions_removed; +} + +hc_topics_t subscription_table_get_topics_for_connection( + subscription_table_t *subscriptions, unsigned connection_id) { + hc_topics_t topics = 0; + for (int topic_index = 0; topic_index < NUM_TOPICS; topic_index++) { + unsigned *conn_id; + bool found = false; + vector_foreach(subscriptions->table[topic_index], conn_id, { + if (*conn_id == connection_id) { + found = true; + break; + } + }); + if (found) topics |= (1 << topic_index); + } + return topics; +} + +unsigned *subscription_table_get_connections_for_topic( + subscription_table_t *subscriptions, hc_topic_t topic) { + int topic_index = object_from_topic(topic); + return subscriptions->table[topic_index]; +} + +void subscription_table_print(subscription_table_t *subscriptions) { + for (int topic_index = OBJECT_UNDEFINED + 1; topic_index < NUM_TOPICS; + topic_index++) { + printf("topic %s (%lu subscription/s) from connection/s: [ ", + object_str(topic_index), + (unsigned long)vector_len(subscriptions->table[topic_index])); + unsigned *connection_id; + vector_foreach(subscriptions->table[topic_index], connection_id, + { printf("%d ", *connection_id); }); + printf("]\n"); + } +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/core/subscription.h b/hicn-light/src/hicn/core/subscription.h new file mode 100644 index 000000000..74ddd9e18 --- /dev/null +++ b/hicn-light/src/hicn/core/subscription.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + */ + +#ifndef HICNLIGHT_SUBSCRIPTION_H +#define HICNLIGHT_SUBSCRIPTION_H + +#include <hicn/ctrl/api.h> +#include <stddef.h> + +/*----------------------------------------------------------------------------* + * Topics + *----------------------------------------------------------------------------*/ + +bool topics_contains(hc_topics_t topic_list, hc_topic_t topic); + +/*----------------------------------------------------------------------------* + * Subscriptions + *----------------------------------------------------------------------------*/ + +typedef struct subscription_table_s subscription_table_t; + +subscription_table_t *subscription_table_create(); + +void subscription_table_free(subscription_table_t *subscriptions); + +/** + * @brief Add topic subscriptions for a connection. + * + * @param subscriptions The pointer to the subscription table + * @param topics Topics the connection wants to subscribe to + * @param connection_id Identifier of the connection + * @return int 0 for success, -1 for error, -2 if already esisting subscription + * for at least one of the topic for + */ +int subscription_table_add_topics_for_connection( + subscription_table_t *subscriptions, hc_topics_t topics, + unsigned connection_id); + +/** + * @brief Remove topic subscriptions for a connection. + * + * @param subscriptions The pointer to the subscription table + * @param topics Topics the connection wants to unsubscribe to + * @param connection_id Identifier of the connection + * @return int Number of removed subscriptions + */ +int subscription_table_remove_topics_for_connection( + subscription_table_t *subscriptions, hc_topics_t topics, + unsigned connection_id); + +/** + * @brief Get the topics a connection has subscribed to. + * + * @param subscriptions The pointer to the subscription table + * @param connection_id Identifier of the connection + * @return hc_topics_t + */ +hc_topics_t subscription_table_get_topics_for_connection( + subscription_table_t *subscriptions, unsigned connection_id); + +/** + * @brief Get the connections that have a subscription for the specified topic. + * + * @param subscriptions The pointer to the subscription table + * @param topic Topic to retrieve the subscriptions for + * @return unsigned* Array containing the connection ids associated with the + * specified topic + */ +unsigned *subscription_table_get_connections_for_topic( + subscription_table_t *subscriptions, hc_topic_t topic); + +/** + * @brief Print the subscription table containing, for each topic, the list + * of connections with a subsctiption. + * + * @param subscriptions The pointer to the subscription table + */ +void subscription_table_print(subscription_table_t *subscriptions); + +#endif // HICNLIGHT_SUBSCRIPTION_H
\ No newline at end of file diff --git a/hicn-light/src/hicn/core/system.h b/hicn-light/src/hicn/core/system.h index be6c3e7cf..860133dd3 100644 --- a/hicn-light/src/hicn/core/system.h +++ b/hicn-light/src/hicn/core/system.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -25,13 +25,12 @@ #define system_h #include <hicn/core/forwarder.h> -#include <hicn/utils/interfaceSet.h> /** * @function system_Interfaces * @abstract The system network interfaces */ -InterfaceSet *system_Interfaces(Forwarder *forwarder); +InterfaceSet *system_Interfaces(forwarder_t *forwarder); /** * Returns the MTU of the named interface @@ -43,7 +42,7 @@ InterfaceSet *system_Interfaces(Forwarder *forwarder); * @return positive the MTU the kernel reports * */ -unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName); +unsigned system_InterfaceMtu(forwarder_t *forwarder, const char *interfaceName); /** * Returns the LINK address of the specified interface @@ -55,6 +54,6 @@ unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName); * @retval null The interface does not exist * */ -Address *system_GetMacAddressByName(Forwarder *forwarder, +Address *system_GetMacAddressByName(forwarder_t *forwarder, const char *interfaceName); #endif diff --git a/hicn-light/src/hicn/core/ticks.h b/hicn-light/src/hicn/core/ticks.h index 8750abde5..0955569df 100644 --- a/hicn-light/src/hicn/core/ticks.h +++ b/hicn-light/src/hicn/core/ticks.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -25,7 +25,42 @@ #define __STDC_FORMAT_MACROS #include <stdint.h> +#include <time.h> + +#include <sys/param.h> // HZ + +#ifdef __APPLE__ +#include <mach/clock.h> +#include <mach/mach.h> +#define HZ 1000 +#endif typedef uint64_t Ticks; +// these will all be a little off because its all integer division +#define NSEC_PER_TICK ((1000000000ULL) / HZ) +#define NSEC_TO_TICKS(nsec) ((nsec < NSEC_PER_TICK) ? 1 : nsec / NSEC_PER_TICK) + +#define TICKS_TO_NSEC(ticks) ((1000000000ULL) * ticks / HZ) + +static inline Ticks ticks_now() { +#if __linux__ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + return ts.tv_sec * 1000 + ts.tv_nsec / 1e6; +#elif _WIN32 + struct timespec ts; + _clock_gettime(TIME_UTC, &ts); + return ts.tv_sec * 1000 + ts.tv_nsec / 1e6; +#else + clock_serv_t clockService; + mach_timespec_t ts; + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clockService); + clock_get_time(clockService, &ts); + mach_port_deallocate(mach_task_self(), clockService); +#endif + + return ts.tv_sec * 1000 + ts.tv_nsec / 1e6; +} + #endif // ticks_h diff --git a/hicn-light/src/hicn/core/wldr.c b/hicn-light/src/hicn/core/wldr.c index ad3663d0d..aa1dbf4f9 100644 --- a/hicn-light/src/hicn/core/wldr.c +++ b/hicn-light/src/hicn/core/wldr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,93 +13,100 @@ * limitations under the License. */ -#include <parc/assert/parc_Assert.h> -#include <parc/logging/parc_LogReporterTextStdout.h> #include <hicn/core/connection.h> #include <hicn/core/forwarder.h> #include <hicn/core/wldr.h> #include <stdint.h> #include <stdio.h> -struct wldr_buffer { - Message *message; +typedef struct { + msgbuf_t *msgbuf; uint8_t rtx_counter; -}; - -typedef struct wldr_buffer WldrBuffer; +} wldr_buffer_t; -struct wldr_state { +struct wldr_s { uint16_t expected_label; uint16_t next_label; - WldrBuffer *buffer[BUFFER_SIZE]; + wldr_buffer_t *buffer[BUFFER_SIZE]; }; -Wldr *wldr_Init() { - Wldr *wldr = parcMemory_AllocateAndClear(sizeof(Wldr)); +wldr_t *wldr_create() { +#if 0 + wldr_t * wldr = parcMemory_AllocateAndClear(sizeof(Wldr)); parcAssertNotNull(wldr, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(Wldr)); wldr->expected_label = 1; wldr->next_label = 1; for (int i = 0; i < BUFFER_SIZE; i++) { - WldrBuffer *entry = parcMemory_AllocateAndClear(sizeof(WldrBuffer)); + wldr_buffer_t *entry = parcMemory_AllocateAndClear(sizeof(wldr_buffer_t)); parcAssertNotNull( entry, - "WldrBuffer init: parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(WldrBuffer)); - entry->message = NULL; + "wldr_buffer_t init: parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(wldr_buffer_t)); + entry->msgbuf = NULL; entry->rtx_counter = 0; wldr->buffer[i] = entry; } return wldr; +#else + return NULL; +#endif } -void wldr_ResetState(Wldr *wldr) { +void wldr_resset_state(wldr_t *wldr) { +#if 0 wldr->expected_label = 1; wldr->next_label = 1; for (int i = 0; i < BUFFER_SIZE; i++) { - wldr->buffer[i]->message = NULL; + wldr->buffer[i]->msgbuf = NULL; wldr->buffer[i]->rtx_counter = 0; } +#endif } -void wldr_Destroy(Wldr **wldrPtr) { - Wldr *wldr = *wldrPtr; +void wldr_free(wldr_t *wldr) { +#if 0 + wldr_t * wldr = *wldrPtr; for (unsigned i = 0; i < BUFFER_SIZE; i++) { - if (wldr->buffer[i]->message != NULL) { - message_Release(&(wldr->buffer[i]->message)); + if (wldr->buffer[i]->msgbuf != NULL) { + message_Release(&(wldr->buffer[i]->msgbuf)); parcMemory_Deallocate((void **)&(wldr->buffer[i])); } } parcMemory_Deallocate((void **)&wldr); *wldrPtr = NULL; +#endif } -static void _wldr_RetransmitPacket(Wldr *wldr, const Connection *conn, +#if 0 +static void _wldr_RetransmitPacket(wldr_t * wldr, const connection_t * conn, uint16_t label) { - if (wldr->buffer[label % BUFFER_SIZE]->message == NULL) { + if (wldr->buffer[label % BUFFER_SIZE]->msgbuf == NULL) { // the required message for retransmission is not in the buffer return; } if (wldr->buffer[label % BUFFER_SIZE]->rtx_counter < MAX_RTX) { - Message *msg = wldr->buffer[label % BUFFER_SIZE]->message; + msgbuf_t *msg = wldr->buffer[label % BUFFER_SIZE]->msgbuf; message_SetWldrLabel(msg, wldr->next_label); - if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->message != NULL) { - message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message)); + if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf != NULL) { + msgbuf_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf)); } - wldr->buffer[wldr->next_label % BUFFER_SIZE]->message = msg; + wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf = msg; wldr->buffer[wldr->next_label % BUFFER_SIZE]->rtx_counter = wldr->buffer[label % BUFFER_SIZE]->rtx_counter + 1; - message_Acquire(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message); + message_Acquire(wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf); wldr->next_label++; connection_ReSend(conn, msg, false); } } +#endif -static void _wldr_SendWldrNotificaiton(Wldr *wldr, const Connection *conn, - Message *message, uint16_t expected_lbl, +#if 0 +static void _wldr_SendWldrNotification(wldr_t * wldr, const connection_t * conn, + msgbuf_t *msgbuf, uint16_t expected_lbl, uint16_t received_lbl) { // here we need to create a new packet that is used to send the wldr // notification to the prevoius hop. the destionation address of the @@ -113,38 +120,43 @@ static void _wldr_SendWldrNotificaiton(Wldr *wldr, const Connection *conn, // this way the notification packet will be dispaced to the right connection // at the next hop. - Message *notification = - message_CreateWldrNotification(message, expected_lbl, received_lbl); + msgbuf_t *notification = + message_CreateWldrNotification(msgbuf, expected_lbl, received_lbl); parcAssertNotNull(notification, "Got null from CreateWldrNotification"); connection_ReSend(conn, notification, true); } +#endif -void wldr_SetLabel(Wldr *wldr, Message *message) { +void wldr_set_label(wldr_t *wldr, msgbuf_t *msgbuf) { +#if 0 // in this function we send the packet for the first time // 1) we set the wldr label - message_SetWldrLabel(message, wldr->next_label); + message_SetWldrLabel(msgbuf, wldr->next_label); // 2) we store the pointer to packet in the buffer - if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->message != NULL) { + if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf != NULL) { // release an old message if necessary - message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message)); + message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf)); } // we need to acquire the message to avoid that it gets destroyed - message_Acquire(message); + message_Acquire(msgbuf); - wldr->buffer[wldr->next_label % BUFFER_SIZE]->message = message; + wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf = msgbuf; wldr->buffer[wldr->next_label % BUFFER_SIZE]->rtx_counter = 0; wldr->next_label++; if (wldr->next_label == 0) // we alwasy skip label 0 beacause it means that wldr is not active wldr->next_label++; +#endif } -void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message) { - if (message_HasWldr(message)) { +void wldr_detect_losses(wldr_t *wldr, const connection_t *connection, + const msgbuf_t *msgbuf) { +#if 0 + if (message_HasWldr(msgbuf)) { // this is a normal wldr packet - uint16_t pkt_lbl = (uint16_t)message_GetWldrLabel(message); + uint16_t pkt_lbl = (uint16_t)message_GetWldrLabel(msgbuf); if (pkt_lbl != wldr->expected_label) { // if the received packet label is 1 and the expected packet label > // pkt_lbl usually we are in the case where a remote note disconnected for @@ -153,7 +165,7 @@ void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message) { // synch the labels if ((pkt_lbl != 1) || (wldr->expected_label < pkt_lbl)) { - _wldr_SendWldrNotificaiton(wldr, conn, message, wldr->expected_label, + _wldr_SendWldrNotificaiton(wldr, conn, msgbuf, wldr->expected_label, pkt_lbl); } @@ -165,12 +177,14 @@ void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message) { wldr->expected_label++; // for the next_label we want to skip 0 } } +#endif } -void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn, - Message *message) { - uint16_t expected_lbl = (uint16_t)message_GetWldrExpectedLabel(message); - uint16_t received_lbl = (uint16_t)message_GetWldrLastReceived(message); +void wldr_handle_notification(wldr_t *wldr, const connection_t *connection, + const msgbuf_t *msgbuf) { +#if 0 + uint16_t expected_lbl = (uint16_t)message_GetWldrExpectedLabel(msgbuf); + uint16_t received_lbl = (uint16_t)message_GetWldrLastReceived(msgbuf); if ((wldr->next_label - expected_lbl) > BUFFER_SIZE) { // the packets are not in the buffer anymore return; @@ -179,4 +193,5 @@ void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn, _wldr_RetransmitPacket(wldr, conn, expected_lbl); expected_lbl++; } +#endif } diff --git a/hicn-light/src/hicn/core/wldr.h b/hicn-light/src/hicn/core/wldr.h index e21889f63..7eccf39cd 100644 --- a/hicn-light/src/hicn/core/wldr.h +++ b/hicn-light/src/hicn/core/wldr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -18,7 +18,7 @@ #include <hicn/hicn-light/config.h> #include <hicn/core/connection.h> -#include <hicn/core/message.h> +#include <hicn/core/msgbuf.h> #define BUFFER_SIZE 8192 #define MAX_RTX 3 @@ -34,19 +34,19 @@ // ATTENTION!!! in order to detect a notificaiton the // source and destination ports must be set to 0 -struct wldr_state; -typedef struct wldr_state Wldr; +typedef struct wldr_s wldr_t; -Wldr *wldr_Init(); +wldr_t *wldr_create(); -void wldr_Destroy(Wldr **wldrPtr); +void wldr_free(wldr_t *wldr); -void wldr_ResetState(Wldr *wldr); +void wldr_reset_state(wldr_t *wldr); -void wldr_SetLabel(Wldr *wldr, Message *message); +void wldr_set_label(wldr_t *wldr, msgbuf_t *msgbuf); -void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message); +void wldr_detect_losses(wldr_t *wldr, const connection_t *connection, + const msgbuf_t *msgbuf); -void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn, - Message *message); +void wldr_handle_notification(wldr_t *wldr, const connection_t *connection, + const msgbuf_t *msgbuf); #endif // wldr_h diff --git a/hicn-light/src/hicn/io/CMakeLists.txt b/hicn-light/src/hicn/io/CMakeLists.txt index cc4f7371f..68a5baec5 100644 --- a/hicn-light/src/hicn/io/CMakeLists.txt +++ b/hicn-light/src/hicn/io/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -12,46 +12,22 @@ # limitations under the License. list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/addressPair.h - ${CMAKE_CURRENT_SOURCE_DIR}/ioOperations.h - ${CMAKE_CURRENT_SOURCE_DIR}/listener.h - ${CMAKE_CURRENT_SOURCE_DIR}/listenerSet.h - ${CMAKE_CURRENT_SOURCE_DIR}/tcpListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicnListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/udpTunnel.h - ${CMAKE_CURRENT_SOURCE_DIR}/tcpTunnel.h - ${CMAKE_CURRENT_SOURCE_DIR}/udpConnection.h - ${CMAKE_CURRENT_SOURCE_DIR}/udpListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/streamConnection.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicnTunnel.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicnConnection.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/addressPair.c - ${CMAKE_CURRENT_SOURCE_DIR}/ioOperations.c - ${CMAKE_CURRENT_SOURCE_DIR}/listenerSet.c - ${CMAKE_CURRENT_SOURCE_DIR}/streamConnection.c - ${CMAKE_CURRENT_SOURCE_DIR}/tcpListener.c - ${CMAKE_CURRENT_SOURCE_DIR}/tcpTunnel.c - ${CMAKE_CURRENT_SOURCE_DIR}/udpConnection.c - ${CMAKE_CURRENT_SOURCE_DIR}/udpListener.c - ${CMAKE_CURRENT_SOURCE_DIR}/udpTunnel.c + ${CMAKE_CURRENT_SOURCE_DIR}/base.c + ${CMAKE_CURRENT_SOURCE_DIR}/hicn.c + ${CMAKE_CURRENT_SOURCE_DIR}/tcp.c + ${CMAKE_CURRENT_SOURCE_DIR}/udp.c ) -if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - list(APPEND SOURCE_FILES - io/hicnTunnel.c - io/hicnConnection.c - io/hicnListener.c - ) -endif() - -set(TO_INSTALL_HEADER_FILES - ${TO_INSTALL_HEADER_FILES} - ${HEADER_FILES} - PARENT_SCOPE -) +#if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") +# list(APPEND SOURCE_FILES +# io/hicnTunnel.c +# io/hicnConnection.c +# io/hicnListener.c +# ) +#endif() set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/io/addressPair.c b/hicn-light/src/hicn/io/addressPair.c deleted file mode 100644 index f9451f900..000000000 --- a/hicn-light/src/hicn/io/addressPair.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/io/addressPair.h> - -struct address_pair { - Address *local; - Address *remote; -}; - -static void _addressPair_Destroy(AddressPair **addressPairPtr) { - AddressPair *pair = *addressPairPtr; - - addressDestroy(&pair->local); - addressDestroy(&pair->remote); -} - -parcObject_ExtendPARCObject(AddressPair, _addressPair_Destroy, NULL, - addressPair_ToString, addressPair_Equals, NULL, - addressPair_HashCode, NULL); - -parcObject_ImplementAcquire(addressPair, AddressPair); - -parcObject_ImplementRelease(addressPair, AddressPair); - -AddressPair *addressPair_Create(const Address *local, const Address *remote) { - parcAssertNotNull(local, "Parameter local must be non-null"); - parcAssertNotNull(remote, "Parameter remote must be non-null"); - - AddressPair *pair = parcObject_CreateInstance(AddressPair); - parcAssertNotNull(pair, "Got null from parcObject_Create()"); - - pair->local = addressCopy(local); - pair->remote = addressCopy(remote); - - return pair; -} - -bool addressPair_Equals(const AddressPair *a, const AddressPair *b) { - if (a == b) { - return true; - } - if (a == NULL || b == NULL) { - return false; - } - - if (addressEquals(a->local, b->local)) { - if (addressEquals(a->remote, b->remote)) { - return true; - } - } - - return false; -} - -bool addressPair_EqualsAddresses(const AddressPair *a, const Address *local, - const Address *remote) { - if (a == NULL || local == NULL || remote == NULL) { - return false; - } - - if (addressEquals(a->local, local)) { - if (addressEquals(a->remote, remote)) { - return true; - } - } - - return false; -} - -char *addressPair_ToString(const AddressPair *pair) { - parcAssertNotNull(pair, "Parameter pair must be non-null"); - - char *local = addressToString(pair->local); - char *remote = addressToString(pair->remote); - - char *output; - int failure = asprintf(&output, "{ .local=%s, .remote=%s }", local, remote); - parcAssertTrue(failure > -1, "Error on asprintf"); - - parcMemory_Deallocate((void **)&local); - parcMemory_Deallocate((void **)&remote); - - return output; -} - -const Address *addressPair_GetLocal(const AddressPair *pair) { - parcAssertNotNull(pair, "Parameter pair must be non-null"); - return pair->local; -} - -const Address *addressPair_GetRemote(const AddressPair *pair) { - parcAssertNotNull(pair, "Parameter pair must be non-null"); - return pair->remote; -} - -/** - * @function addressPair_HashCode - * @abstract Hash useful for tables. Consistent with Equals. - * @discussion - * Returns a non-cryptographic hash that is consistent with equals. That is, - * if a == b, then hash(a) == hash(b). - * - */ -PARCHashCode addressPair_HashCode(const AddressPair *pair) { - PARCHashCode hashpair[2]; - hashpair[0] = addressHashCode(pair->local); - hashpair[1] = addressHashCode(pair->remote); - return parcHashCode_Hash((const uint8_t *)hashpair, sizeof(hashpair)); -} diff --git a/hicn-light/src/hicn/io/addressPair.h b/hicn-light/src/hicn/io/addressPair.h deleted file mode 100644 index f1b72e0dc..000000000 --- a/hicn-light/src/hicn/io/addressPair.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * Used to identify a connection between a specific local address and - * a specific remote address. - */ - -#ifndef address_Pair_h -#define address_Pair_h - -#include <hicn/utils/address.h> - -struct address_pair; -typedef struct address_pair AddressPair; - -/** - * @function addressPair_Create - * @abstract Creates and address pair. There is no restriction on the address - * types. - * @discussion - * Creates an ordered pair of addresses, where the first is considered the - * "local" address and the second is the "remote" address. Those designations - * are purely a convention used to name them, and does not imply any specifici - * types of operations. - * - * The two addresses may be of any address types (e.g. IPv4, IPv6, Local, - * Ethernet). However, some functions that use an AddressPair may require that - * the local and remote addresses be the same type. - * - */ -AddressPair *addressPair_Create(const Address *local, const Address *remote); - -/** - * Returns a reference counted copy of the address pair - * - * Increments the reference count and returns the same address pair - * - * @param [in] addressPair An allocated address pair - * - * @retval non-null A reference counted copy - * @retval null An error - */ -AddressPair *addressPair_Acquire(const AddressPair *addressPair); - -/** - * Releases a reference count to the object - * - * Decrements the reference count and destroys the object when it reaches 0. - */ -void addressPair_Release(AddressPair **pairPtr); - -/** - * Determine if two AddressPair instances are equal. - * - * Two AddressPair instances are equal if, and only if, the local and remote - * addresses are identical. Equality is determined by addressEquals(a->local, - * b->local) and Adress_Equals(a->remote, b->remote). - * - * The following equivalence relations on non-null `AddressPair` instances are - * maintained: - * - * * It is reflexive: for any non-null reference value x, - * `AddressPair_Equals(x, x)` must return true. - * - * * It is symmetric: for any non-null reference values x and y, - * `addressPair_Equals(x, y)` must return true if and only if - * `addressPair_Equals(y, x)` returns true. - * - * * It is transitive: for any non-null reference values x, y, and z, if - * `addressPair_Equals(x, y)` returns true and - * `addressPair_Equals(y, z)` returns true, - * then `addressPair_Equals(x, z)` must return true. - * - * * It is consistent: for any non-null reference values x and y, multiple - * invocations of `addressPair_Equals(x, y)` consistently return true or - * consistently return false. - * - * * For any non-null reference value x, `addressPair_Equals(x, NULL)` must - * return false. - * - * @param a A pointer to a `AddressPair` instance. - * @param b A pointer to a `AddressPair` instance. - * @return true if the two `AddressPair` instances are equal. - */ -bool addressPair_Equals(const AddressPair *a, const AddressPair *b); - -/** - * @function addressPair_EqualsAddresses - * @abstract As AddressEquals, but "b" is broken out - * @discussion - * Equality is determined by addressEquals(a->local, local) and - * Adress_Equals(a->remote, remote). - */ -bool addressPair_EqualsAddresses(const AddressPair *a, const Address *local, - const Address *remote); - -const Address *addressPair_GetLocal(const AddressPair *pair); - -const Address *addressPair_GetRemote(const AddressPair *pair); - -/** - * @function addressPair_HashCode - * @abstract Hash useful for tables. Consistent with Equals. - * @discussion - * Returns a non-cryptographic hash that is consistent with equals. That is, - * if a == b, then hash(a) == hash(b). - */ -PARCHashCode addressPair_HashCode(const AddressPair *pair); - -/** - * @function addressPair_ToString - * @abstract Human readable string representation. Caller must use free(3). - */ -char *addressPair_ToString(const AddressPair *pair); -#endif // address_Pair_h diff --git a/hicn-light/src/hicn/io/base.c b/hicn-light/src/hicn/io/base.c new file mode 100644 index 000000000..71d10021e --- /dev/null +++ b/hicn-light/src/hicn/io/base.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file base.c + * #brief Implementation of base IO functions. + */ + +#include <hicn/util/log.h> + +#include "base.h" + +/** + * @brief Helper function for listener to read a single packet on a socket + */ +ssize_t io_read_single_fd(int fd, msgbuf_t *msgbuf, address_t *address) { + uint8_t *packet = msgbuf_get_packet(msgbuf); + size_t size = msgbuf_get_len(msgbuf); + + for (;;) { + ssize_t n = read(fd, packet, size); + if (n == 0) return n; + if (n < 0) { + if (errno == EINTR) continue; // XXX was break; + + /* ICMP unreachable due to closing the remote end of a connection */ + if (errno == ECONNREFUSED) continue; + + ERROR("read failed %d: (%d) %s", fd, errno, strerror(errno)); + return -1; + } + + msgbuf->length = n; + *address = ADDRESS_ANY(AF_UNSPEC, 0); // XXX placeholder, see hicn.c + } + + return 1; +} + +ssize_t io_read_single_socket(int fd, msgbuf_t *msgbuf, address_t *address) { + struct sockaddr_storage *sa = &address->as_ss; + socklen_t sa_len = sizeof(sa); + uint8_t *packet = msgbuf_get_packet(msgbuf); + + ssize_t n = recvfrom(fd, packet, MTU, 0, (struct sockaddr *)sa, &sa_len); + msgbuf->length = n; + + return n; +} + +#ifdef __linux__ +ssize_t io_read_batch_socket(int fd, msgbuf_t **msgbuf, address_t **address, + size_t batch_size) { + struct mmsghdr msghdr[batch_size]; + struct iovec iovecs[batch_size]; + struct sockaddr_storage addrs[batch_size]; + + /* Prepare the mmghdr struct for recvmmsg */ + for (unsigned i = 0; i < MAX_MSG; i++) { + struct mmsghdr *msg = &msghdr[i]; + *msg = (struct mmsghdr){ + .msg_hdr = + { + .msg_iov = &iovecs[i], + .msg_iovlen = 1, + .msg_name = &addrs[i], + .msg_namelen = sizeof(struct sockaddr_storage), + .msg_control = NULL, + .msg_controllen = 0, + }, + }; + + iovecs[i] = (struct iovec){ + .iov_base = msgbuf_get_packet(msgbuf[i]), + .iov_len = MTU, + }; + } + + int n; + for (;;) { + n = recvmmsg(fd, msghdr, batch_size, /* flags */ 0, + /* timeout */ NULL); + if (n == 0) return 0; + if (n < 0) { + if (errno == EINTR) continue; // XXX was break; + + /* ICMP unreachable due to closing the remote end of a connection */ + if (errno == ECONNREFUSED) break; + if (errno == EAGAIN) return n; // Nothing to read + + ERROR("read failed %d: (%d) %s", fd, errno, strerror(errno)); + return (ssize_t)n; + } + + /* + * Assign size to msgbuf, and put the source address into the array + * received in parameters, which corresponds to the remote parts of the + * connection (local part is setup in the listener itself, eg. + * listener_read_batch). + */ + for (int i = 0; i < n; i++) { + struct mmsghdr *msg = &msghdr[i]; + msgbuf[i]->length = msg->msg_len; + + /* + * As is, the address we put in the array has uninitialized + * memory in it: + * *address[i] = *(address_t*)msg->msg_hdr.msg_name; + * + * This can be confirmed by testing with the following + * memset which removes the valgrind errors: + * memset(address[i], 0, sizeof(address_t)); + * + * The solution is to copy only the part which we know is + * initialized (we have compatible types, since the destination, an + * address_t, is effectively a struct sockaddr_storage). We might + * eventually provide a helper for this to avoid similar mistakes. + */ + //*address[i] = *(address_t*)msg->msg_hdr.msg_name; + memcpy(address[i], msg->msg_hdr.msg_name, msg->msg_hdr.msg_namelen); + } + break; + } + + return n; +} +#endif /* __linux__ */ diff --git a/hicn-light/src/hicn/config/controlUpdateConnection.h b/hicn-light/src/hicn/io/base.h index eea303202..3463c6760 100644 --- a/hicn-light/src/hicn/config/controlUpdateConnection.h +++ b/hicn-light/src/hicn/io/base.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -14,22 +14,24 @@ */ /** - * @file control_UpdateConnection.h - * @brief Update a connection to an interface - * - * <#Detailed Description#> - * + * @file base.h + * #brief Base IO functions. */ -#ifndef Control_UpdateConnection_h -#define Control_UpdateConnection_h +#ifndef HICNLIGHT_IO_BASE +#define HICNLIGHT_IO_BASE + +#include "../core/address_pair.h" +#include "../core/msgbuf.h" + +#define MAX_MSG 128 // 64 //16 //32 +#define USE_CONNECTED_SOCKETS 1 -#ifdef WITH_POLICY +ssize_t io_read_single_fd(int fd, msgbuf_t* msgbuf, address_t* address); -#include <hicn/config/controlState.h> -CommandOps *controlUpdateConnection_Create(ControlState *state); -CommandOps *controlUpdateConnection_HelpCreate(ControlState *state); +ssize_t io_read_single_socket(int fd, msgbuf_t* msgbuf, address_t* address); -#endif /* WITH_POLICY */ +ssize_t io_read_batch_socket(int fd, msgbuf_t** msgbuf, address_t** address, + size_t n); -#endif // Control_UpdateConnection_h +#endif /* HICNLIGHT_IO_BASE */ diff --git a/hicn-light/src/hicn/io/hicn.c b/hicn-light/src/hicn/io/hicn.c new file mode 100644 index 000000000..8b4ad2e00 --- /dev/null +++ b/hicn-light/src/hicn/io/hicn.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file hicn.c + * @brief Implementation of hicn face + */ + +#include <errno.h> +#include <fcntl.h> +#include <hicn/hicn-light/config.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <hicn/util/log.h> + +#include "base.h" +#include "../core/listener.h" +#include "../core/listener_vft.h" +#include "../core/connection.h" +#include "../core/connection_vft.h" +#include "../core/connection_table.h" +#include "../core/forwarder.h" +#include "../core/mapme.h" +#include "../socket/api.h" + +#ifdef __linux__ +#include "../socket/error.h" + +#define IPv6 6 +#define IPv4 4 +#define MTU_SIZE 1500 // bytes +#define MAX_HICN_RETRY 5 +#define DEFAULT_PORT 1234 + +// XXX #if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && +// defined(PUNTING) + +// XXX the socket helper should be moved here as we can have a single hicn +// listener + +#if 0 +static +const +address_pair_t * +_createRecvAddressPairFromPacket(const uint8_t *msgBuffer) { + address_t * packetSrcAddr = NULL; /* This one is in the packet */ + address_t * localAddr = NULL; /* This one is to be determined */ + + if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) { + struct sockaddr_in6 addr_in6; + addr_in6.sin6_family = AF_INET6; + addr_in6.sin6_port = htons(DEFAULT_PORT); + addr_in6.sin6_flowinfo = 0; + addr_in6.sin6_scope_id = 0; + memcpy(&addr_in6.sin6_addr, + (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16); + packetSrcAddr = addressCreateFromInet6(&addr_in6); + + /* We now determine the local address used to reach the packet src address */ +#ifndef _WIN32 + int sock = socket (AF_INET6, SOCK_DGRAM, 0); +#else + int sock = (int)socket (AF_INET6, SOCK_DGRAM, 0); +#endif /* _WIN32 */ + if (sock < 0) + goto ERR; + + struct sockaddr_in6 remote, local; + memset(&remote, 0, sizeof(remote)); + remote.sin6_family = AF_INET6; + remote.sin6_addr = addr_in6.sin6_addr; + remote.sin6_port = htons(DEFAULT_PORT); + + socklen_t locallen = sizeof(local); + if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1) + goto ERR; + if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1) + goto ERR; + + local.sin6_port = htons(DEFAULT_PORT); + localAddr = addressCreateFromInet6(&local); + + close(sock); + + } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) { + struct sockaddr_in addr_in; + addr_in.sin_family = AF_INET; + addr_in.sin_port = htons(DEFAULT_PORT); + memcpy(&addr_in.sin_addr, + (struct in_addr *)messageHandler_GetSource(msgBuffer), 4); + packetSrcAddr = addressCreateFromInet(&addr_in); + + /* We now determine the local address used to reach the packet src address */ + +#ifndef _WIN32 + int sock = socket (AF_INET, SOCK_DGRAM, 0); +#else + int sock = (int)socket (AF_INET, SOCK_DGRAM, 0); +#endif /* _WIN32 */ + if (sock < 0) { + perror("Socket error"); + goto ERR; + } + + struct sockaddr_in remote, local; + memset(&remote, 0, sizeof(remote)); + remote.sin_family = AF_INET; + remote.sin_addr = addr_in.sin_addr; + remote.sin_port = htons(DEFAULT_PORT); + + socklen_t locallen = sizeof(local); + if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1) + goto ERR; + if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1) + goto ERR; + + local.sin_port = htons(DEFAULT_PORT); + localAddr = addressCreateFromInet(&local); + + close(sock); + } + /* As this is a receive pair, we swap src and dst */ + return addressPair_Create(localAddr, packetSrcAddr); + +ERR: + perror("Socket error"); + return NULL; +} + +static +bool _isEmptyAddressIPv6(address_t * address) { + struct sockaddr_in6 *addr6 = + parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6)); + parcAssertNotNull(addr6, "parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(addr6)); + + addressGetInet6(address, addr6); + + bool res = true; + for (int i = 0; i < 16; ++i) { + if (addr6->sin6_addr.s6_addr[i] != 0) { + res = false; + } + } + + parcMemory_Deallocate((void **)&addr6); + + return res; +} + +} + +static +const Connection * +_lookupConnection(ListenerOps * listener, const address_pair_t *pair) +{ + HicnListener * hicn = (HicnListener*)listener->context; + const connection_table_t * table = forwarder_GetConnectionTable(hicn->forwarder); + const address_t * packetSourceAddress = address_pair_local(pair); + + if (hicn->connection_id != -1) + return connection_table_get_by_id(table, hicn->connection_id); + + if (!packetSourceAddress) + return NULL; + + // in this first check we try to retrieve the standard connection + // generated by the hicn-light + const address_pair_t new_pair = { + .local = hicn->localAddress, + .remote = *packetSourceAddress, + }; + return *connection_table_lookup(table, &new_pair); +} + + +// XXX TODO : rely on libhicn +int +_createAddressFromPacket(const uint8_t *packet, address_t * address) +{ + if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) { + struct sockaddr_in6 * sin6 = address6(address); + *sin6 = (struct sockaddr_in6) { + .sin6_family = AF_INET6, + .sin6_port = htons(DEFAULT_PORT), + .sin6_flowinfo = 0, + .sin6_scope_id = 0, + }; + memcpy(&sin6->sin6_addr, + (struct in6_addr *)messageHandler_GetSource(packet), 16); + return 0; + } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) { + struct sockaddr_in * sin = address4(address); + *sin = (struct sockaddr_in) { + .sin_family = AF_INET, + .sin_port = htons(DEFAULT_PORT), + }; + memcpy(&sin->sin_addr, + (struct in_addr *)messageHandler_GetSource(packet), 4); + return 0; + } else { + return -1; + } +} + +#endif + +/****************************************************************************** + * Listener + ******************************************************************************/ + +typedef struct { + // address_t localAddress; // this is the local address or 0::0 in case of + // the + // main listener this is the address used inside + // forwarder to identify the listener. Notice that this + // address is the same as the fisical interfaces on + // which we create the TUN. it is NOT the TUN address + // which is given by libhicn after the bind operation + // However the user alway uses this address since is + // the only one available at configuration time + + // XXX why do we need the id of the associated connection ? + int connection_id; // this is used only if the listener is used to receive + // data packets we assume that 1 connection is associated + // to one listener in this case so we set the + // connection_id we the connection is create. if this id + // is not set and a data packet is received, the packet is + // dropped + + hicn_socket_t *hicn_socket; + hicn_socket_helper_t *hicn_socket_helper; + +} listener_hicn_data_t; + +#define listener_hicn_read_callback listener_read_callback + +bool listener_hicn_bind(listener_t *listener, const address_t *address) { + assert(listener); + assert(address); + + listener_hicn_data_t *data = listener->data; + assert(data); + + char *address_str = malloc(/* max */ INET6_ADDRSTRLEN); + inet_ntop(address_family(address), address, address_str, + /* max */ INET6_ADDRSTRLEN); + int rc = hicn_bind(data->hicn_socket_helper, listener->fd, address_str); + if (rc < 0) { + ERROR("hicn_bind failed %d %s", rc, hicn_socket_strerror(rc)); + free(address_str); + return false; + } + + free(address_str); + return true; +} + +static int listener_hicn_initialize(listener_t *listener) { + assert(listener); + + listener_hicn_data_t *data = listener->data; + assert(data); + + /* This is the id of the connection associated to this listener (unique in + * the case of hICN */ + data->connection_id = -1; + + data->hicn_socket_helper = hicn_create(); + if (!data->hicn_socket) goto ERR_HELPER; + + if (address_empty(&listener->address)) { + listener->fd = hicn_socket(data->hicn_socket_helper, listener->name, NULL); + } else { + char *local_addr = malloc(/* max */ INET6_ADDRSTRLEN); + inet_ntop(address_family(&listener->address), &listener->address, + local_addr, /* max */ INET6_ADDRSTRLEN); + listener->fd = + hicn_socket(data->hicn_socket_helper, listener->name, local_addr); + free(local_addr); + } + + if (listener->fd < 0) { + ERROR("HicnListener %s: error creating hICN listener", listener->name); + goto ERR_FD; + } + + // Set non-blocking flag + int flags = fcntl(listener->fd, F_GETFL, NULL); + if (flags != -1) { + ERROR("fcntl failed to obtain file descriptor flags (%d)", errno); + goto ERR_FLAGS; + } + + if (fcntl(listener->fd, F_SETFL, flags | O_NONBLOCK) < 0) { + ERROR("fcntl failed to set file descriptor flags (%d)", errno); + goto ERR_FLAGS; + } + + return 0; + +ERR_FLAGS: + close(listener->fd); +ERR_FD: + hicn_free(data->hicn_socket_helper); +ERR_HELPER: + return -1; +} + +static void listener_hicn_finalize(listener_t *listener) { + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_HICN); + + listener_hicn_data_t *data = listener->data; + assert(data); + + // TODO destroy hicn_socket + // TODO free(data) (like in other classes) + + hicn_free(data->hicn_socket_helper); + // XXX + // hicn_socket_free(data->hicn_socket); + + return; +} + +static int listener_hicn_punt(const listener_t *listener, + const char *prefix_s) { + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_HICN); + assert(prefix_s); + + listener_hicn_data_t *data = listener->data; + assert(data); + + int rc; + for (int retry = 0; retry < MAX_HICN_RETRY; retry++) { + if ((rc = hicn_listen(data->hicn_socket_helper, listener->fd, prefix_s)) >= + 0) + return 0; + sleep(1); + } + ERROR("hicn_listen failed %d %s", rc, hicn_socket_strerror(rc)); + return -1; +} + +static int listener_hicn_get_socket(const listener_t *listener, + const address_t *local, + const address_t *remote, + const char *interface_name) { + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_HICN); + assert(local); + assert(remote); + + /* ... */ + + return -1; +} + +#define listener_hicn_read_single io_read_single_fd +#define listener_hicn_read_batch NULL + +DECLARE_LISTENER(hicn); + +/****************************************************************************** + * Connection + ******************************************************************************/ + +typedef struct { + /* ... */ +} connection_hicn_data_t; + +static int connection_hicn_initialize(connection_t *connection) { + assert(connection); + assert(connection_get_type(connection) == FACE_TYPE_HICN); + + /* ... */ + + return 0; +} + +static void connection_hicn_finalize(connection_t *connection) { + /* ... */ + + return; +} + +static bool connection_hicn_flush(const connection_t *connection) { + return false; +} + +static bool connection_hicn_send(const connection_t *connection, + msgbuf_t *msgbuf, bool queue) { + assert(connection); + /* msgbuf can be NULL */ + + // connection_hicn_data_t * data = connection->data; + // assert(data); + + /* ... */ + + return false; +} + +// static +// int +// connection_hicn_sendv(const connection_t * connection, struct iovec * iov, +// size_t size) +//{ +// +// assert(connetion); +// assert(iov); +// +//// connection_hicn_data_t * data = connection->data; +//// assert(data); +// +// /* ... */ +// +// return 0; +//} +// +static int connection_hicn_send_packet(const connection_t *connection, + const uint8_t *packet, size_t size) { + assert(connection); + assert(packet); + + /* ... */ + + return 0; +} + +DECLARE_CONNECTION(hicn); + +#endif diff --git a/hicn-light/src/hicn/io/hicnConnection.c b/hicn-light/src/hicn/io/hicnConnection.c deleted file mode 100644 index 646cea990..000000000 --- a/hicn-light/src/hicn/io/hicnConnection.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * Embodies the reader/writer for a Hicn connection - * - * NB The Send() function may overflow the output buffer - * - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <string.h> -#include <sys/uio.h> -#include <unistd.h> - -#include <hicn/core/message.h> -#include <hicn/io/hicnConnection.h> - -#include <hicn/core/messageHandler.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/connection.h> -#include <hicn/core/forwarder.h> - -typedef struct hicn_state { - Forwarder *forwarder; - char * interfaceName; - Logger *logger; - - // the hicn listener socket we receive packets on - int hicnListenerSocket; - - AddressPair *addressPair; - - // We need to access this all the time, so grab it out - // of the addressPair; - struct sockaddr *peerAddress; - socklen_t peerAddressLength; - - struct sockaddr *localAddress; - socklen_t localAddressLength; - - bool isLocal; - bool isUp; - unsigned id; - - unsigned delay; - - /* This information would better be stored in the connection data structure - * but it is currently not reachable from within the implementation. */ - connection_state_t state; - connection_state_t admin_state; -#ifdef WITH_POLICY - uint32_t priority; -#endif /* WITH_POLICY */ -} _HicnState; - -// Prototypes -static bool _send(IoOperations *ops, const Address *nexthop, Message *message); -static bool _sendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size); -static const Address *_getRemoteAddress(const IoOperations *ops); -static const AddressPair *_getAddressPair(const IoOperations *ops); -static unsigned _getConnectionId(const IoOperations *ops); -static bool _isUp(const IoOperations *ops); -static bool _isLocal(const IoOperations *ops); -static void _destroy(IoOperations **opsPtr); -static list_connections_type _getConnectionType(const IoOperations *ops); -static void _sendProbe(IoOperations *ops, uint8_t *message); -static connection_state_t _getState(const IoOperations *ops); -static void _setState(IoOperations *ops, connection_state_t state); -static connection_state_t _getAdminState(const IoOperations *ops); -static void _setAdminState(IoOperations *ops, connection_state_t admin_state); -#ifdef WITH_POLICY -static uint32_t _getPriority(const IoOperations *ops); -static void _setPriority(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ -static const char * _getInterfaceName(const IoOperations *ops); - -/* - * This assigns a unique pointer to the void * which we use - * as a GUID for this class. - */ -static const void *_ioOperationsGuid = __FILE__; - -/* - * Return our GUID - */ -static const void *_streamConnection_Class(const IoOperations *ops) { - return _ioOperationsGuid; -} - -static IoOperations _template = { - .closure = NULL, - .send = &_send, - .sendIOVBuffer = &_sendIOVBuffer, - .getRemoteAddress = &_getRemoteAddress, - .getAddressPair = &_getAddressPair, - .getConnectionId = &_getConnectionId, - .isUp = &_isUp, - .isLocal = &_isLocal, - .destroy = &_destroy, - .class = &_streamConnection_Class, - .getConnectionType = &_getConnectionType, - .sendProbe = &_sendProbe, - .getState = &_getState, - .setState = &_setState, - .getAdminState = &_getAdminState, - .setAdminState = &_setAdminState, -#ifdef WITH_POLICY - .getPriority = &_getPriority, - .setPriority = &_setPriority, -#endif /* WITH_POLICY */ - .getInterfaceName = &_getInterfaceName, -}; - -// ================================================================= - -static void _setConnectionState(_HicnState *Hicn, bool isUp); -static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair); - -IoOperations *hicnConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd, - const AddressPair *pair, bool isLocal) { - IoOperations *io_ops = NULL; - - _HicnState *hicnConnState = parcMemory_AllocateAndClear(sizeof(_HicnState)); - parcAssertNotNull(hicnConnState, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_HicnState)); - - hicnConnState->forwarder = forwarder; - hicnConnState->interfaceName = strdup(interfaceName); - hicnConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - bool saved = _saveSockaddr(hicnConnState, pair); - if (saved) { - hicnConnState->hicnListenerSocket = fd; - hicnConnState->id = forwarder_GetNextConnectionId(forwarder); - hicnConnState->addressPair = addressPair_Acquire(pair); - hicnConnState->isLocal = isLocal; - - // allocate a connection - io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations)); - parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(IoOperations)); - memcpy(io_ops, &_template, sizeof(IoOperations)); - io_ops->closure = hicnConnState; - - _setConnectionState(hicnConnState, true); - -#ifdef WITH_POLICY - hicnConnState->priority = 0; -#endif /* WITH_POLICY */ - - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - char *str = addressPair_ToString(hicnConnState->addressPair); - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Info, - __func__, - "HicnConnection %p created for address %s (isLocal %d)", - (void *)hicnConnState, str, hicnConnState->isLocal); - free(str); - } - - messenger_Send( - forwarder_GetMessenger(forwarder), - missive_Create(MissiveType_ConnectionCreate, hicnConnState->id)); - messenger_Send(forwarder_GetMessenger(forwarder), - missive_Create(MissiveType_ConnectionUp, hicnConnState->id)); - } else { - // _saveSockaddr will already log an error, no need for extra log message - // here - logger_Release(&hicnConnState->logger); - free(hicnConnState->interfaceName); - parcMemory_Deallocate((void **)&hicnConnState); - } - - return io_ops; -} - -// ================================================================= -// I/O Operations implementation - -static void _destroy(IoOperations **opsPtr) { - parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer"); - parcAssertNotNull(*opsPtr, - "Parameter opsPtr must dereference to non-null pointer"); - - IoOperations *ops = *opsPtr; - parcAssertNotNull(ioOperations_GetClosure(ops), - "ops->context must not be null"); - - _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops); - addressPair_Release(&hicnConnState->addressPair); - parcMemory_Deallocate((void **)&(hicnConnState->peerAddress)); - parcMemory_Deallocate((void **)&(hicnConnState->localAddress)); - - messenger_Send( - forwarder_GetMessenger(hicnConnState->forwarder), - missive_Create(MissiveType_ConnectionDestroyed, hicnConnState->id)); - - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Info, - __func__, "HicnConnection %p destroyed", (void *)hicnConnState); - } - - // do not close hicListenerSocket, the listener will close - // that when its done - // should I say something to libhicn? - - logger_Release(&hicnConnState->logger); - free(hicnConnState->interfaceName); - parcMemory_Deallocate((void **)&hicnConnState); - parcMemory_Deallocate((void **)&ops); - - *opsPtr = NULL; -} - -static bool _isUp(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->isUp; -} - -static bool _isLocal(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->isLocal; -} - -static const Address *_getRemoteAddress(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return addressPair_GetRemote(hicnConnState->addressPair); -} - -static const AddressPair *_getAddressPair(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->addressPair; -} - -static unsigned _getConnectionId(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->id; -} - -/** - * @function hicnConnection_Send - * @abstract Non-destructive send of the message. - * @discussion - * sends a message to the peer. - * - * @param dummy is ignored. . - */ -static bool _send(IoOperations *ops, const Address *dummy, Message *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops); - - // NAT for HICN - if (message_GetType(message) == MessagePacketType_ContentObject) { - // this is a data packet. We need to put the remote address in the - // destination field - - if (messageHandler_GetIPPacketType(message_FixedHeader(message)) == - IPv6_TYPE) { - messageHandler_SetDestination_IPv6( - (uint8_t *)message_FixedHeader(message), - &((struct sockaddr_in6 *)hicnConnState->peerAddress)->sin6_addr); - } else { - messageHandler_SetDestination_IPv4( - (uint8_t *)message_FixedHeader(message), - &(((struct sockaddr_in *)hicnConnState->peerAddress) - ->sin_addr.s_addr)); - } - } else if (message_GetType(message) == MessagePacketType_Interest) { - // this si an interest packet. We need to put the local address in the - // source field - if (messageHandler_GetIPPacketType(message_FixedHeader(message)) == - IPv6_TYPE) { - messageHandler_SetSource_IPv6( - (uint8_t *)message_FixedHeader(message), - &((struct sockaddr_in6 *)hicnConnState->localAddress)->sin6_addr); - } else { - messageHandler_SetSource_IPv4( - (uint8_t *)message_FixedHeader(message), - &(((struct sockaddr_in *)hicnConnState->localAddress) - ->sin_addr.s_addr)); - } - } else if (message_GetType(message) == MessagePacketType_WldrNotification) { - // here we don't need to do anything for now - } else { - // unkown packet - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Debug, - __func__, "connid %u can't parse the message", - hicnConnState->id); - } - return false; - } - - ssize_t writeLength = - write(hicnConnState->hicnListenerSocket, message_FixedHeader(message), - message_Length(message)); - - if (writeLength < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - return false; - } else { - // this print is for debugging - printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLength, - message_Length(message), errno, strerror(errno)); - return false; - } - } - - return true; -} - -static bool _sendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - - _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops); - - - ssize_t n = writev(hicnConnState->hicnListenerSocket, message, size); - if (n < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - size_t length = 0; - for (int i = 0; i < size; i++) - length += message[i].iov_len; - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Error, - __func__, "Incorrect write length %zd, expected %zd: (%d) %s\n", - n, length, errno, strerror(errno)); - } - } - return false; - } - return true; -} - -static list_connections_type _getConnectionType(const IoOperations *ops) { - return CONN_HICN; -} - -static void _sendProbe(IoOperations *ops, uint8_t *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - - _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops); - - if(messageHandler_IsInterest(message)){// - // this is an interest packet. We need to put the local address in the - // source field - if (messageHandler_GetIPPacketType(message) == IPv6_TYPE) { - messageHandler_SetSource_IPv6(message, - &((struct sockaddr_in6 *)hicnConnState->localAddress)->sin6_addr); - } else { - messageHandler_SetSource_IPv4(message, - &(((struct sockaddr_in *)hicnConnState->localAddress) - ->sin_addr.s_addr)); - } - }//if is a data packet the packet is already set (see - //messageHandler_CreateProbeReply) - - ssize_t writeLength = write(hicnConnState->hicnListenerSocket, message, - messageHandler_GetTotalPacketLength(message)); - - if (writeLength < 0) { - return; - } -} - -// ================================================================= -// Internal API - -static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair) { - bool success = false; - const Address *remoteAddress = addressPair_GetRemote(pair); - const Address *localAddress = addressPair_GetLocal(pair); - switch (addressGetType(remoteAddress)) { // local must be of the same type - - case ADDR_INET: { - size_t bytes = sizeof(struct sockaddr_in); - hicnConnState->peerAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(hicnConnState->peerAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet(remoteAddress, - (struct sockaddr_in *)hicnConnState->peerAddress); - hicnConnState->peerAddressLength = (socklen_t)bytes; - - hicnConnState->localAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(hicnConnState->localAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet(localAddress, - (struct sockaddr_in *)hicnConnState->localAddress); - hicnConnState->localAddressLength = (socklen_t)bytes; - success = true; - break; - } - - case ADDR_INET6: { - size_t bytes = sizeof(struct sockaddr_in6); - hicnConnState->peerAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(hicnConnState->peerAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet6(remoteAddress, - (struct sockaddr_in6 *)hicnConnState->peerAddress); - hicnConnState->peerAddressLength = (socklen_t)bytes; - - hicnConnState->localAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(hicnConnState->localAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet6(localAddress, - (struct sockaddr_in6 *)hicnConnState->localAddress); - hicnConnState->localAddressLength = (socklen_t)bytes; - success = true; - break; - } - - default: - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - char *str = addressToString(remoteAddress); - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Error, - __func__, "Remote address is not INET or INET6: %s", str); - parcMemory_Deallocate((void **)&str); - } - break; - } - return success; -} - -static void _setConnectionState(_HicnState *hicnConnState, bool isUp) { - parcAssertNotNull(hicnConnState, "Parameter HICN must be non-null"); - - Messenger *messenger = forwarder_GetMessenger(hicnConnState->forwarder); - - bool oldStateIsUp = hicnConnState->isUp; - hicnConnState->isUp = isUp; - - if (oldStateIsUp && !isUp) { - // bring connection DOWN - Missive *missive = - missive_Create(MissiveType_ConnectionDown, hicnConnState->id); - messenger_Send(messenger, missive); - return; - } - - if (!oldStateIsUp && isUp) { - // bring connection UP - Missive *missive = - missive_Create(MissiveType_ConnectionUp, hicnConnState->id); - messenger_Send(messenger, missive); - return; - } -} - -static connection_state_t _getState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->state; -} - -static void _setState(IoOperations *ops, connection_state_t state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _HicnState *hicnConnState = - (_HicnState *)ioOperations_GetClosure(ops); - hicnConnState->state = state; -} - -static connection_state_t _getAdminState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->admin_state; -} - -static void _setAdminState(IoOperations *ops, connection_state_t admin_state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _HicnState *hicnConnState = - (_HicnState *)ioOperations_GetClosure(ops); - hicnConnState->admin_state = admin_state; -} - -#ifdef WITH_POLICY -static uint32_t _getPriority(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->priority; -} - -static void _setPriority(IoOperations *ops, uint32_t priority) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _HicnState *hicnConnState = - (_HicnState *)ioOperations_GetClosure(ops); - hicnConnState->priority = priority; -} -#endif /* WITH_POLICY -*/ -static const char * _getInterfaceName(const IoOperations *ops) -{ - parcAssertNotNull(ops, "Parameter must be non-null"); - _HicnState *hicnConnState = - (_HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->interfaceName; -} diff --git a/hicn-light/src/hicn/io/hicnConnection.h b/hicn-light/src/hicn/io/hicnConnection.h deleted file mode 100644 index fec18e1bd..000000000 --- a/hicn-light/src/hicn/io/hicnConnection.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file hicnConnection.h - * @brief Represents a Hicn connection for the connection table - * - * <#Detailed Description#> - * - */ - -#ifndef hicnConnection_h -#define hicnConnection_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> -#include <hicn/utils/address.h> - -/** - * Creates a Hicn connection that can send to the remote address - * - * The address pair must both be same type (i.e. INET or INET6). - * - * @param [in] an allocated hicn-light Forwarder (saves reference) - * @param [in] fd The socket to use - * @param [in] pair An allocated address pair for the connection (saves - * reference) - * @param [in] isLocal determines if the remote address is on the current system - * - * @retval non-null An allocated Io operations - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -IoOperations *hicnConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd, - const AddressPair *pair, bool isLocal); -#endif // hicnConnection_h diff --git a/hicn-light/src/hicn/io/hicnListener.c b/hicn-light/src/hicn/io/hicnListener.c deleted file mode 100644 index 8647a4d54..000000000 --- a/hicn-light/src/hicn/io/hicnListener.c +++ /dev/null @@ -1,673 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <errno.h> -#include <fcntl.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <unistd.h> - -#include <hicn/io/hicnConnection.h> -#include <hicn/io/hicnListener.h> - -#include <hicn/core/connection.h> -#include <hicn/core/connectionTable.h> -#include <hicn/core/forwarder.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/mapme.h> -#include <hicn/core/messagePacketType.h> -#include <hicn/io/listener.h> -#include <hicn/socket/api.h> - -#define IPv6 6 -#define IPv4 4 -#define MTU_SIZE 1500 // bytes -#define MAX_HICN_RETRY 5 - -struct hicn_listener { - - char *listenerName; - - Forwarder *forwarder; - Logger *logger; - - PARCEvent *hicn_event; - int hicn_fd; // this is the file descriptor got from hicn library - - Address - *localAddress; // this is the local address or 0::0 in case of the - // main listener this is the address used inside - // forwarder to identify the listener. Notice that this - // address is the same as the fisical interfaces on - // which we create the TUN. it is NOT the TUN address - // which is given by libhicn after the bind operation - // However the user alway uses this address since is - // the only one available at configuration time - - unsigned inetFamily; - - int connection_id; // this is used only if the listener is used to receive - // data packets we assume that 1 connection is associated - // to one listener in this case so we set the - // connection_id we the connection is create. if this id - // is not set and a data packet is received, the packet is - // dropped - - unsigned conn_id; -}; - -static void _destroy(ListenerOps **listenerOpsPtr); -static const char *_getListenerName(const ListenerOps *ops); -static const char *_getInterfaceName(const ListenerOps *ops); -static unsigned _getInterfaceIndex(const ListenerOps *ops); -static const Address *_getListenAddress(const ListenerOps *ops); -static EncapType _getEncapType(const ListenerOps *ops); -static int _getSocket(const ListenerOps *ops); -static unsigned _createNewConnection(ListenerOps *listener, int fd, const AddressPair *pair); -static const Connection * _lookupConnection(ListenerOps * listener, const AddressPair *pair); -static Message *_readMessage(ListenerOps * listener, int fd, uint8_t *msgBuffer); -static void _hicnListener_readcb(int fd, PARCEventType what, void *listener_void); -static Address *_createAddressFromPacket(uint8_t *msgBuffer); -static void _handleWldrNotification(ListenerOps *listener, uint8_t *msgBuffer); -static void _readFrameToDiscard(HicnListener *hicn, int fd); - -static ListenerOps _hicnTemplate = { - .context = NULL, - .destroy = &_destroy, - .getInterfaceIndex = &_getInterfaceIndex, - .getListenAddress = &_getListenAddress, - .getEncapType = &_getEncapType, - .getSocket = &_getSocket, - .getInterfaceName = &_getInterfaceName, - .getListenerName = &_getListenerName, - .createConnection = &_createNewConnection, - .lookupConnection = &_lookupConnection, -}; - -static bool _isEmptyAddressIPv6(Address *address) { - struct sockaddr_in6 *addr6 = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6)); - parcAssertNotNull(addr6, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(addr6)); - - addressGetInet6(address, addr6); - - bool res = true; - for (int i = 0; i < 16; ++i) { - if (addr6->sin6_addr.s6_addr[i] != 0) { - res = false; - } - } - - parcMemory_Deallocate((void **)&addr6); - - return res; -} - -static Message *_readMessage(ListenerOps * listener, int fd, uint8_t *msgBuffer) { - HicnListener * hicn = (HicnListener*)listener->context; - Message *message = NULL; - - ssize_t readLength = read(fd, msgBuffer, MTU_SIZE); - - if (readLength < 0) { - printf("read failed %d: (%d) %s\n", fd, errno, strerror(errno)); - return message; - } - - size_t packetLength = messageHandler_GetTotalPacketLength(msgBuffer); - - if (readLength != packetLength) { - parcMemory_Deallocate((void **)&msgBuffer); - return message; - } - - if (messageHandler_IsTCP(msgBuffer)) { - MessagePacketType pktType; - unsigned connid = 0; - if (messageHandler_IsData(msgBuffer)) { - pktType = MessagePacketType_ContentObject; - if (hicn->connection_id == -1) { - parcMemory_Deallocate((void **)&msgBuffer); - return message; - } else { - connid = hicn->connection_id; - } - } else if (messageHandler_IsInterest(msgBuffer)) { - // notice that the connections for the interest (the one that we create at - // run time) uses as a local address 0::0, so the main tun - pktType = MessagePacketType_Interest; - Address *packetAddr = _createAddressFromPacket(msgBuffer); - - AddressPair *pair_find = addressPair_Create(packetAddr, /* dummy */ hicn->localAddress); - const Connection *conn = _lookupConnection(listener, pair_find); - addressPair_Release(&pair_find); - if (conn == NULL) { - AddressPair *pair = addressPair_Create(hicn->localAddress, packetAddr); - connid = _createNewConnection(listener, fd, pair); - addressPair_Release(&pair); - } else { - connid = connection_GetConnectionId(conn); - } - addressDestroy(&packetAddr); - } else { - printf("Got a packet that is not a data nor an interest, drop it!\n"); - parcMemory_Deallocate((void **)&msgBuffer); - return message; - } - - message = message_CreateFromByteArray(connid, msgBuffer, pktType, - forwarder_GetTicks(hicn->forwarder), - forwarder_GetLogger(hicn->forwarder)); - if (message == NULL) { - parcMemory_Deallocate((void **)&msgBuffer); - } - } else if (messageHandler_IsWldrNotification(msgBuffer)) { - _handleWldrNotification(listener, msgBuffer); - } else { - messageHandler_handleHooks(hicn->forwarder, msgBuffer, listener, fd, NULL); - parcMemory_Deallocate((void **)&msgBuffer); - } - - return message; -} - -static void _receivePacket(ListenerOps * listener, int fd) { - HicnListener * hicn = (HicnListener*)listener->context; - Message *msg = NULL; - uint8_t *msgBuffer = parcMemory_AllocateAndClear(MTU_SIZE); - msg = _readMessage(listener, fd, msgBuffer); - - if (msg) { - forwarder_Receive(hicn->forwarder, msg); - } -} - -static void _hicnListener_readcb(int fd, PARCEventType what, void *listener_void) { - ListenerOps * listener = (ListenerOps *)listener_void; - HicnListener *hicn = (HicnListener *)listener->context; - - if (hicn->inetFamily == IPv4 || hicn->inetFamily == IPv6) { - if (what & PARCEventType_Read) { - _receivePacket(listener, fd); - } - } else { - _readFrameToDiscard(hicn, fd); - } -} - -static bool _isEmptyAddressIPv4(Address *address) { - bool res = false; - - char * str = addressToString(address); - if (strcmp("inet4://0.0.0.0:1234", str) == 0) res = true; - parcMemory_Deallocate((void**)&str); - - return res; -} - -ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic, - Address *address) { - HicnListener *hicn = parcMemory_AllocateAndClear(sizeof(HicnListener)); - parcAssertNotNull(hicn, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(HicnListener)); - - hicn->forwarder = forwarder; - hicn->listenerName = parcMemory_StringDuplicate(symbolic, strlen(symbolic)); - hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - hicn->conn_id = forwarder_GetNextConnectionId(forwarder); - hicn->inetFamily = IPv4; - - hicn->connection_id = -1; - - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(forwarder); - - if (_isEmptyAddressIPv4(address)) { - hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, NULL); - } else { - struct sockaddr_in *tmpAddr = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in)); - parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(tmpAddr)); - addressGetInet(address, tmpAddr); - char *local_addr = parcMemory_AllocateAndClear(INET_ADDRSTRLEN); - inet_ntop(AF_INET, &(tmpAddr->sin_addr), local_addr, INET_ADDRSTRLEN); - parcMemory_Deallocate((void **)&tmpAddr); - - hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, local_addr); - - parcMemory_Deallocate((void **)&local_addr); - } - - if (hicn->hicn_fd < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log( - hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "HicnListener %s: error while creating an hicn listener in lib_hicn", - symbolic); - } - logger_Release(&hicn->logger); - addressDestroy(&hicn->localAddress); - parcMemory_Deallocate((void **)&hicn->listenerName); - parcMemory_Deallocate((void **)&hicn); - return NULL; - } - - // Set non-blocking flag - int flags = fcntl(hicn->hicn_fd, F_GETFL, NULL); - parcAssertTrue(flags != -1, - "fcntl failed to obtain file descriptor flags (%d)", errno); - int failure = fcntl(hicn->hicn_fd, F_SETFL, flags | O_NONBLOCK); - parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)", - errno); - - ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - - memcpy(ops, &_hicnTemplate, sizeof(ListenerOps)); - ops->context = hicn; - - hicn->hicn_event = dispatcher_CreateNetworkEvent( - forwarder_GetDispatcher(forwarder), true, _hicnListener_readcb, - (void *)ops, hicn->hicn_fd); - dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder), - hicn->hicn_event); - - - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "HicnListener %s created", symbolic); - } - - return ops; - return NULL; -} - -ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic, - Address *address) { - HicnListener *hicn = parcMemory_AllocateAndClear(sizeof(HicnListener)); - parcAssertNotNull(hicn, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(HicnListener)); - - hicn->forwarder = forwarder; - hicn->listenerName = parcMemory_StringDuplicate(symbolic, strlen(symbolic)); - hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - hicn->conn_id = forwarder_GetNextConnectionId(forwarder); - hicn->localAddress = addressCopy(address); - - hicn->inetFamily = IPv6; - - hicn->connection_id = -1; - - // the call to libhicn is the same both for the main and the normal listeners - // in both cases we need to set only the identifier. In the case of normal - // listener (listener for data packet) we let the library select the right ip - // address we just need to set the right type of packet - - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(forwarder); - - if (_isEmptyAddressIPv6(address)) { - // create main listener - hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, NULL); - } else { - // create listener for the connetion - struct sockaddr_in6 *tmpAddr = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6)); - - parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(tmpAddr)); - addressGetInet6(address, tmpAddr); - - char *local_addr = parcMemory_AllocateAndClear(INET6_ADDRSTRLEN); - inet_ntop(AF_INET6, &(tmpAddr->sin6_addr), local_addr, INET6_ADDRSTRLEN); - - parcMemory_Deallocate((void **)&tmpAddr); - - hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, local_addr); - - parcMemory_Deallocate((void **)&local_addr); - } - - if (hicn->hicn_fd < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log( - hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "HicnListener %s: error while creating an hicn listener in lib_hicn", - symbolic); - } - logger_Release(&hicn->logger); - addressDestroy(&hicn->localAddress); - parcMemory_Deallocate((void **)&hicn->listenerName); - parcMemory_Deallocate((void **)&hicn); - return NULL; - } - - // Set non-blocking flag - int flags = fcntl(hicn->hicn_fd, F_GETFL, NULL); - parcAssertTrue(flags != -1, - "fcntl failed to obtain file descriptor flags (%d)", errno); - int failure = fcntl(hicn->hicn_fd, F_SETFL, flags | O_NONBLOCK); - parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)", - errno); - - ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - - memcpy(ops, &_hicnTemplate, sizeof(ListenerOps)); - ops->context = hicn; - - hicn->hicn_event = dispatcher_CreateNetworkEvent( - forwarder_GetDispatcher(forwarder), true, _hicnListener_readcb, - (void *)ops, hicn->hicn_fd); - dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder), - hicn->hicn_event); - - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "HicnListener %s created", symbolic); - } - - return ops; -} - -bool _hicnListener_BindInet6(ListenerOps *ops, const Address *remoteAddress) { - HicnListener *hicn = (HicnListener *)ops->context; - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(hicn->forwarder); - - struct sockaddr_in6 *tmpAddr = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6)); - parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(tmpAddr)); - addressGetInet6(remoteAddress, tmpAddr); - char *remote_addr = parcMemory_AllocateAndClear(INET6_ADDRSTRLEN); - inet_ntop(AF_INET6, &(tmpAddr->sin6_addr), remote_addr, INET6_ADDRSTRLEN); - parcMemory_Deallocate((void **)&tmpAddr); - - int res = hicn_bind(hicnSocketHelper, hicn->hicn_fd, remote_addr); - - bool result = false; - if (res < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "hicn_bind failed %d %s", res, hicn_socket_strerror(res)); - } - } else { - result = true; - } - - parcMemory_Deallocate((void **)&remote_addr); - - return result; -} - -bool _hicnListener_BindInet(ListenerOps *ops, const Address *remoteAddress) { - HicnListener *hicn = (HicnListener *)ops->context; - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(hicn->forwarder); - - struct sockaddr_in *tmpAddr = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in)); - parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(tmpAddr)); - addressGetInet(remoteAddress, tmpAddr); - char *remote_addr = parcMemory_AllocateAndClear(INET_ADDRSTRLEN); - inet_ntop(AF_INET, &(tmpAddr->sin_addr), remote_addr, INET_ADDRSTRLEN); - parcMemory_Deallocate((void **)&tmpAddr); - - int res = hicn_bind(hicnSocketHelper, hicn->hicn_fd, remote_addr); - bool result = false; - - if (res < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "hicn_bind failed %d %s", res, hicn_socket_strerror(res)); - } - } else { - result = true; - } - - parcMemory_Deallocate((void **)&remote_addr); - - return result; -} - -bool hicnListener_Bind(ListenerOps *ops, const Address *remoteAddress) { - if (addressGetType(remoteAddress) == ADDR_INET) { - return _hicnListener_BindInet(ops, remoteAddress); - } else if (addressGetType(remoteAddress) == ADDR_INET6) { - return _hicnListener_BindInet6(ops, remoteAddress); - } else { - printf("Bind failed: Invalid address\n"); - return false; - } -} - -bool hicnListener_Punting(ListenerOps *ops, const char *prefix) { - HicnListener *hicn = (HicnListener *)ops->context; - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(hicn->forwarder); - - int res = hicn_listen(hicnSocketHelper, hicn->hicn_fd, prefix); - int retry = 0; - - while (res < 0 && retry < MAX_HICN_RETRY) { - sleep(1); - res = hicn_listen(hicnSocketHelper, hicn->hicn_fd, prefix); - retry++; - } - - if (res < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "hicn_listen failed %d %s", res, hicn_socket_strerror(res)); - } - return false; - } - - return true; -} - -bool hicnListener_SetConnectionId(ListenerOps *ops, unsigned connId) { - HicnListener *hicn = (HicnListener *)ops->context; - if (hicn) { - hicn->connection_id = connId; - return true; - } - return false; -} - -static void _hicnListener_Destroy(HicnListener **listenerPtr) { - parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listenerPtr, - "Parameter must derefernce to non-null pointer"); - - HicnListener *hicn = *listenerPtr; - - dispatcher_DestroyNetworkEvent(forwarder_GetDispatcher(hicn->forwarder), - &hicn->hicn_event); - logger_Release(&hicn->logger); - addressDestroy(&hicn->localAddress); - parcMemory_Deallocate((void **)&hicn); - *listenerPtr = NULL; -} - -static void _destroy(ListenerOps **listenerOpsPtr) { - ListenerOps *ops = *listenerOpsPtr; - HicnListener *hicn = (HicnListener *)ops->context; - _hicnListener_Destroy(&hicn); - parcMemory_Deallocate((void **)&ops); - *listenerOpsPtr = NULL; -} - -static const char *_getListenerName(const ListenerOps *ops) { - HicnListener *hicn = (HicnListener *)ops->context; - return hicn->listenerName; -} - -static const char *_getInterfaceName(const ListenerOps *ops) { - const char *interfaceName = ""; - return interfaceName; -} - -static unsigned _getInterfaceIndex(const ListenerOps *ops) { - HicnListener *hicn = (HicnListener *)ops->context; - return hicn->conn_id; -} - -static const Address *_getListenAddress(const ListenerOps *ops) { - HicnListener *hicn = (HicnListener *)ops->context; - return hicn->localAddress; -} - -static EncapType _getEncapType(const ListenerOps *ops) { return ENCAP_HICN; } - -static int _getSocket(const ListenerOps *ops) { - HicnListener *hicn = (HicnListener *)ops->context; - return hicn->hicn_fd; -} - -// =============================== - -static void _readFrameToDiscard(HicnListener *hicn, int fd) { - // we need to discard the frame. Read 1 byte. This will clear it off the - // stack. - uint8_t buffer; - int nread = read(fd, &buffer, 1); - - if (nread > 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "Discarded frame from fd %d", fd); - } - } else if (nread < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Error trying to discard frame from fd %d: (%d) %s", fd, errno, - strerror(errno)); - } - } -} - -static unsigned _createNewConnection(ListenerOps * listener, int fd, - const AddressPair *pair) { - HicnListener * hicn = (HicnListener *)listener->context; - bool isLocal = false; - - // udpConnection_Create takes ownership of the pair - IoOperations *ops = hicnConnection_Create(hicn->forwarder, listener->getInterfaceName(listener), fd, pair, isLocal); - Connection *conn = connection_Create(ops); - - connectionTable_Add(forwarder_GetConnectionTable(hicn->forwarder), conn); - unsigned connid = ioOperations_GetConnectionId(ops); - - return connid; -} - -static const Connection * _lookupConnection(ListenerOps * listener, - const AddressPair *pair) { - HicnListener * hicn = (HicnListener*)listener->context; - const Address * packetSourceAddress = addressPair_GetLocal(pair); - - const Connection *conn = NULL; - if (hicn->connection_id != -1) { - conn = connectionTable_FindById( - forwarder_GetConnectionTable(hicn->forwarder), hicn->connection_id); - } else { - if (packetSourceAddress != NULL) { - // in this first check we try to retrieve the standard connection - // generated by the hicn-light - AddressPair *pair = - addressPair_Create(hicn->localAddress, packetSourceAddress); - conn = connectionTable_FindByAddressPair( - forwarder_GetConnectionTable(hicn->forwarder), pair); - addressPair_Release(&pair); - } - } - - return conn; -} - -static Address *_createAddressFromPacket(uint8_t *msgBuffer) { - Address *packetAddr = NULL; - if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) { - struct sockaddr_in6 addr_in6; - addr_in6.sin6_family = AF_INET6; - addr_in6.sin6_port = htons(1234); - addr_in6.sin6_flowinfo = 0; - addr_in6.sin6_scope_id = 0; - memcpy(&addr_in6.sin6_addr, - (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16); - packetAddr = addressCreateFromInet6(&addr_in6); - } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) { - struct sockaddr_in addr_in; - addr_in.sin_family = AF_INET; - addr_in.sin_port = htons(1234); - memcpy(&addr_in.sin_addr, - (struct in_addr *)messageHandler_GetSource(msgBuffer), 4); - packetAddr = addressCreateFromInet(&addr_in); - } - return packetAddr; -} - -static void _handleWldrNotification(ListenerOps *listener, uint8_t *msgBuffer) { - HicnListener * hicn = (HicnListener *)listener->context; - - Address *packetAddr = _createAddressFromPacket(msgBuffer); - - if (packetAddr == NULL) { - parcMemory_Deallocate((void **)&msgBuffer); - return; - } - - AddressPair * pair = addressPair_Create(packetAddr, /* dummy */ hicn->localAddress); - - const Connection *conn = _lookupConnection(listener, pair); - - addressPair_Release(&pair); - addressDestroy(&packetAddr); - - if (conn == NULL) { - parcMemory_Deallocate((void **)&msgBuffer); - return; - } - - Message *message = message_CreateFromByteArray( - connection_GetConnectionId(conn), msgBuffer, - MessagePacketType_WldrNotification, forwarder_GetTicks(hicn->forwarder), - forwarder_GetLogger(hicn->forwarder)); - - connection_HandleWldrNotification((Connection *)conn, message); - - message_Release(&message); -} diff --git a/hicn-light/src/hicn/io/hicnListener.h b/hicn-light/src/hicn/io/hicnListener.h deleted file mode 100644 index faf6ad6b8..000000000 --- a/hicn-light/src/hicn/io/hicnListener.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file hicnListener.h - * @brief Listens for in coming Hicn connections - * - * - */ - -#ifndef hicnListener_h -#define hicnListener_h - -#include <hicn/core/forwarder.h> -#include <hicn/core/messageHandler.h> -#include <hicn/io/listener.h> -#include <stdlib.h> - -struct hicn_listener; -typedef struct hicn_listener HicnListener; - -ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic, - Address *address); -ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic, - Address *address); -bool hicnListener_Punting(ListenerOps *ops, const char *prefix); -bool hicnListener_Bind(ListenerOps *ops, const Address *remoteAddress); -bool hicnListener_SetConnectionId(ListenerOps *ops, unsigned connId); -// const Address *hicnListener_GetTunAddress(const ListenerOps *ops); -#endif // hicnListener_h diff --git a/hicn-light/src/hicn/io/hicnTunnel.c b/hicn-light/src/hicn/io/hicnTunnel.c deleted file mode 100644 index fd5acc680..000000000 --- a/hicn-light/src/hicn/io/hicnTunnel.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/io/hicnConnection.h> -#include <hicn/io/hicnListener.h> -#include <hicn/io/hicnTunnel.h> - -IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder, - ListenerOps *localListener, - const Address *remoteAddress) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(localListener, "Parameter localListener must be non-null"); - parcAssertNotNull(remoteAddress, "Parameter remoteAddress must be non-null"); - - Logger *logger = forwarder_GetLogger(forwarder); - - IoOperations *ops = NULL; - if (localListener->getEncapType(localListener) == ENCAP_HICN) { - const Address *localAddress = - localListener->getListenAddress(localListener); - address_type localType = addressGetType(localAddress); - address_type remoteType = addressGetType(remoteAddress); - - if (localType == remoteType) { - bool res = hicnListener_Bind(localListener, remoteAddress); - if (res == false) { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Unable to bind local listener to remote node"); - } - return ops; - } - - // localAddress = hicnListener_GetTunAddress(localListener); //This is the - // true local address - - AddressPair *pair = addressPair_Create(localAddress, remoteAddress); - bool isLocal = false; - int fd = localListener->getSocket(localListener); - ops = hicnConnection_Create(forwarder, localListener->getInterfaceName(localListener), fd, pair, isLocal); - - addressPair_Release(&pair); - } else { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Local listener of type %s and remote type %s, cannot " - "establish tunnel", - addressTypeToString(localType), - addressTypeToString(remoteType)); - } - } - } else { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Local listener %p is not type UDP, cannot establish tunnel", - (void *)localListener); - } - } - - return ops; -} - -IoOperations *hicnTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress) { - ListenerSet *set = forwarder_GetListenerSet(forwarder); - ListenerOps *listener = listenerSet_Find(set, ENCAP_HICN, localAddress); - IoOperations *ops = NULL; - if (listener) { - ops = hicnTunnel_CreateOnListener(forwarder, listener, remoteAddress); - } else { - if (logger_IsLoggable(forwarder_GetLogger(forwarder), LoggerFacility_IO, - PARCLogLevel_Error)) { - char *str = addressToString(localAddress); - logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "Could not find listener to match address %s", str); - parcMemory_Deallocate((void **)&str); - } - } - - if (ops) { - hicnListener_SetConnectionId(listener, ops->getConnectionId(ops)); - } - - return ops; -} diff --git a/hicn-light/src/hicn/io/hicnTunnel.h b/hicn-light/src/hicn/io/hicnTunnel.h deleted file mode 100644 index 1fe0b413c..000000000 --- a/hicn-light/src/hicn/io/hicnTunnel.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file hicnTunnel.h - * @brief Establish a tunnel to a remote system - * - * Creates a "hicn tunnel" to a remote system. There must already be a local - * HICN listener for the local side of the connection. - * - */ - -#ifndef hicnTunnel_h -#define hicnTunnel_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/ioOperations.h> -#include <hicn/io/listener.h> -#include <hicn/utils/address.h> - -/** - * Establishes a connection to a remote system over HICN - * - * The remoteAddress must be of the same type (i.e. v4 or v6) as the - * localAddress. There must be an existing HICN listener on the local address. - * If either of these are not true, will return NULL. - * - * The connection will go in the table immediately, and will be in the "up" - * state. - * - * @param [in] an allocated hicn-light Forwarder - * @param [in] localAddress The local IP address and port to use for the - * connection - * @param [in] remote Address the remote IP address for the connection, must - * include a destination port. - * - * @retval non-null An allocated Io Operations structure for the connection - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -IoOperations *hicnTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress); - -IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder, - ListenerOps *localListener, - const Address *remoteAddress); - -#endif // hicnTunnel_h diff --git a/hicn-light/src/hicn/io/ioOperations.c b/hicn-light/src/hicn/io/ioOperations.c deleted file mode 100644 index 0087b320a..000000000 --- a/hicn-light/src/hicn/io/ioOperations.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <hicn/io/ioOperations.h> -#include <stdio.h> - -void *ioOperations_GetClosure(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - return ops->closure; -} - -bool ioOperations_Send(IoOperations *ops, const Address *nexthop, - Message *message) { - return ops->send(ops, nexthop, message); -} - -bool ioOperations_SendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size) { - return ops->sendIOVBuffer(ops, message, size); -} - -const Address *ioOperations_GetRemoteAddress(const IoOperations *ops) { - return ops->getRemoteAddress(ops); -} - -const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops) { - return ops->getAddressPair(ops); -} - - - -bool ioOperations_IsUp(const IoOperations *ops) { return ops->isUp(ops); } - -bool ioOperations_IsLocal(const IoOperations *ops) { return ops->isLocal(ops); } - -unsigned ioOperations_GetConnectionId(const IoOperations *ops) { - return ops->getConnectionId(ops); -} - -void ioOperations_Release(IoOperations **opsPtr) { - IoOperations *ops = *opsPtr; - ops->destroy(opsPtr); -} - -const void *ioOperations_Class(const IoOperations *ops) { - return ops->class(ops); -} - -list_connections_type ioOperations_GetConnectionType(const IoOperations *ops) { - return ops->getConnectionType(ops); -} - -void ioOperations_SendProbe(IoOperations *ops, uint8_t *message) { - ops->sendProbe(ops, message); -} - - -connection_state_t ioOperations_GetState(const IoOperations *ops) { - return ops->getState(ops); -} - -void ioOperations_SetState(IoOperations *ops, connection_state_t state) { - ops->setState(ops, state); -} - -connection_state_t ioOperations_GetAdminState(const IoOperations *ops) { - return ops->getAdminState(ops); -} - -void ioOperations_SetAdminState(IoOperations *ops, connection_state_t admin_state) { - ops->setAdminState(ops, admin_state); -} - -#ifdef WITH_POLICY -uint32_t ioOperations_GetPriority(const IoOperations *ops) { - return ops->getPriority(ops); -} - -void ioOperations_SetPriority(IoOperations *ops, uint32_t priority) { - ops->setPriority(ops, priority); -} -#endif /* WITH_POLICY */ - -const char * ioOperations_GetInterfaceName(const IoOperations *ops) { - return ops->getInterfaceName(ops); -} diff --git a/hicn-light/src/hicn/io/ioOperations.h b/hicn-light/src/hicn/io/ioOperations.h deleted file mode 100644 index 5d9befac3..000000000 --- a/hicn-light/src/hicn/io/ioOperations.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * Defines the interface all connections use to communicate with the forwarder. - */ - -/** - * I/O is built around a callback structure. The connection table contains an - * operations structure built around function pointers. These allow the - * connection table to be agnostic about underlying connections. - */ - -#ifndef io_h -#define io_h - -#include <hicn/core/connectionState.h> -#include <hicn/core/message.h> -#include <hicn/core/ticks.h> -#include <hicn/io/addressPair.h> -#include <hicn/utils/address.h> - -// packet types for probing -#define PACKET_TYPE_PROBE_REQUEST 5 -#define PACKET_TYPE_PROBE_REPLY 6 - -struct io_ops; -typedef struct io_ops IoOperations; - -/** - * @typedef IoOperations - * @abstract The IO Operations structure abstracts an connection's properties - * and send() method - * @constant context Implementation specific opaque data, passed back on each - * call - * @constant send function pointer to send a message, does not destroy the - * message - * @constant getRemoteAddress function pointer to return the "to" address - * associated with the connection. Some connections might not have a specific - * peer, such as multicast, where its the group address. - * @constant isUp test if the connection is up, ready to send a message. - * @constant isLocal test if the connection is local to the host. - * @constant getConnectionId returns the hicn-light id for the connection. - * @constant destroy releases a refernce count on the connection and possibly - * destroys the connection. - * @constant class A unique identifier for each class that instantiates - * IoOperations. - * @constant getConnectionType Returns the type of connection (TCP, UDP, L2, - * etc.) of the underlying connection. - * @constant getState Returns the current state of the connection (redundant - * with isUp for added for completeness of the API). - * @constant setState Allows to mark the current state of a connection. - * @constant getAdminState Returns the administrative state of a connection (as - * requested by the user, which might occasionally differ from the current - * state). - * @constant setAdminState Allows to set the administrative state of a - * connection. - * @constant getInterfaceName Returns the interface name associated to a - * connection. - * @discussion <#Discussion#> - */ -struct io_ops { - void *closure; - bool (*send)(IoOperations *ops, const Address *nexthop, Message *message); - bool (*sendIOVBuffer)(IoOperations *ops, struct iovec *message, size_t - size); - const Address *(*getRemoteAddress)(const IoOperations *ops); - const AddressPair *(*getAddressPair)(const IoOperations *ops); - bool (*isUp)(const IoOperations *ops); - bool (*isLocal)(const IoOperations *ops); - unsigned (*getConnectionId)(const IoOperations *ops); - void (*destroy)(IoOperations **opsPtr); - const void *(*class)(const IoOperations *ops); - list_connections_type (*getConnectionType)(const IoOperations *ops); - void (*sendProbe)(IoOperations *ops, uint8_t *message); - connection_state_t (*getState)(const IoOperations *ops); - void (*setState)(IoOperations *ops, connection_state_t state); - connection_state_t (*getAdminState)(const IoOperations *ops); - void (*setAdminState)(IoOperations *ops, connection_state_t admin_state); -#ifdef WITH_POLICY - uint32_t (*getPriority)(const IoOperations *ops); - void (*setPriority)(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ - const char * (*getInterfaceName)(const IoOperations *ops); -}; - -/** - * Returns the closure of the interface - * - * The creator of the closure sets this parameter to store its state. - * - * @param [in] ops A concrete instance of the interface - * - * @return The value set by the concrete instance of the interface. - * - * Example: - * @clode - * { - - * } - * @endcode - */ -void *ioOperations_GetClosure(const IoOperations *ops); - -/** - * Release all memory related to the interface and implementation - * - * This function must release all referenced memory in the concrete - * implementation and memory related to the IoOperations. It should NULL the - * input parameter. - * - * @param [in,out] opsPtr Pointer to interface. Will be NULLed. - * - * Example: - * @code - * - * static void - * _etherConnection_InternalRelease(_EtherState *etherConnState) - * { - * // release internal state of _EtherState - * } - * - * static void - * _etherConnection_Release(IoOperations **opsPtr) - * { - * IoOperations *ops = *opsPtr; - * - * _EtherState *etherConnState = (_EtherState *) - * ioOperations_GetClosure(ops); - * _etherConnection_InternalRelease(etherConnState); - * - * parcMemory_Deallocate((void **) &ops); - * } - * - * IoOperations * - * etherConnection_Create(Forwarder *forwarder, GenericEther *ether, - * AddressPair *pair) - * { - * size_t allocationSize = sizeof(_EtherState) + sizeof(IoOperations); - * IoOperations *ops = parcMemory_AllocateAndClear(allocationSize); - * if (ops) { - * // fill in other interface functions - * ops->destroy = &_etherConnection_Release; - * ops->closure = (uint8_t *) ops + sizeof(IoOperations); - * - * _EtherState *etherConnState = ioOperations_GetClosure(ops); - * // fill in Ethernet state - * } - * return ops; - * } - * @endcode - */ -void ioOperations_Release(IoOperations **opsPtr); - -/** - * Sends the specified Message out this connection - * - * The the implementation of send may queue the message, it must acquire a - * reference to it. - * - * @param [in] ops The connection implementation. - * @param [in] nexthop On multiple access networks, this parameter might be - * used, usually NULL. - * @param [in] message The message to send. If the message will be queued, it - * will be acquired. - * - * @return true The message was sent or queued - * @retrun false An error occured and the message will not be sent or queued - * - * Example: - * @code - * { - * if (ioOperations_IsUp(conn->ops)) { - * return ioOperations_Send(conn->ops, NULL, message); - * } - * } - * @endcode - */ -bool ioOperations_Send(IoOperations *ops, const Address *nexthop, - Message *message); - -bool ioOperations_SendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size); - -/** - * A connection is made up of a local and a remote address. This function - * returns the remote address. - * - * Represents the destination endpoint of the communication. - * - * @param [in] ops The connection implementation. - * - * @return non-null The remote address - * @return null The connection does not have a remote address - * - * Example: - * @code - * { - * Address *local = addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03, - * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t []) - * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair = - * addressPair_Create(local, remote); IoOperations *ops = - * etherConnection_Create(forwarder, ether, pair); - * - * const Address *test = ioOperations_GetRemoteAddress(ops); - * parcAssertTrue(addressEquals(test, remote), "Wrong remote address"); - * ioOperations_Release(&ops); - * addressPair_Release(&pair); - * addressDestroy(&local); - * addressDestroy(&remote); - * } - * @endcode - */ -const Address *ioOperations_GetRemoteAddress(const IoOperations *ops); - -/** - * A connection is made up of a local and a remote address. This function - * returns the address pair. - * - * Represents the destination endpoint of the communication. - * - * @param [in] ops The connection implementation. - * - * @return non-null The address pair - * @return null An error. - * - * Example: - * @code - * { - * Address *local = addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03, - * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t []) - * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair = - * addressPair_Create(local, remote); IoOperations *ops = - * etherConnection_Create(forwarder, ether, pair); - * - * const AddressPair *test = ioOperations_GetAddressPair(ops); - * parcAssertTrue(addressPair(test, pair), "Wrong address pair"); - * ioOperations_Release(&ops); - * addressPair_Release(&pair); - * addressDestroy(&local); - * addressDestroy(&remote); - * } - * @endcode - */ -const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops); - -/** - * Returns true if the underlying connection is in operation - * - * An UP connection is able to send and receive packets. If a subsystem needs to - * take actions when a connection goes UP or DOWN, it should subscribe as a - * Missive listener. - * - * @param [in] ops The connection implementation. - * - * @return true The connection is UP - * @return false The connection is not UP - * - * Example: - * @code - * { - * if (ioOperations_IsUp(conn->ops)) { - * return ioOperations_Send(conn->ops, NULL, message); - * } - * } - * @endcode - */ -bool ioOperations_IsUp(const IoOperations *ops); - -/** - * If the remote address is local to this system, returns true - * - * Will return true if an INET or INET6 connection is on localhost. Will return - * true for AF_UNIX. An Ethernet connection is not local. - * - * @param [in] ops The connection implementation. - * - * @return true The remote address is local to the system - * @return false The remote address is not local - * - * Example: - * @code - * { - * // Is the ingress connection remote? If so check for non-zero and - * decrement if (!ioOperations(ingressConnectionOps) { uint8_t hoplimit = - * message_GetHopLimit(interestMessage); if (hoplimit == 0) { - * // error - * } else { - * hoplimit--; - * } - * // take actions on hoplimit - * } - * } - * @endcode - */ -bool ioOperations_IsLocal(const IoOperations *ops); - -/** - * Returns the connection ID represented by this IoOperations in the - * ConnectionTable. - * - * <#Paragraphs Of Explanation#> - * - * @param [in] ops The connection implementation. - * - * @return number The connection ID in the connection table. - * - * Example: - * @code - * { - * unsigned id = ioOperations_GetConnectionId(ingressIoOps); - * const Connection *conn = - * connectionTable_FindById(forwarder->connectionTable, id); - * } - * @endcode - */ -unsigned ioOperations_GetConnectionId(const IoOperations *ops); - -/** - * A pointer that represents the class of the connection - * - * Each concrete implementation has a class pointer that is unique to the - * implementation (not instance). Each implementation is free to choose how to - * determine the value, so long as it is unique on the system. This is a - * system-local value. - * - * @param [in] ops The connection implementation. - * - * @return non-null A pointer value unique to the implementation (not instance). - * - * Example: - * @code - * bool - * etherConnection_IsInstanceOf(const Connection *conn) - * { - * bool result = false; - * if (conn != NULL) { - * IoOperations *ops = connection_GetIoOperations(conn); - * const void *class = ioOperations_Class(ops); - * result = (class == _etherConnection_Class(ops)); - * } - * return result; - * } - * @endcode - */ -const void *ioOperations_Class(const IoOperations *ops); - -/** - * Returns the transport type of the connection (TCP, UDP, L2, etc.). - * - * TCP and AF_UNIX are both stream connections and will both return - * "Connection_TCP". Ethernet will return "Connection_L2". - * - * @param [in] ops The connection implementation. - * - * @return Connection_TCP A TCP4, TCP6, or AF_UNIX connection - * @return Connection_UDP A UDP4 or UDP6 connection - * @return Connection_L2 An Ethernet connection - * - * Example: - * @code - * { - * ConnectionType type = - * ioOperations_GetConnectionType(connection_GetIoOperations(connection)); - * Connection *Conn = - * Connection_Create(connection_GetConnectionId(connection), localAddress, - * remoteAddress, type); - * } - * @endcode - */ -list_connections_type ioOperations_GetConnectionType(const IoOperations *ops); - -void ioOperations_SendProbe(IoOperations *ops, uint8_t *message); - - -/** - * Returns the current state of the connection - * - * @param [in] ops The connection implementation. - * - * @return Connection state (connection_state_t). - */ -connection_state_t ioOperations_GetState(const IoOperations *ops); - -/** - * Sets the current state of the connection - * - * @param [in] ops The connection implementation. - * @param [in] state New state to set (connection_state_t). - */ -void ioOperations_SetState(IoOperations *ops, connection_state_t state); - -/** - * Returns the administrative state of the connection - * - * @param [in] ops The connection implementation. - * - * @return Connection state (connection_state_t). - */ -connection_state_t ioOperations_GetAdminState(const IoOperations *ops); - -/** - * Sets the administrative state of the connection - * - * @param [in] ops The connection implementation. - * @param [in] state New state to set (connection_state_t). - */ -void ioOperations_SetAdminState(IoOperations *ops, connection_state_t admin_state); - -#ifdef WITH_POLICY -/** - * Returns the priority of the connection - * - * @param [in] ops The connection implementation. - * - * @return Connection state (uint32_t). - */ -uint32_t ioOperations_GetPriority(const IoOperations *ops); - -/** - * Sets the priority of the connection - * - * @param [in] ops The connection implementation. - * @param [in] state New state to set (uint32_t). - */ -void ioOperations_SetPriority(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ - -/** - * Sets the interface name associated to the connection. - * - * @param [in] ops The connection implementation. - * @return the name associated to the connection (const char *) - */ -const char * ioOperations_GetInterfaceName(const IoOperations *ops); - -#endif // io_h diff --git a/hicn-light/src/hicn/io/listener.h b/hicn-light/src/hicn/io/listener.h deleted file mode 100644 index 1b473be59..000000000 --- a/hicn-light/src/hicn/io/listener.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file listener.h - * @brief Provides the function abstraction of all Listeners. - * - * A listener accepts in coming packets. A Stream listener will accept the - * connection then pass it off to the {@link StreamConnection} class. A - * datagram listener will have to have its own way to multiplex packets. - * - */ - -#ifndef listener_h -#define listener_h - -#include <hicn/utils/address.h> -#include <hicn/io/addressPair.h> -#include <hicn/core/connection.h> - -struct listener_ops; -typedef struct listener_ops ListenerOps; - -typedef enum { - ENCAP_TCP, /**< TCP encapsulation type */ - ENCAP_UDP, /**< UDP encapsulation type */ - ENCAP_ETHER, /**< Ethernet encapsulation type */ - ENCAP_LOCAL, /**< A connection to a local protocol stack */ - ENCAP_HICN -} EncapType; - -struct listener_ops { - /** - * A user-defined parameter - */ - void *context; - - /** - * Called to destroy the Listener. - * - * @param [in] listenerOpsPtr Double pointer to this structure - */ - void (*destroy)(ListenerOps **listenerOpsPtr); - - /** - * Returns the listener name of the listener. - * - * @param [in] ops Pointer to this structure - * - * @return the listener name of the listener - */ - const char *(*getListenerName)(const ListenerOps *ops); - - /** - * Returns the interface index of the listener. - * - * @param [in] ops Pointer to this structure - * - * @return the interface index of the listener - */ - unsigned (*getInterfaceIndex)(const ListenerOps *ops); - - /** - * Returns the address pair that defines the listener (local, remote) - * - * @param [in] ops Pointer to this structure - * - * @return the (local, remote) pair of addresses - */ - const Address *(*getListenAddress)(const ListenerOps *ops); - - /** - * Returns the encapsulation type of the listener (e.g. TCP, UDP, HICN) - * - * @param [in] ops Pointer to this structure - * - * @return the listener encapsulation type - */ - EncapType (*getEncapType)(const ListenerOps *ops); - - /** - * Returns the interface name of the listener. - * - * @param [in] ops Pointer to this structure - * - * @return the interface name of the listener - */ - const char *(*getInterfaceName)(const ListenerOps *ops); - - /** - * Returns the underlying socket associated with the listener - * - * Not all listeners are capable of returning a useful socket. In those - * cases, this function pointer is NULL. - * - * TCP does not support this operation (function is NULL). UDP returns its - * local socket. - * - * The caller should never close this socket, the listener will do that when - * its destroy method is called. - * - * @param [in] ops Pointer to this structure - * - * @retval integer The socket descriptor - * - * Example: - * @code - * <#example#> - * @endcode - */ - int (*getSocket)(const ListenerOps *ops); - - unsigned (*createConnection)(ListenerOps *listener, int fd, const AddressPair *pair); - const Connection * (*lookupConnection)(ListenerOps * listener, const AddressPair *pair); -}; -#endif // listener_h diff --git a/hicn-light/src/hicn/io/listenerSet.c b/hicn-light/src/hicn/io/listenerSet.c deleted file mode 100644 index d69632287..000000000 --- a/hicn-light/src/hicn/io/listenerSet.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/io/listenerSet.h> - -struct listener_set { - PARCArrayList *listOfListeners; -}; - -static void listenerSet_DestroyListenerOps(void **opsPtr) { - ListenerOps *ops = *((ListenerOps **)opsPtr); - ops->destroy(&ops); -} - -ListenerSet *listenerSet_Create() { - ListenerSet *set = parcMemory_AllocateAndClear(sizeof(ListenerSet)); - parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerSet)); - set->listOfListeners = parcArrayList_Create(listenerSet_DestroyListenerOps); - - return set; -} - -void listenerSet_Destroy(ListenerSet **setPtr) { - parcAssertNotNull(setPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer"); - - ListenerSet *set = *setPtr; - parcArrayList_Destroy(&set->listOfListeners); - parcMemory_Deallocate((void **)&set); - *setPtr = NULL; -} - -/** - * @function listenerSet_Add - * @abstract Adds the listener to the set - * @discussion - * Unique set based on pair (EncapType, localAddress) - * - * @param <#param1#> - * @return <#return#> - */ -bool listenerSet_Add(ListenerSet *set, ListenerOps *ops) { - parcAssertNotNull(set, "Parameter set must be non-null"); - parcAssertNotNull(ops, "Parameter ops must be non-null"); - - int opsEncap = ops->getEncapType(ops); - const Address *opsAddress = ops->getListenAddress(ops); - - // make sure its not in the set - size_t length = parcArrayList_Size(set->listOfListeners); - for (size_t i = 0; i < length; i++) { - ListenerOps *entry = parcArrayList_Get(set->listOfListeners, i); - - int entryEncap = entry->getEncapType(entry); - const Address *entryAddress = entry->getListenAddress(entry); - - if (opsEncap == entryEncap && addressEquals(opsAddress, entryAddress)) { - // duplicate - return false; - } - } - - parcArrayList_Add(set->listOfListeners, ops); - return true; -} - -size_t listenerSet_Length(const ListenerSet *set) { - parcAssertNotNull(set, "Parameter set must be non-null"); - return parcArrayList_Size(set->listOfListeners); -} - -/** - * Returns the listener at the given index - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] index The index position (0 <= index < listenerSet_Count) - * - * @retval non-null The listener at index - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index) { - parcAssertNotNull(set, "Parameter set must be non-null"); - return parcArrayList_Get(set->listOfListeners, index); -} - -ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType, - const Address *localAddress) { - parcAssertNotNull(set, "Parameter set must be non-null"); - parcAssertNotNull(localAddress, "Parameter localAddress must be non-null"); - - ListenerOps *match = NULL; - - for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match; - i++) { - ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); - parcAssertNotNull(ops, "Got null listener ops at index %zu", i); - - if (ops->getEncapType(ops) == encapType) { - if (addressEquals(localAddress, ops->getListenAddress(ops))) { - match = ops; - } - } - } - - return match; -} - -ListenerOps *listenerSet_FindById(const ListenerSet *set, unsigned id) { - parcAssertNotNull(set, "Parameter set must be non-null"); - - ListenerOps *match = NULL; - - for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match; - i++) { - ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); - parcAssertNotNull(ops, "Got null listener ops at index %zu", i); - if (ops->getInterfaceIndex(ops) == id) { - match = ops; - } - } - - return match; -} - -int listenerSet_FindIdByListenerName(const ListenerSet *set, const char *listenerName ) { - parcAssertNotNull(set, "Parameter set must be non-null"); - parcAssertNotNull(listenerName, "Parameter listenerName must be non-null"); - - ListenerOps *match = NULL; - int index = -1; - for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match; - i++) { - ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); - parcAssertNotNull(ops, "Got null listener ops at index %zu", i); - if (ops->getListenerName(ops) && strcmp(ops->getListenerName(ops), listenerName) == 0) { - index = ops->getInterfaceIndex(ops); - break; - } - } - - return index; -} - -void listenerSet_RemoveById(const ListenerSet *set, unsigned id) { - parcAssertNotNull(set, "Parameter set must be non-null"); - - for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners); - i++) { - ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); - parcAssertNotNull(ops, "Got null listener ops at index %zu", i); - if (ops->getInterfaceIndex(ops) == id) { - parcArrayList_RemoveAndDestroyAtIndex(set->listOfListeners, i); - break; - } - } -} diff --git a/hicn-light/src/hicn/io/listenerSet.h b/hicn-light/src/hicn/io/listenerSet.h deleted file mode 100644 index 5779d2af4..000000000 --- a/hicn-light/src/hicn/io/listenerSet.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file listenerSet.h - * @brief A listener set is unique on (EncapType, localAddress) - * - * Keeps track of all the running listeners. The set is unique on the - * encapsulation type and the local address. For example, with TCP - * encapsulation and local address 127.0.0.1 or Ethernet encapsulation and MAC - * address 00:11:22:33:44:55. - * - * NOTE: This does not allow multiple EtherType on the same interface because - * the Address for a LINK address does not include an EtherType. - * - */ - -#ifndef listenerSet_h -#define listenerSet_h - -#include <hicn/io/listener.h> - -struct listener_set; -typedef struct listener_set ListenerSet; - -/** - * <#One Line Description#> - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @retval <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -ListenerSet *listenerSet_Create(void); - -/** - * <#One Line Description#> - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @retval <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -void listenerSet_Destroy(ListenerSet **setPtr); - -/** - * @function listenerSet_Add - * @abstract Adds the listener to the set - * @discussion - * Unique set based on pair (EncapType, localAddress). - * Takes ownership of the ops memory if added. - * - * @param <#param1#> - * @return true if added, false if not - */ -bool listenerSet_Add(ListenerSet *set, ListenerOps *ops); - -/** - * The number of listeners in the set - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * - * @retval <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -size_t listenerSet_Length(const ListenerSet *set); -size_t listenerSet_Length(const ListenerSet *set); - -/** - * Returns the listener at the given index - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] index The index position (0 <= index < listenerSet_Lenght) - * - * @retval non-null The listener at index - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index); - -/** - * Looks up a listener by its key (EncapType, LocalAddress) - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] encapType the listener type - * @param [in] localAddress The local bind address (e.g. MAC address or TCP - * socket) - * - * @retval non-null The listener matching the query - * @retval null Does not exist - * - * Example: - * @code - * - * @endcode - */ -ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType, - const Address *localAddress); - -/** - * Looks up a listener by its id - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] id of the listener - * - * @retval non-null The listener matching the query - * @retval null Does not exist - * - * Example: - * @code - * - * @endcode - */ -ListenerOps *listenerSet_FindById(const ListenerSet *set, unsigned id); - -/** - * Looks up a listener by its id - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] name of the listener - * - * @retval greater or equal to 0 The listener matching the query - * @retval -1 Does not exist - * - * Example: - * @code - * - * @endcode - */ -int listenerSet_FindIdByListenerName(const ListenerSet *set, const char *listenerName); - -/** - * Remove up a listener by its id - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] id of the listener - * - * Example: - * @code - * - * @endcode - */ -void listenerSet_RemoveById(const ListenerSet *set, unsigned id); -#endif diff --git a/hicn-light/src/hicn/io/streamConnection.c b/hicn-light/src/hicn/io/streamConnection.c deleted file mode 100644 index 53ffa74c3..000000000 --- a/hicn-light/src/hicn/io/streamConnection.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * Common activity for STREAM based listeners. - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <parc/algol/parc_Hash.h> -#include <hicn/core/connection.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/message.h> -#include <hicn/io/streamConnection.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/messageHandler.h> - -#include <hicn/utils/commands.h> - -#include <hicn/hicn.h> -// 128 KB output queue -#define OUTPUT_QUEUE_BYTES (128 * 1024) - -static void _conn_readcb(PARCEventQueue *bufferEventVector, PARCEventType type, - void *ioOpsVoid); - -static void _conn_eventcb(PARCEventQueue *bufferEventVector, - PARCEventQueueEventType events, void *ioOpsVoid); - -typedef struct stream_state { - Forwarder *forwarder; - char * interfaceName; - Logger *logger; - - int fd; - - AddressPair *addressPair; - PARCEventQueue *bufferEventVector; - - bool isLocal; - bool isUp; - bool isClosed; - unsigned id; - - size_t nextMessageLength; - - /* This information would better be stored in the connection data structure - * but it is currently not reachable from within the implementation. */ - connection_state_t state; - connection_state_t admin_state; -#ifdef WITH_POLICY - uint32_t priority; -#endif /* WITH_POLICY */ -} _StreamState; - -// Prototypes -static bool _streamConnection_Send(IoOperations *ops, const Address *nexthop, - Message *message); -static bool _streamConnection_SendIOVBuffer(IoOperations *ops, struct - iovec *msg, size_t size); -static const Address *_streamConnection_GetRemoteAddress( - const IoOperations *ops); -static const AddressPair *_streamConnection_GetAddressPair( - const IoOperations *ops); -static unsigned _streamConnection_GetConnectionId(const IoOperations *ops); -static bool _streamConnection_IsUp(const IoOperations *ops); -static bool _streamConnection_IsLocal(const IoOperations *ops); -static void _streamConnection_DestroyOperations(IoOperations **opsPtr); - -static void _setConnectionState(_StreamState *stream, bool isUp); -static list_connections_type _streamConnection_GetConnectionType( - const IoOperations *ops); -static void _sendProbe(IoOperations *ops, uint8_t *message); -static connection_state_t _streamConnection_getState(const IoOperations *ops); -static void _streamConnection_setState(IoOperations *ops, connection_state_t state); -static connection_state_t _streamConnection_getAdminState(const IoOperations *ops); -static void _streamConnection_setAdminState(IoOperations *ops, connection_state_t admin_state); -#ifdef WITH_POLICY -static uint32_t _streamConnection_getPriority(const IoOperations *ops); -static void _streamConnection_setPriority(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ -static const char * _streamConnection_getInterfaceName(const IoOperations *ops); - -/* - * This assigns a unique pointer to the void * which we use - * as a GUID for this class. - */ -static const void *_ioOperationsGuid = __FILE__; - -/* - * Return our GUID - */ -static const void *_streamConnection_Class(const IoOperations *ops) { - return _ioOperationsGuid; -} - -static IoOperations _template = { - .closure = NULL, - .send = &_streamConnection_Send, - .sendIOVBuffer = &_streamConnection_SendIOVBuffer, - .getRemoteAddress = &_streamConnection_GetRemoteAddress, - .getAddressPair = &_streamConnection_GetAddressPair, - .getConnectionId = &_streamConnection_GetConnectionId, - .isUp = &_streamConnection_IsUp, - .isLocal = &_streamConnection_IsLocal, - .destroy = &_streamConnection_DestroyOperations, - .class = &_streamConnection_Class, - .getConnectionType = &_streamConnection_GetConnectionType, - .sendProbe = &_sendProbe, - .getState = &_streamConnection_getState, - .setState = &_streamConnection_setState, - .getAdminState = &_streamConnection_getAdminState, - .setAdminState = &_streamConnection_setAdminState, -#ifdef WITH_POLICY - .getPriority = &_streamConnection_getPriority, - .setPriority = &_streamConnection_setPriority, -#endif /* WITH_POLICY */ - .getInterfaceName = &_streamConnection_getInterfaceName, -}; - -IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd, - AddressPair *pair, - bool isLocal) { - _StreamState *stream = parcMemory_AllocateAndClear(sizeof(_StreamState)); - parcAssertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_StreamState)); - - Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder); - PARCEventScheduler *eventBase = dispatcher_GetEventScheduler(dispatcher); - stream->bufferEventVector = parcEventQueue_Create( - eventBase, fd, - PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks); - - stream->forwarder = forwarder; - stream->interfaceName = NULL; - stream->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - stream->fd = fd; - stream->id = forwarder_GetNextConnectionId(forwarder); - stream->addressPair = pair; - stream->isClosed = false; - -#ifdef WITH_POLICY - stream->priority = 0; -#endif /* WITH_POLICY */ - - // allocate a connection - IoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations)); - parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(IoOperations)); - memcpy(io_ops, &_template, sizeof(IoOperations)); - io_ops->closure = stream; - stream->isLocal = isLocal; - - parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL, - _conn_eventcb, (void *)io_ops); - parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read); - - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionCreate, stream->id)); - - // As we are acceting a connection, we begin in the UP state - _setConnectionState(stream, true); - - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - char *pair_str = addressPair_ToString(pair); - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "StreamConnection %p accept for address pair %s", (void *)stream, - pair_str); - free(pair_str); - } - - return io_ops; -} - -IoOperations *streamConnection_OpenConnection(Forwarder *forwarder, - AddressPair *pair, bool isLocal) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(pair, "Parameter pair must be non-null"); - - // if there's an error on the bind or connect, will return NULL - PARCEventQueue *bufferEventVector = - dispatcher_StreamBufferConnect(forwarder_GetDispatcher(forwarder), pair); - if (bufferEventVector == NULL) { - // error opening connection - return NULL; - } - - _StreamState *stream = parcMemory_AllocateAndClear(sizeof(_StreamState)); - parcAssertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_StreamState)); - - stream->forwarder = forwarder; - stream->interfaceName = NULL; - stream->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - stream->fd = parcEventQueue_GetFileDescriptor(bufferEventVector); - stream->bufferEventVector = bufferEventVector; - stream->id = forwarder_GetNextConnectionId(forwarder); - stream->addressPair = pair; - stream->isClosed = false; - - // allocate a connection - IoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations)); - parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(IoOperations)); - memcpy(io_ops, &_template, sizeof(IoOperations)); - io_ops->closure = stream; - stream->isLocal = isLocal; - - parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL, - _conn_eventcb, (void *)io_ops); - parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read); - - // we start in DOWN state, until remote side answers - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionCreate, stream->id)); - _setConnectionState(stream, false); - - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, PARCLogLevel_Info)) { - char *pair_str = addressPair_ToString(pair); - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__, - "StreamConnection %p connect for address pair %s", - (void *)stream, pair_str); - free(pair_str); - } - - return io_ops; -} - -static void _streamConnection_DestroyOperations(IoOperations **opsPtr) { - parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer"); - parcAssertNotNull(*opsPtr, - "Parameter opsPtr must dereference to non-null pointer"); - - IoOperations *ops = *opsPtr; - parcAssertNotNull(ioOperations_GetClosure(ops), - "ops->context must not be null"); - - _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops); - - parcEventQueue_Destroy(&stream->bufferEventVector); - - addressPair_Release(&stream->addressPair); - - if (!stream->isClosed) { - stream->isClosed = true; - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionClosed, stream->id)); - } - - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionDestroyed, stream->id)); - - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, PARCLogLevel_Info)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__, - "StreamConnection %p destroyed", (void *)stream); - } - - logger_Release(&stream->logger); - parcMemory_Deallocate((void **)&stream); - parcMemory_Deallocate((void **)&ops); - - *opsPtr = NULL; -} - -static bool _streamConnection_IsUp(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->isUp; -} - -static bool _streamConnection_IsLocal(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->isLocal; -} - -static const Address *_streamConnection_GetRemoteAddress( - const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return addressPair_GetRemote(stream->addressPair); -} - -static const AddressPair *_streamConnection_GetAddressPair( - const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->addressPair; -} - -static unsigned _streamConnection_GetConnectionId(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->id; -} - -bool _streamConnection_SendIOVBuffer(IoOperations *ops, - struct iovec * message, size_t size) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - - _StreamState *conn = (_StreamState *)ioOperations_GetClosure(ops); - - if (!conn->isUp) { - if (logger_IsLoggable(conn->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - logger_Log( - conn->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "connid %u tried to send to down connection (isUp %d isClosed %d)", - conn->id, conn->isUp, conn->isClosed); - } - return false; - } - - PARCEventBuffer *buffer = - parcEventBuffer_GetQueueBufferOutput(conn->bufferEventVector); - size_t buffer_backlog = parcEventBuffer_GetLength(buffer); - parcEventBuffer_Destroy(&buffer); - - if (buffer_backlog >= OUTPUT_QUEUE_BYTES) { - if (logger_IsLoggable(conn->logger, LoggerFacility_IO, - PARCLogLevel_Warning)) { - logger_Log(conn->logger, LoggerFacility_IO, PARCLogLevel_Warning, - __func__, - "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE", - conn->id, buffer_backlog); - } - return false; - } - - if (logger_IsLoggable(conn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - size_t length = 0; - for (int i = 0; i < size; i++) - length += message[i].iov_len; - - logger_Log( conn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "connid %u Writing %zu bytes to buffer with backlog %zu bytes", - conn->id, length, buffer_backlog); - } - - /* Write directly into the parcEventQueue without passing through message */ - for (int i = 0; i < size; i++) { - if (parcEventQueue_Write(conn->bufferEventVector, message[i].iov_base, - message[i].iov_len) != 0) - return false; - } - - return true; -} - -/** - * @function streamConnection_Send - * @abstract Non-destructive send of the message. - * @discussion - * Send uses message_CopyToStreamBuffer, which is a non-destructive write. - * The send may fail if there's no buffer space in the output queue. - * - * @param dummy is ignored. A stream has only one peer. - * @return <#return#> - */ -static bool _streamConnection_Send(IoOperations *ops, const Address *dummy, - Message *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops); - - bool success = false; - if (stream->isUp) { - PARCEventBuffer *buffer = - parcEventBuffer_GetQueueBufferOutput(stream->bufferEventVector); - size_t buffer_backlog = parcEventBuffer_GetLength(buffer); - parcEventBuffer_Destroy(&buffer); - - if (buffer_backlog < OUTPUT_QUEUE_BYTES) { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log( - stream->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "connid %u Writing %zu bytes to buffer with backlog %zu bytes", - stream->id, message_Length(message), buffer_backlog); - } - - int failure = message_Write(stream->bufferEventVector, message); - if (failure == 0) { - success = true; - } - } else { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Warning)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Warning, - __func__, - "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE", - stream->id, buffer_backlog); - } - } - } else { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - logger_Log( - stream->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "connid %u tried to send to down connection (isUp %d isClosed %d)", - stream->id, stream->isUp, stream->isClosed); - } - } - - return success; -} - -list_connections_type _streamConnection_GetConnectionType( - const IoOperations *ops) { - return CONN_TCP; -} - -static void _sendProbe(IoOperations *ops, uint8_t *message) { - // we don't need to implemet this here, it is a local connection -} - -// ================================================================= -// the actual I/O functions - -int _isACommand(PARCEventBuffer *input) { - size_t bytesAvailable = parcEventBuffer_GetLength(input); - parcAssertTrue(bytesAvailable >= sizeof(header_control_message), - "Called with too short an input: %zu", bytesAvailable); - - uint8_t *msg = parcEventBuffer_Pullup(input, bytesAvailable); - // read first byte of the header - - // first byte: must be a REQUEST_LIGHT - if (msg[0] != REQUEST_LIGHT) { - return LAST_COMMAND_VALUE; - } - - // second byte: must be a command_id - if (msg[1] < 0 || msg[1] >= LAST_COMMAND_VALUE) { - return LAST_COMMAND_VALUE; - } - - return msg[1]; -} - -PARCEventBuffer *_tryReadControlMessage(_StreamState *stream, - PARCEventBuffer *input, - command_id command, - struct iovec **request) { - size_t bytesAvailable = parcEventBuffer_GetLength(input); - - if (stream->nextMessageLength == 0) { - stream->nextMessageLength = - sizeof(header_control_message) + - payloadLengthDaemon(command); // consider the whole packet. - } - - if (bytesAvailable >= stream->nextMessageLength) { - PARCEventBuffer *message = parcEventBuffer_Create(); - int bytesRead = parcEventBuffer_ReadIntoBuffer(input, message, - stream->nextMessageLength); - parcAssertTrue(bytesRead == stream->nextMessageLength, - "Partial read, expected %zu got %d", - stream->nextMessageLength, bytesRead); - - uint8_t *control = - parcEventBuffer_Pullup(message, stream->nextMessageLength); - if (!(*request = (struct iovec *)parcMemory_AllocateAndClear( - sizeof(struct iovec) * 2))) { - return NULL; - } - (*request)[0].iov_base = control; // header - (*request)[0].iov_len = sizeof(header_control_message); - if (payloadLengthDaemon(command) > 0) { - (*request)[1].iov_base = - control + sizeof(header_control_message); // payload - } else { - (*request)[1].iov_base = NULL; - } - (*request)[1].iov_len = payloadLengthDaemon(command); - // now reset message length for next packet - - stream->nextMessageLength = 0; - - return message; - } - - return NULL; -} - -static bool _isAnHicnPacket(PARCEventBuffer *input) { - size_t bytesAvailable = parcEventBuffer_GetLength(input); - parcAssertTrue(bytesAvailable >= sizeof(header_control_message), - "Called with too short an input: %zu", bytesAvailable); - - uint8_t *fh = parcEventBuffer_Pullup(input, sizeof(header_control_message)); - return messageHandler_IsValidHicnPacket(fh); -} - -static Message *_readMessage(_StreamState *stream, Ticks time, - PARCEventBuffer *input) { - Message *message = message_CreateFromEventBuffer( - input, stream->nextMessageLength, stream->id, time, stream->logger); - - return message; -} - -static void _startNewMessage(_StreamState *stream, PARCEventBuffer *input, - size_t inputBytesAvailable) { - parcAssertTrue(stream->nextMessageLength == 0, - "Invalid state, nextMessageLength not zero: %zu", - stream->nextMessageLength); - parcAssertTrue(inputBytesAvailable >= sizeof(header_control_message), - "read_length not a whole fixed header!: %zd", - inputBytesAvailable); - - // this linearizes the first messageHandler_GetIPv6HeaderLength() bytes of the - // input buffer's iovecs and returns a pointer to it. - uint8_t *fh = parcEventBuffer_Pullup(input, sizeof(header_control_message)); - - // Calculate the total message size based on the fixed header - stream->nextMessageLength = messageHandler_GetTotalPacketLength(fh); -} - -static Message *_tryReadMessage(PARCEventBuffer *input, _StreamState *stream) { - size_t bytesAvailable = parcEventBuffer_GetLength(input); - parcAssertTrue(bytesAvailable >= sizeof(header_control_message), - "Called with too short an input: %zu", bytesAvailable); - - if (stream->nextMessageLength == 0) { - _startNewMessage(stream, input, bytesAvailable); - } - - // This is not an ELSE statement. We can both start a new message then - // check if there's enough bytes to read the whole thing. - - if (bytesAvailable >= stream->nextMessageLength) { - Message *message = - _readMessage(stream, forwarder_GetTicks(stream->forwarder), input); - - // now reset message length for next packet - stream->nextMessageLength = 0; - - return message; - } - - return NULL; -} - -/** - * @function conn_readcb - * @abstract Event callback for reads - * @discussion - * Will read messages off the input. Continues reading as long as we - * can get a header to determine the next message length or as long as we - * can read a complete message. - * - * This function manipulates the read low water mark. (1) read a fixed header - * plus complete message, then set the low water mark to FIXED_HEADER_LEN. (2) - * read a fixed header, but not a complete message, then set low water mark to - * the total mesage length. Using the low water mark like this means the buffer - * event will only trigger on meaningful byte boundaries when we can get actual - * work done. - * - * @param <#param1#> - * @return <#return#> - */ -static void _conn_readcb(PARCEventQueue *event, PARCEventType type, - void *ioOpsVoid) { - command_id command; - IoOperations *ops = (IoOperations *)ioOpsVoid; - _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops); - - PARCEventBuffer *input = parcEventBuffer_GetQueueBufferInput(event); - - // drain the input buffer - - // notice that we always try to read at least 8 bytes - // (sizeof(header_control_message)). This is enough to read the length of all - // kind of packets - while (parcEventBuffer_GetLength(input) >= sizeof(header_control_message) && - parcEventBuffer_GetLength(input) >= stream->nextMessageLength) { - - if ((command = _isACommand(input)) != LAST_COMMAND_VALUE) { - struct iovec *rx; - // Get message from the stream and set the stream->nextMessageLength - PARCEventBuffer *message = - _tryReadControlMessage(stream, input, command, &rx); - // If received correctly the whole message, send to dispatcher - if (message) { - forwarder_ReceiveCommand(stream->forwarder, command, rx, stream->id); - //parcMemory_Deallocate((void **)&rx); - parcEventBuffer_Destroy(&message); - } - - } else if (_isAnHicnPacket(input)) { - // this is an Hicn packet (here we should distinguish between IPv4 and - // IPv6 tryReadMessage may set nextMessageLength - Message *message = _tryReadMessage(input, stream); - - if (message) { - forwarder_Receive(stream->forwarder, message); - } - - } else { - parcAssertTrue(false, - "(Local stream connection) malformed packet received"); - } - } - - if (stream->nextMessageLength == 0) { - // we don't have the next header, so set it to the header length - streamBuffer_SetWatermark(event, true, false, - sizeof(header_control_message), 0); - } else { - // set it to the packet length - streamBuffer_SetWatermark(event, true, false, stream->nextMessageLength, 0); - } - parcEventBuffer_Destroy(&input); -} - -static void _setConnectionState(_StreamState *stream, bool isUp) { - parcAssertNotNull(stream, "Parameter stream must be non-null"); - - Messenger *messenger = forwarder_GetMessenger(stream->forwarder); - - bool oldStateIsUp = stream->isUp; - stream->isUp = isUp; - - if (oldStateIsUp && !isUp) { - // bring connection DOWN - Missive *missive = missive_Create(MissiveType_ConnectionDown, stream->id); - messenger_Send(messenger, missive); - return; - } - - if (!oldStateIsUp && isUp) { - // bring connection UP - Missive *missive = missive_Create(MissiveType_ConnectionUp, stream->id); - messenger_Send(messenger, missive); - return; - } -} - -static void _conn_eventcb(PARCEventQueue *event, PARCEventQueueEventType events, - void *ioOpsVoid) { - IoOperations *ops = (IoOperations *)ioOpsVoid; - _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops); - - if (events & PARCEventQueueEventType_Connected) { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__, - "Connection %u is connected", stream->id); - } - - // if the stream was closed, do not transition to an UP state - if (!stream->isClosed) { - _setConnectionState(stream, true); - } - } else if (events & PARCEventQueueEventType_EOF) { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__, - "connid %u closed.", stream->id); - } - - parcEventQueue_Disable(stream->bufferEventVector, PARCEventType_Read); - - _setConnectionState(stream, false); - - if (!stream->isClosed) { - stream->isClosed = true; - // this will cause the connection manager to destroy the connection later - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionClosed, stream->id)); - } - } else if (events & PARCEventQueueEventType_Error) { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Error, - __func__, "Got an error on the connection %u: %s", stream->id, - strerror(errno)); - } - - parcEventQueue_Disable(stream->bufferEventVector, - PARCEventType_Read | PARCEventType_Write); - - _setConnectionState(stream, false); - - if (!stream->isClosed) { - stream->isClosed = true; - // this will cause the connection manager to destroy the connection later - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionClosed, stream->id)); - } - } - /* None of the other events can happen here, since we haven't enabled - * timeouts */ -} - -static connection_state_t _streamConnection_getState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->state; -} - -static void _streamConnection_setState(IoOperations *ops, connection_state_t state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _StreamState *stream = - (_StreamState *)ioOperations_GetClosure(ops); - stream->state = state; -} - -static connection_state_t _streamConnection_getAdminState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->admin_state; -} - -static void _streamConnection_setAdminState(IoOperations *ops, connection_state_t admin_state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _StreamState *stream = - (_StreamState *)ioOperations_GetClosure(ops); - stream->admin_state = admin_state; -} - -#ifdef WITH_POLICY -static uint32_t _streamConnection_getPriority(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->priority; -} - -static void _streamConnection_setPriority(IoOperations *ops, uint32_t priority) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _StreamState *stream = - (_StreamState *)ioOperations_GetClosure(ops); - stream->priority = priority; -} -#endif /* WITH_POLICY */ - -static const char * _streamConnection_getInterfaceName(const IoOperations *ops) -{ - parcAssertNotNull(ops, "Parameter must be non-null"); - _StreamState *stream = - (_StreamState *)ioOperations_GetClosure(ops); - return stream->interfaceName; -} diff --git a/hicn-light/src/hicn/io/streamConnection.h b/hicn-light/src/hicn/io/streamConnection.h deleted file mode 100644 index f483d0b82..000000000 --- a/hicn-light/src/hicn/io/streamConnection.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * Methods common to TCP and PF_LOCAL stream-based listeners - */ - -#ifndef streamConnection_h -#define streamConnection_h - -#include <hicn/core/forwarder.h> -#include <hicn/core/messagePacketType.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> -#include <hicn/utils/address.h> - -/** - * @function streamConnection_AcceptConnection - * @abstract Receive a connection from a remote peer - * @discussion - * We are the "server side" of the stream connection, so we need to accept the - * client connection and setup state for her. - * - * @param <#param1#> - * @return <#return#> - */ -IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd, - AddressPair *pair, - bool isLocal); - -/** - * @function streamConnection_OpenConnection - * @abstract Initiate a connection to a remote peer - * @discussion - * We are the "client side" of the stream connection. We'll create state for - * the peer, but it will be in the "down" state until the connection - * establishes. - * - * For TCP, both address pairs need to be the same address family: both INET - * or both INET6. The remote address must have the complete socket information - * (address, port). The local socket could be wildcarded or may specify down to - * the (address, port) pair. - * - * If the local address is IPADDR_ANY and the port is 0, then it is a normal - * call to "connect" that will use whatever local IP address and whatever local - * port for the connection. If either the address or port is set, the local - * socket will first be bound (via bind(2)), and then call connect(). - * - * AF_UNIX is not yet supported - * - * If there's an error binding to the specified address or connecting to the - * remote address, will return NULL. - * - * @param pair (takes ownership of this) is the complete socket pair of - * (address, port) for each end, if INET or INET6. - * @return NULL on error, otherwise the connections IO operations. - */ -IoOperations *streamConnection_OpenConnection(Forwarder *forwarder, - AddressPair *pair, bool isLocal); - -bool streamState_SendIOVBuffer(IoOperations *ops, struct iovec *response, - size_t size); - -#endif // streamConnection_h diff --git a/hicn-light/src/hicn/io/tcp.c b/hicn-light/src/hicn/io/tcp.c new file mode 100644 index 000000000..69ad32d16 --- /dev/null +++ b/hicn-light/src/hicn/io/tcp.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * Common activity for STREAM based listeners. + */ + +#include <errno.h> +#ifndef _WIN32 +#include <unistd.h> // fcntl +#endif /* _WIN32 */ +#include <fcntl.h> // fcntl +#include <hicn/hicn-light/config.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include <hicn/hicn.h> +#include <hicn/util/log.h> + +#include "base.h" +#include "../core/connection.h" +#include "../core/connection_vft.h" +#include "../core/listener.h" +#include "../core/listener_vft.h" +#include "../core/msgbuf.h" +#include "../core/forwarder.h" +#include "../core/messageHandler.h" + +// 128 KB output queue +#define OUTPUT_QUEUE_BYTES (128 * 1024) + +#define TCP_RECV_BUFLEN 8192 +//#define MTU 1500 + +/****************************************************************************** + * Listener + ******************************************************************************/ + +typedef struct { + void *_; +} listener_tcp_data_t; + +static int listener_tcp_initialize(listener_t *listener) { + ERROR("[listener_tcp_initialize] Not implemented"); + + return 0; +} + +static void listener_tcp_finalize(listener_t *listener) { + ERROR("[listener_tcp_finalize] Not implemented"); +} + +static int listener_tcp_punt(const listener_t *listener, const char *prefix_s) { + ERROR("[listener_tcp_punt] Not implemented"); + return -1; +} + +static int listener_tcp_get_socket(const listener_t *listener, + const address_t *local, + const address_t *remote, + const char *interface_name) { + ERROR("[listener_tcp_get_socket] Not implemented"); + return -1; +} + +#define listener_tcp_read_single io_read_single_socket +#define listener_tcp_read_batch NULL + +DECLARE_LISTENER(tcp); + +/****************************************************************************** + * Connection + ******************************************************************************/ + +typedef struct { + /* Partial receive buffer */ + u8 buf[TCP_RECV_BUFLEN]; + size_t roff; /**< Read offset */ + size_t woff; /**< Write offset */ + + // XXX this should be initialized with the header length, and tells what we + // expect to receive next... + size_t next_len; + struct bufferevent *bufferevent; +} connection_tcp_data_t; + +// XXX This seems more a listener code ! +// XXX we must have accept to the connection table to spawn new ones !! +// XXX equivalent to initialize +int connection_tcp_accept(connection_t *connection, listener_t *listener, + int fd, address_pair_t *pair, bool local, + unsigned connection_id) { + assert(connection); + assert(listener); + + *connection = (connection_t){ + .id = connection_id, + .interface_name = NULL, + .type = FACE_TYPE_TCP, + .pair = *pair, + .fd = fd, + .local = local, + // As we are accepting a connection, we begin in the UP state + .state = FACE_STATE_UP, + .admin_state = FACE_STATE_UP, +#ifdef WITH_POLICY + .priority = 0, +#endif /* WITH_POLICY */ + + .listener = listener, + .closed = false, + }; + + WITH_INFO({ + char addr_str[NI_MAXHOST]; + int port; + address_to_string(&(pair->local), addr_str, &port); + INFO("%s connection %p created for address %s:%d (local=%s)", + face_type_str(connection->type), connection, addr_str, port, + connection_is_local(connection) ? "true" : "false"); + }) + + return 0; +} + +int make_socket(address_pair_t *pair) { +#ifndef _WIN32 + int fd = socket(address_family(&pair->local), SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + goto ERR_SOCKET; + } +#else + SOCKET fd = socket(address_family(&pair->local), SOCK_STREAM, 0); + if (fd == INVALID_SOCKET) { + perror("socket"); + goto ERR_SOCKET; + } +#endif /* _WIN32 */ + + /* Set non-blocking flag */ +#ifndef _WIN32 + int flags = fcntl(fd, F_GETFL, NULL); + if (flags == -1) { + perror("F_GETFL"); + goto ERR; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + perror("F_SETFL"); + goto ERR; + } +#else + if (ioctlsocket(fd, FIONBIO, &(u_long){1}) != NO_ERROR) { + perror("ioctlsocket"); + goto ERR; + } +#endif /* _WIN32 */ + + if (bind(fd, address_sa(&pair->local), address_socklen(&pair->local)) == -1) { + perror("bind"); + goto ERR; + } + + if (connect(fd, address_sa(&pair->remote), address_socklen(&pair->remote)) < + 0) { + perror("connect"); + goto ERR; + } + + return 0; + +ERR: +#ifndef _WIN32 + close(fd); +#else + closesocket(fd); +#endif + +ERR_SOCKET: + return -1; +} + +static int connection_tcp_initialize(connection_t *connection) { + assert(connection); + assert(connection->type == FACE_TYPE_TCP); + + connection_tcp_data_t *data = connection->data; + assert(data); + + data->roff = 0; + data->woff = 0; + + connection->fd = make_socket(connection_get_pair(connection)); + if (connection->fd < 0) { + ERROR("Error creating TCP socket"); + return -1; + } + + WITH_INFO({ + char local_addr_str[NI_MAXHOST]; + char remote_addr_str[NI_MAXHOST]; + int local_port; + int remote_port; + address_to_string(&(connection->pair.local), local_addr_str, &local_port); + address_to_string(&(connection->pair.remote), remote_addr_str, + &remote_port); + INFO("%s connection %p connect for address pair %s:%d (local=%s) - %s:%d", + face_type_str(connection->type), connection, local_addr_str, + local_port, connection_is_local(connection) ? "true" : "false", + remote_addr_str, remote_port); + }) + + return 0; +} + +// XXX a part needs to be handled in the connection.c +static void connection_tcp_finalize(connection_t *connection) { + if (!connection->closed) { + connection->closed = true; + // XXX need to delete the connection like previously in the connection + // manager + } + + INFO("%s connection %p destroyed", face_type_str(connection->type), + connection); + // XXX need to release the "connection" +} + +#if 0 +static +bool +connection_tcp_sendv(connnection_t * connection, struct iovec * iov, + size_t size) +{ + assert(connection); + assert(iov); + + if (!connection_is_up(connection)) { + ERROR("Connection #%u tried to send to down connection (up=%d closed=%d)", + connection_get_id(connection), + connection_get_up(connection) ? "true" : "false", + connection_get_closed(connection) ? "true" : "false"); + return false; + } + + PARCEventBuffer *buffer = + parcEventBuffer_GetQueueBufferOutput(connection->events); + size_t buffer_backlog = parcEventBuffer_GetLength(buffer); + parcEventBuffer_Destroy(&buffer); + + if (buffer_backlog >= OUTPUT_QUEUE_BYTES) { + WARN("Connection #%u Writing to buffer backlog %zu bytes DROP MESSAGE", + connection_get_id(connection), buffer_backlog); + return false; + } + +#if 0 + /* DEBUG */ + size_t length = 0; + for (int i = 0; i < size; i++) + length += message[i].iov_len; + DEBUG("Connection #%u writing %zu bytes to buffer with backlog %zu bytes", + connection_get_id(connection), length, buffer_backlog); +#endif + + /* Write directly into the parcEventQueue without passing through message */ + for (int i = 0; i < size; i++) { + if (parcEventQueue_Write(conn->events, iov[i].iov_base, + iov[i].iov_len) != 0) + return false; + } + + return true; +} +#endif + +static bool connection_tcp_flush(const connection_t *connection) { + return true; +} + +/** + * @function streamConnection_Send + * @abstract Non-destructive send of the message. + * @discussion + * Send uses message_CopyToStreamBuffer, which is a non-destructive write. + * The send may fail if there's no buffer space in the output queue. + * + * @param dummy is ignored. A stream has only one peer. + * @return <#return#> + */ +// XXX address not used anywhere +// XXX too much repeated code with sendv here +static bool connection_tcp_send(const connection_t *connection, + msgbuf_t *msgbuf, bool queue) { + assert(connection); + assert(msgbuf); + + if (!connection_is_up(connection)) { + ERROR("Connection #%u tried to send to down connection (up=%d closed=%d)", + connection_get_id(connection), + connection_is_up(connection) ? "true" : "false", + connection_is_closed(connection) ? "true" : "false"); + return false; + } + + // XXX TODO write to fd +#if 0 + PARCEventBuffer *buffer = + parcEventBuffer_GetQueueBufferOutput(connection->events); + size_t buffer_backlog = parcEventBuffer_GetLength(buffer); + parcEventBuffer_Destroy(&buffer); + + if (buffer_backlog >= OUTPUT_QUEUE_BYTES) { + WARN("Connection #%u Writing to buffer backlog %zu bytes DROP MESSAGE", + connection_get_id(connection), buffer_backlog); + return false; + } + + DEBUG("Connection #%u Writing %zu bytes to buffer with backlog %zu bytes", + connection_get_id(connection), msgbuf_len(message), buffer_backlog); + + return (parcEventQueue_Write(connection->events, msgbuf_packet(message), + msgbuf_len(message)) == 0); +#endif + return true; +} + +static int connection_tcp_send_packet(const connection_t *connection, + const uint8_t *packet, size_t size) { + /* Not implemented for local connections */ + // XXX shall we set the pointer to NULL and add a check ? + + ERROR("[connection_tcp_send_packet] Not implemented"); + + return -1; +} + +// ================================================================= +// the actual I/O functions + +// not needed anymore ? +#if 0 +// XXX this is called iif there is sufficient data to read, otherwise it raises +// an assertion error. This was a problem before I guess +static +int +connection_tcp_read_message(connection_t * connection, msgbuf_t * msgbuf) +{ + assert(connection); + assert(msgbuf); + + connection_tcp_data_t * data = connection->data; + assert(data); + + size_t n = evbuffer_get_length(data->evbuffer); + // XXX this check was wrong + // parcAssertTrue(n >= sizeof(cmd_header_t), + "Called with too short an input: %zu", n); + + // XXX WTF + if (stream->next_len == 0) { + // this linearizes the first messageHandler_GetIPv6HeaderLength() bytes of the + // input buffer's iovecs and returns a pointer to it. + uint8_t *fh = parcEventBuffer_Pullup(data->evbuffer, sizeof(cmd_header_t)); + + // Calculate the total message size based on the fixed header + stream->next_len = messageHandler_GetTotalPacketLength(fh); + } + // This is not an ELSE statement. We can both start a new message then + // check if there's enough bytes to read the whole thing. + + if (n < stream->next_len) + return -1; + + uint8_t packet_type; + if (messageHandler_IsInterest(packet)) { + packet_type = MESSAGE_TYPE_INTEREST; + } else if (messageHandler_IsData(packet)) { + packet_type = MESSAGE_TYPE_DATA; + } else { + ERROR("Dropped packet that is not interest nor data"); + goto ERR; + } + + if (evbuffer_remove(data->evbuffer, data->packet, data->next_len) < 0) + return -1; + + msgbuf_from_packet(msgbuf, data->packet, packet_type, stream->id, + ticks_now()); + + // now reset message length for next packet + data->next_len = 0; + return 0; + +ERR: + evbuffer_drain(data->evbuffer, data->next_len); + return -1; +} +#endif + +/** + * @function conn_readcb + * @abstract Event callback for reads + * @discussion + * Will read messages off the input. Continues reading as long as we + * can get a header to determine the next message length or as long as we + * can read a complete message. + * + * This function manipulates the read low water mark. (1) read a fixed header + * plus complete message, then set the low water mark to FIXED_HEADER_LEN. (2) + * read a fixed header, but not a complete message, then set low water mark to + * the total mesage length. Using the low water mark like this means the buffer + * event will only trigger on meaningful byte boundaries when we can get actual + * work done. + * + * @param <#param1#> + * @return <#return#> + */ +#if 0 +static +void +connection_tcp_read_callback(connection_t * connection, int fd, void * user_data) +{ + assert(connection); + /* user_data can be NULL */ + + connection_tcp_data_t * data = connection->data; + assert(TCP_RECV_BUFLEN - data->woff > MTU); + + /* No batching here as code is not expected to receive much throughput */ + for (;;) { + ssize_t n = recv(connection->fd, data->buf + data->woff, + TCP_RECV_BUFLEN - data->woff, 0); + if (n == 0) /* EOF */ + return; // XXX close connection + if (n < 0) { + if (errno == EWOULDBLOCK) + break; + perror("recv"); + return; // XXX close connection + } + data->woff += n; + + /* Process */ + uint8_t * packet = data->buf + data->roff; + size_t size = data->woff - data->roff; /* > 0 */ + + ssize_t used = listener_read_callback(NULL, fd, + address_pair_get_local(&connection->pair), packet, size); + if (used < 0) + return; // XXX close connection ? + if (used == 0) + break; /* We would have received more if there was still packets to be read */ + data->roff += used; + assert(data->roff <= data->woff); + + if (data->roff == data->woff) { + /* Reset state whenever possible to avoid memcpy's */ + data->roff = 0; + data->woff = 0; + return; + } + } + + /* Make sure there is enough remaining space in the buffer */ + if (TCP_RECV_BUFLEN - data->woff < MTU) { + /* + * There should be no overlap provided a sufficiently large BUFLEN, but + * who knows. + */ + memmove(data->buf, data->buf + data->roff, data->woff - data->roff); + data->woff -= data->roff; + data->roff = 0; + } + + return; +} +#endif + +#if 0 +static +void +connection_tcp_callback(connection_t * connection, int fd, void * user_data) +{ + if (events & PARCEventQueueEventType_Connected) { + INFO("Connection %u is connected", stream->id); + + // if the stream was closed, do not transition to an UP state + if (!stream->isClosed) { + _setConnectionState(stream, true); + } + } else if (events & PARCEventQueueEventType_EOF) { + INFO("connid %u closed.", stream->id); + + parcEventQueue_Disable(stream->events, PARCEventType_Read); + + _setConnectionState(stream, false); + + if (!stream->isClosed) { + stream->isClosed = true; + // XXX TODO destroy the connection + } + } else if (events & PARCEventQueueEventType_Error) { + ERROR("Got an error on the connection %u: %s", stream->id, + strerror(errno)); + + parcEventQueue_Disable(stream->events, + PARCEventType_Read | PARCEventType_Write); + + _setConnectionState(stream, false); + + if (!stream->isClosed) { + stream->isClosed = true; + // XXX TODO destroy the connection + } + } + /* None of the other events can happen here, since we haven't enabled + * timeouts */ +} +#endif + +DECLARE_CONNECTION(tcp) diff --git a/hicn-light/src/hicn/io/tcpListener.c b/hicn-light/src/hicn/io/tcpListener.c deleted file mode 100644 index e2b80c215..000000000 --- a/hicn-light/src/hicn/io/tcpListener.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <hicn/core/connectionTable.h> -#include <hicn/core/forwarder.h> -#include <hicn/io/listener.h> -#include <hicn/io/streamConnection.h> -#include <hicn/io/tcpListener.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> - -typedef struct tcp_listener { - char *listenerName; - Forwarder *forwarder; - Logger *logger; - - PARCEventSocket *listener; - - Address *localAddress; - - unsigned id; - char *interfaceName; - - // is the localAddress as 127.0.0.0 address? - bool isLocalAddressLocal; -} _TcpListener; - -static void _tcpListener_Destroy(_TcpListener **listenerPtr); - -static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr); - -static const char *_tcpListener_ListenerName(const ListenerOps *ops); - -static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops); - -static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops); - -static const char *_tcpListener_InterfaceName(const ListenerOps *ops); - -static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops); - -static ListenerOps _tcpTemplate = { - .context = NULL, - .destroy = &_tcpListener_OpsDestroy, - .getListenerName = &_tcpListener_ListenerName, - .getInterfaceIndex = &_tcpListener_OpsGetInterfaceIndex, - .getListenAddress = &_tcpListener_OpsGetListenAddress, - .getEncapType = &_tcpListener_OpsGetEncapType, - .getInterfaceName = &_tcpListener_InterfaceName, - .getSocket = NULL}; - -// STREAM daemon listener callback -static void _tcpListener_Listen(int, struct sockaddr *, int socklen, - void *tcpVoid); - -ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder, char *listenerName, - struct sockaddr_in6 sin6, char *interfaceName) { - - _TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener)); - parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_TcpListener)); - - tcp->forwarder = forwarder; - tcp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName)); - tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - tcp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName)); - - tcp->listener = dispatcher_CreateListener( - forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1, - (struct sockaddr *)&sin6, sizeof(sin6)); - - if (tcp->listener == NULL) { - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "dispatcher_CreateListener failed to create listener (%d) %s", - errno, strerror(errno)); - logger_Release(&tcp->logger); - parcMemory_Deallocate((void **)&tcp); - return NULL; - } - - tcp->localAddress = addressCreateFromInet6(&sin6); - tcp->id = forwarder_GetNextConnectionId(forwarder); - tcp->isLocalAddressLocal = - parcNetwork_IsSocketLocal((struct sockaddr *)&sin6); - - ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - - memcpy(ops, &_tcpTemplate, sizeof(ListenerOps)); - ops->context = tcp; - - if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(tcp->localAddress); - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "TcpListener %p created for address %s (isLocal %d)", - (void *)tcp, str, tcp->isLocalAddressLocal); - parcMemory_Deallocate((void **)&str); - } - - return ops; -} - -ListenerOps *tcpListener_CreateInet(Forwarder *forwarder, char *listenerName, - struct sockaddr_in sin, char *interfaceName) { - _TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener)); - parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_TcpListener)); - - tcp->forwarder = forwarder; - tcp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName)); - tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - tcp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName)); - - tcp->listener = dispatcher_CreateListener( - forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1, - (struct sockaddr *)&sin, sizeof(sin)); - - if (tcp->listener == NULL) { - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "dispatcher_CreateListener failed to create listener (%d) %s", - errno, strerror(errno)); - - logger_Release(&tcp->logger); - parcMemory_Deallocate((void **)&tcp); - return NULL; - } - - tcp->localAddress = addressCreateFromInet(&sin); - tcp->id = forwarder_GetNextConnectionId(forwarder); - tcp->isLocalAddressLocal = parcNetwork_IsSocketLocal((struct sockaddr *)&sin); - - ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - - memcpy(ops, &_tcpTemplate, sizeof(ListenerOps)); - ops->context = tcp; - - if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(tcp->localAddress); - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "TcpListener %p created for address %s (isLocal %d)", - (void *)tcp, str, tcp->isLocalAddressLocal); - parcMemory_Deallocate((void **)&str); - } - - return ops; -} - -static void _tcpListener_Destroy(_TcpListener **listenerPtr) { - parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listenerPtr, - "Parameter must derefernce to non-null pointer"); - _TcpListener *tcp = *listenerPtr; - - if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(tcp->localAddress); - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "TcpListener %p destroyed", (void *)tcp); - parcMemory_Deallocate((void **)&str); - } - - parcMemory_Deallocate((void **)&tcp->listenerName); - parcMemory_Deallocate((void **)&tcp->interfaceName); - logger_Release(&tcp->logger); - dispatcher_DestroyListener(forwarder_GetDispatcher(tcp->forwarder), - &tcp->listener); - addressDestroy(&tcp->localAddress); - parcMemory_Deallocate((void **)&tcp); - *listenerPtr = NULL; -} - -// ================================================== - -static const char *_tcpListener_ListenerName(const ListenerOps *ops) { - _TcpListener *tcp = (_TcpListener *)ops->context; - return tcp->listenerName; -} - -static const char *_tcpListener_InterfaceName(const ListenerOps *ops) { - _TcpListener *tcp = (_TcpListener *)ops->context; - return tcp->interfaceName; -} - -static void _tcpListener_Listen(int fd, struct sockaddr *sa, int socklen, - void *tcpVoid) { - _TcpListener *tcp = (_TcpListener *)tcpVoid; - - Address *remote; - - switch (sa->sa_family) { - case AF_INET: - remote = addressCreateFromInet((struct sockaddr_in *)sa); - break; - - case AF_INET6: - remote = addressCreateFromInet6((struct sockaddr_in6 *)sa); - break; - - default: - parcTrapIllegalValue(sa, "Expected INET or INET6, got %d", sa->sa_family); - abort(); - } - - AddressPair *pair = addressPair_Create(tcp->localAddress, remote); - - IoOperations *ops = streamConnection_AcceptConnection( - tcp->forwarder, fd, pair, tcp->isLocalAddressLocal); - Connection *conn = connection_Create(ops); - - connectionTable_Add(forwarder_GetConnectionTable(tcp->forwarder), conn); - - if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "TcpListener %p listen started", (void *)tcp); - } - - addressDestroy(&remote); -} - -static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr) { - ListenerOps *ops = *listenerOpsPtr; - _TcpListener *tcp = (_TcpListener *)ops->context; - _tcpListener_Destroy(&tcp); - parcMemory_Deallocate((void **)&ops); - *listenerOpsPtr = NULL; -} - -static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops) { - _TcpListener *tcp = (_TcpListener *)ops->context; - return tcp->id; -} - -static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops) { - _TcpListener *tcp = (_TcpListener *)ops->context; - return tcp->localAddress; -} - -static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops) { - return ENCAP_TCP; -} diff --git a/hicn-light/src/hicn/io/tcpListener.h b/hicn-light/src/hicn/io/tcpListener.h deleted file mode 100644 index a841738e5..000000000 --- a/hicn-light/src/hicn/io/tcpListener.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file tcpListener.h - * @brief Listens for in coming TCP connections - * - * This is the "server socket" of hicn-light for TCP connections. The actual - * I/O is handled by {@link StreamConnection}. - * - */ - -#ifndef tcpListener_h -#define tcpListener_h - -#ifndef _WIN32 -#include <netinet/in.h> -#endif - -#include <hicn/core/forwarder.h> -#include <hicn/io/listener.h> -#include <stdlib.h> - -ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder, char *listenerName, - struct sockaddr_in6 sin6, char *interfaceName); -ListenerOps *tcpListener_CreateInet(Forwarder *forwarder, char *listenerName, - struct sockaddr_in sin, char *interfaceName); -#endif // tcpListener_h diff --git a/hicn-light/src/hicn/io/tcpTunnel.c b/hicn-light/src/hicn/io/tcpTunnel.c deleted file mode 100644 index 7a04a4222..000000000 --- a/hicn-light/src/hicn/io/tcpTunnel.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/io/streamConnection.h> -#include <hicn/io/tcpListener.h> -#include <hicn/io/tcpTunnel.h> - -IoOperations *tcpTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress) { - IoOperations *ops = NULL; - - address_type localType = addressGetType(localAddress); - address_type remoteType = addressGetType(remoteAddress); - - if (localType == remoteType) { - AddressPair *pair = addressPair_Create(localAddress, remoteAddress); - bool isLocal = false; - - ops = streamConnection_OpenConnection(forwarder, pair, isLocal); - } - - return ops; -} diff --git a/hicn-light/src/hicn/io/tcpTunnel.h b/hicn-light/src/hicn/io/tcpTunnel.h deleted file mode 100644 index d1d2a8524..000000000 --- a/hicn-light/src/hicn/io/tcpTunnel.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file tcpTunnel.h - * @brief Establish a tunnel to a remote system - * - */ - -#ifndef tcpTunnel_h -#define tcpTunnel_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/ioOperations.h> -#include <hicn/io/listener.h> -#include <hicn/utils/address.h> - -/** - */ -// IoOperations *tcpTunnel_CreateOnListener(Forwarder *forwarder, -// ListenerOps *localListener, -// const Address *remoteAddress); - -/** - */ -IoOperations *tcpTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress); - -#endif // tcpTunnel_h diff --git a/hicn-light/src/hicn/io/udp.c b/hicn-light/src/hicn/io/udp.c new file mode 100644 index 000000000..3301e2178 --- /dev/null +++ b/hicn-light/src/hicn/io/udp.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * @file udp.c + * #brief Implementation of the UDP face + * + * Old comment: + * - The Send() function may overflow the output buffer + * + */ + +/* This has to be included early as other modules are including socket.h */ + +#ifndef _WIN32 +#include <arpa/inet.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef _WIN32 +#include <sys/uio.h> +#include <unistd.h> +#endif +#include <sys/socket.h> + +#ifdef WITH_GSO +#include <netinet/if_ether.h> // ETH_DATA_LEN +#include <linux/ipv6.h> // struct ipv6hdr +#include <netinet/udp.h> // struct udphdr, SOL_UDP +//#include <linux/udp.h> // UDP_GRO +#define UDP_GRO 104 +#endif /* WITH_GSO */ + +#include <hicn/util/log.h> +#include <hicn/util/sstrncpy.h> + +#include "base.h" +#include "../base/loop.h" +#include "../base/ring.h" +#include "../core/address_pair.h" +#include "../core/connection.h" +#include "../core/connection_vft.h" +#include "../core/forwarder.h" +#include "../core/listener.h" +#include "../core/listener_vft.h" +#include "../core/messageHandler.h" +#include "../core/msgbuf.h" +//#include "../hicn-light/config.h" + +// Batching based on recvmmsg is also generic +// the difference is the handling of packet as in tcp we need to go through the +// ring buffer first to do the framing, while in UDP this is already done +// +// each module should have a function to process a packet, then call a callback +// in the forwarder again + +#define BATCH_SOCKET_BUFFER 512 * 1024 /* 256k */ + +/****************************************************************************** + * Listener + ******************************************************************************/ + +typedef struct { + uint16_t port; // in address ? +} listener_udp_data_t; + +#ifdef __ANDROID__ +extern int bindSocket(int sock, const char *interface_name); +#endif + +#if 0 +#include <arpa/inet.h> +char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen) { + switch (sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen); + break; + + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen); + break; + + default: + strncpy(s, "Unknown AF", maxlen); + return NULL; + } + + return s; +} +#endif + +/* socket options */ +int socket_set_options(int fd) { +#ifndef _WIN32 + // Set non-blocking flag + int flags = fcntl(fd, F_GETFL, NULL); + if (flags < 0) { + perror("fcntl"); + return -1; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl"); + return -1; + } +#else + // Set non-blocking flag + int result = ioctlsocket(fd, FIONBIO, &(int){1}); + if (result != NO_ERROR) { + perror("ioctlsocket"); + return -1; + } +#endif + + // don't hang onto address after listener has closed + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } + +#ifdef WITH_GSO + int gso_size = ETH_DATA_LEN - sizeof(struct ipv6hdr) - sizeof(struct udphdr); + if (setsockopt(fd, SOL_UDP, UDP_SEGMENT, &gso_size, sizeof(gso_size)) < 0) { + perror("setsockopt"); + return -1; + } +#endif /* WITH_GSO */ + +#ifdef WITH_GRO + if (setsockopt(fd, IPPROTO_UDP, UDP_GRO, &(int){1}, sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } +#endif /* WITH_GRO */ + +#ifdef WITH_ZEROCOPY + if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &(int){1}, sizeof(int))) { + perror("setsockopt"); + return -1; + } +#endif /* WITH_ZEROCOPY */ + + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &(int){BATCH_SOCKET_BUFFER}, + sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &(int){BATCH_SOCKET_BUFFER}, + sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } + return 0; +} + +#ifdef __linux__ +/* bind to device */ +int socket_bind_to_device(int fd, const char *interface_name) { + if (strncmp("lo", interface_name, 2) == 0) return 0; + + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name, + strnlen_s(interface_name, IFNAMSIZ)) < 0) { + perror("setsockopt"); + goto ERR_BIND_TO_DEVICE; + } + + return 0; + +ERR_BIND_TO_DEVICE: +#ifdef __ANDROID__ + if (bindSocket(fd, interface_name) < 0) return -1; + return 0; +#else + return -1; +#endif /* __ANDROID__ */ +} +#endif /* __linux__ */ + +static int listener_udp_initialize(listener_t *listener) { + assert(listener); + +#if 0 + listener_udp_data_t * data = listener->data; + assert(data); +#endif + return 0; +} + +static void listener_udp_finalize(listener_t *listener) { + assert(listener); + assert(listener->type == FACE_TYPE_UDP_LISTENER); + + return; +} + +static int listener_udp_punt(const listener_t *listener, const char *prefix_s) { + return -1; +} + +static int listener_udp_get_socket(const listener_t *listener, + const address_t *local, + const address_t *remote, + const char *interface_name) { + int fd = socket(address_family(local), SOCK_DGRAM, 0); + if (fd < 0) goto ERR_SOCKET; + + if (socket_set_options(fd) < 0) { + goto ERR; + } + + if (bind(fd, address_sa(local), address_socklen(local)) < 0) { + perror("bind"); + goto ERR; + } + +#ifdef __linux__ + if (socket_bind_to_device(fd, interface_name) < 0) { + goto ERR; + } +#endif /* __linux__ */ + + // DEBUG("UDP remote ?"); + if (remote) { + // DEBUG("UDP connected socket "); + if (connect(fd, address_sa(remote), address_socklen(remote)) < 0) { + perror("connect"); + goto ERR; + } + } + + return fd; + +ERR: +#ifndef _WIN32 + close(fd); +#else + closesocket(fd); +#endif +ERR_SOCKET: + return -1; +} + +#define listener_udp_read_single io_read_single_socket + +#ifdef __linux__ +#define listener_udp_read_batch io_read_batch_socket +#else +#define listener_udp_read_batch NULL +#endif /* __linux__ */ + +DECLARE_LISTENER(udp); + +/****************************************************************************** + * Connection + ******************************************************************************/ + +#define RING_LEN 5 * MAX_MSG + +typedef struct { + /* + * Ring buffer + * + * This is sized to more than a batch to cope with transient failures of + * sendmmsg. + */ + off_t *ring; + +#ifdef __linux__ + struct mmsghdr msghdr[MAX_MSG]; + struct iovec iovecs[MAX_MSG]; +#endif /* __linux__ */ +} connection_udp_data_t; + +static int connection_udp_initialize(connection_t *connection) { + assert(connection); + assert(connection->type == FACE_TYPE_UDP); + assert(connection->interface_name); + +#ifdef __linux__ + connection_udp_data_t *data = connection->data; + assert(data); + + ring_init(data->ring, RING_LEN); + + void *name = NULL; + int namelen = 0; + + /* + * If the connection does not use a connected socket, we need to set the + * different destination addresses + */ + if (!connection->connected) { + const address_t *remote = connection_get_remote(connection); + name = address_sa(remote); + namelen = address_socklen(remote); + } + + memset(data->msghdr, 0, MAX_MSG * sizeof(struct mmsghdr)); + for (unsigned i = 0; i < MAX_MSG; i++) { + struct mmsghdr *msg = &data->msghdr[i]; + *msg = (struct mmsghdr){ + .msg_hdr = + { + .msg_iov = &data->iovecs[i], + .msg_iovlen = 1, + .msg_name = name, + .msg_namelen = namelen, +#if 0 + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, +#endif + }, + }; + } +#endif /* __linux__ */ + + return 0; +} + +static void connection_udp_finalize(connection_t *connection) { + assert(connection); + assert(connection->type == FACE_TYPE_UDP); + + connection_udp_data_t *data = connection->data; + assert(data); + + ring_free(data->ring); +} + +static bool connection_udp_flush(const connection_t *connection) { +#ifdef __linux__ + int retry = 0; + off_t msgbuf_id = 0; + unsigned cpt; + size_t i; + int n; + + assert(connection); + forwarder_t *forwarder = listener_get_forwarder(connection->listener); + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + connection_udp_data_t *data = connection->data; + assert(data); + + TRACE("[connection_udp_send] Flushing connection queue"); + + /* Flush operation */ +#ifdef WITH_ZEROCOPY + int flags = MSG_ZEROCOPY; +#else + int flags = 0; +#endif /* WITH_ZEROCOPY */ + +SEND: + /* Consume up to MSG_MSG packets in ring buffer */ + cpt = 0; + + ring_enumerate_n(data->ring, i, &msgbuf_id, MAX_MSG, { + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + + // update path label + if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) + msgbuf_update_pathlabel(msgbuf, connection_get_id(connection)); + + data->iovecs[i].iov_base = msgbuf_get_packet(msgbuf); + data->iovecs[i].iov_len = msgbuf_get_len(msgbuf); + cpt++; + }); + +SENDMMSG: + n = sendmmsg(connection->fd, data->msghdr, cpt, flags); + if (n == -1) { + /* man(2)sendmmsg / BUGS + * + * If an error occurs after at least one message has been sent, the call + * succeeds, and returns the number of messages sent. The error code is + * lost. The caller can retry the transmission, starting at the first + * failed message, but there is no guarantee that, if an error is + * returned, it will be the same as the one that was lost on the previous + * call. + */ + WARN("sendmmsg failed %s", strerror(errno)); + if (retry < 1) { + retry++; + goto SENDMMSG; + } + return false; + } + + ring_advance(data->ring, n); + + if (n < cpt) { + WARN("Unknown error after sending n=%d packets...", n); + if (retry < 1) { + retry++; + goto SEND; + } + } + + if (ring_get_size(data->ring) > 0) { + retry = 0; + goto SEND; + } +#endif /* __linux__ */ + return true; +} + +/** + * @function metisUdpConnection_Send + * @abstract Non-destructive send of the message. + * @discussion + * sends a message to the peer. + * + * @param dummy is ignored. A udp connection has only one peer. + * @return <#return#> + */ +static bool connection_udp_send(const connection_t *connection, + msgbuf_t *msgbuf, bool queue) { + assert(connection); + assert(msgbuf); + +#ifdef __linux__ + connection_udp_data_t *data = connection->data; + assert(data); + + forwarder_t *forwarder = listener_get_forwarder(connection->listener); + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + + /* Queue packet ? */ + if (queue) { + off_t msgbuf_id; + if (ring_is_full(data->ring)) connection_udp_flush(connection); + + msgbuf_id = msgbuf_pool_get_id(msgbuf_pool, msgbuf); + ring_add(data->ring, &msgbuf_id); + + } else { +#endif /* __linux__ */ + /* Send one */ + // update the path label befor send the packet + if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) + msgbuf_update_pathlabel(msgbuf, connection_get_id(connection)); + + ssize_t writeLength = write(connection->fd, msgbuf_get_packet(msgbuf), + msgbuf_get_len(msgbuf)); + + if (writeLength < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return false; + } else { + // this print is for debugging + printf("Incorrect write length %zd, expected %u: (%d) %s\n", + writeLength, msgbuf_get_len(msgbuf), errno, strerror(errno)); + return false; + } + } +#ifdef __linux__ + } +#endif /* __linux__ */ + + return true; +} + +#if 0 +static +bool +connection_udp_sendv(const connection_t * connection, struct iovec * iov, + size_t size) +{ + + assert(connetion); + assert(iov); + + connection_udp_data_t * data = connection->data; + assert(data); + +#ifndef _WIN32 + // Perform connect before to establish association between this peer and + // the remote peer. This is required to use writev. + // Connection association can be changed at any time. + + if (writev(connection->fd, iov, (int)size) < 0) + return false; +#else + WSABUF *buf = (WSABUF *) malloc(size * sizeof(WSABUF)); + + DWORD bytes_sent = 0; + + for (int i = 0; i < size; i++) { + buf[i].buf = iov[i].iov_base; + buf[i].len = (ULONG)iov[i].iov_len; + } + + int rc = WSASendTo(udp->fd, buf, size, &bytes_sent, 0, + (SOCKADDR *)address_sa(address_pair_remote(&udp->pair)), + address_socklen(address_pair_remote(&udp->pair)), NULL, NULL); + free(dataBuf); + if (rc == SOCKET_ERROR) + return false; +#endif + + return true; +} +#endif + +static int connection_udp_send_packet(const connection_t *connection, + const uint8_t *packet, size_t size) { + assert(connection); + assert(packet); + + // XXX: in case of two connections this functions may have wrong behaviour. We + // noticed that the packet is sent by the forwarder on the right socket (fd) + // but from tcpdump we see that the packet goes on the other connection. In + // other cases the packet is sent twice, first on the wrong socket and later + // on the right one, even if we log a single send from the forwarder. The + // same behaviour was observed with the write executed in the function + // connection_udp_send with the queue flag set to false. A workaround that + // seems to solve the problem is to use connection_udp_send with queue = true + // and force the flush of the connection if needed. + + // TODO: commented otherwise unable to do tests locally + // if(connection_is_local(connection)) + // return -1; + +#ifdef USE_CONNECTED_SOCKETS + ssize_t n = send(connection->fd, packet, size, 0); + if (n < 0) { + perror("sendto"); + return -1; + } +#else + const address_t *remote = connection_get_remote(connection); + ssize_t n = sendto(connection->fd, packet, size, 0, address_sa(remote), + address_socklen(remote)); + if (n < 0) return -1; +#endif + + return 0; +} + +#define connection_udp_read_single \ + listener_read_batch_socket listener_single_socket + +#ifdef __linux__ +#define connection_udp_read_batch listener_read_batch_socket +#else +#define connection_udp_read_batch NULL +#endif /* __linux__ */ + +DECLARE_CONNECTION(udp); diff --git a/hicn-light/src/hicn/io/udpConnection.c b/hicn-light/src/hicn/io/udpConnection.c deleted file mode 100644 index 2747b7ef4..000000000 --- a/hicn-light/src/hicn/io/udpConnection.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * Embodies the reader/writer for a UDP connection - * - * NB The Send() function may overflow the output buffer - * - */ - -#ifndef _WIN32 -#include <sys/uio.h> -#endif -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <string.h> - -#include <hicn/core/messageHandler.h> -#include <hicn/io/udpConnection.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/connection.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/message.h> - -typedef struct udp_state { - Forwarder *forwarder; - char * interfaceName; - Logger *logger; - - // the udp listener socket we receive packets on - int udpListenerSocket; - - AddressPair *addressPair; - - // We need to access this all the time, so grab it out - // of the addressPair; - struct sockaddr *peerAddress; - socklen_t peerAddressLength; - - bool isLocal; - bool isUp; - unsigned id; - - unsigned delay; - - /* This information would better be stored in the connection data structure - * but it is currently not reachable from within the implementation. */ - connection_state_t state; - connection_state_t admin_state; -#ifdef WITH_POLICY - uint32_t priority; -#endif /* WITH_POLICY */ -} _UdpState; - -// Prototypes -static bool _send(IoOperations *ops, const Address *nexthop, Message *message); -static bool _sendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size); -static const Address *_getRemoteAddress(const IoOperations *ops); -static const AddressPair *_getAddressPair(const IoOperations *ops); -static unsigned _getConnectionId(const IoOperations *ops); -static bool _isUp(const IoOperations *ops); -static bool _isLocal(const IoOperations *ops); -static void _destroy(IoOperations **opsPtr); -static list_connections_type _getConnectionType(const IoOperations *ops); -static void _sendProbe(IoOperations *ops, uint8_t *message); -static connection_state_t _getState(const IoOperations *ops); -static void _setState(IoOperations *ops, connection_state_t state); -static connection_state_t _getAdminState(const IoOperations *ops); -static void _setAdminState(IoOperations *ops, connection_state_t admin_state); -#ifdef WITH_POLICY -static uint32_t _getPriority(const IoOperations *ops); -static void _setPriority(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ -static const char * _getInterfaceName(const IoOperations *ops); - -/* - * This assigns a unique pointer to the void * which we use - * as a GUID for this class. - */ -static const void *_IoOperationsGuid = __FILE__; - -/* - * Return our GUID - */ -static const void *_streamConnection_Class(const IoOperations *ops) { - return _IoOperationsGuid; -} - -static IoOperations _template = { - .closure = NULL, - .send = &_send, - .sendIOVBuffer = &_sendIOVBuffer, - .getRemoteAddress = &_getRemoteAddress, - .getAddressPair = &_getAddressPair, - .getConnectionId = &_getConnectionId, - .isUp = &_isUp, - .isLocal = &_isLocal, - .destroy = &_destroy, - .class = &_streamConnection_Class, - .getConnectionType = &_getConnectionType, - .sendProbe = &_sendProbe, - .getState = &_getState, - .setState = &_setState, - .getAdminState = &_getAdminState, - .setAdminState = &_setAdminState, -#ifdef WITH_POLICY - .getPriority = &_getPriority, - .setPriority = &_setPriority, -#endif /* WITH_POLICY */ - .getInterfaceName = &_getInterfaceName, -}; - -// ================================================================= - -static void _setConnectionState(_UdpState *Udp, bool isUp); -static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair); - -IoOperations *udpConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd, - const AddressPair *pair, bool isLocal) { - IoOperations *io_ops = NULL; - - _UdpState *udpConnState = parcMemory_AllocateAndClear(sizeof(_UdpState)); - parcAssertNotNull(udpConnState, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_UdpState)); - - udpConnState->forwarder = forwarder; - udpConnState->interfaceName = strdup(interfaceName); - udpConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - bool saved = _saveSockaddr(udpConnState, pair); - if (saved) { - udpConnState->udpListenerSocket = fd; - udpConnState->id = forwarder_GetNextConnectionId(forwarder); - udpConnState->addressPair = addressPair_Acquire(pair); - udpConnState->isLocal = isLocal; - - // allocate a connection - io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations)); - parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(IoOperations)); - memcpy(io_ops, &_template, sizeof(IoOperations)); - io_ops->closure = udpConnState; - - _setConnectionState(udpConnState, true); - -#ifdef WITH_POLICY - udpConnState->priority = 0; -#endif /* WITH_POLICY */ - - if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - char *str = addressPair_ToString(udpConnState->addressPair); - logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Info, - __func__, - "UdpConnection %p created for address %s (isLocal %d)", - (void *)udpConnState, str, udpConnState->isLocal); - free(str); - } - - messenger_Send( - forwarder_GetMessenger(forwarder), - missive_Create(MissiveType_ConnectionCreate, udpConnState->id)); - messenger_Send(forwarder_GetMessenger(forwarder), - missive_Create(MissiveType_ConnectionUp, udpConnState->id)); - } else { - // _saveSockaddr will already log an error, no need for extra log message - // here - logger_Release(&udpConnState->logger); - - free(udpConnState->interfaceName); - parcMemory_Deallocate((void **)&udpConnState); - } - - return io_ops; -} - -// ================================================================= -// I/O Operations implementation - -static void _destroy(IoOperations **opsPtr) { - parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer"); - parcAssertNotNull(*opsPtr, - "Parameter opsPtr must dereference to non-null pointer"); - - IoOperations *ops = *opsPtr; - parcAssertNotNull(ioOperations_GetClosure(ops), - "ops->context must not be null"); - - _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops); - addressPair_Release(&udpConnState->addressPair); - parcMemory_Deallocate((void **)&(udpConnState->peerAddress)); - - messenger_Send( - forwarder_GetMessenger(udpConnState->forwarder), - missive_Create(MissiveType_ConnectionDestroyed, udpConnState->id)); - - if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Info, - __func__, "UdpConnection %p destroyed", (void *)udpConnState); - } - - // do not close udp->udpListenerSocket, the listener will close - // that when its done - - logger_Release(&udpConnState->logger); - free(udpConnState->interfaceName); - parcMemory_Deallocate((void **)&udpConnState); - parcMemory_Deallocate((void **)&ops); - - *opsPtr = NULL; -} - -static bool _isUp(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->isUp; -} - -static bool _isLocal(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->isLocal; -} - -static const Address *_getRemoteAddress(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return addressPair_GetRemote(udpConnState->addressPair); -} - -static const AddressPair *_getAddressPair(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->addressPair; -} - -static unsigned _getConnectionId(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->id; -} - -/** - * @function metisUdpConnection_Send - * @abstract Non-destructive send of the message. - * @discussion - * sends a message to the peer. - * - * @param dummy is ignored. A udp connection has only one peer. - * @return <#return#> - */ -static bool _send(IoOperations *ops, const Address *dummy, Message *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops); - - // NAT for HICN - // in this particular connection we don't need natting beacause we send the - // packet to the next hop using upd connection - - ssize_t writeLength = - sendto(udpConnState->udpListenerSocket, message_FixedHeader(message), - (int)message_Length(message), 0, udpConnState->peerAddress, - udpConnState->peerAddressLength); - - if (writeLength < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - return false; - } else { - // this print is for debugging - printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLength, - message_Length(message), errno, strerror(errno)); - return false; - } - } - - return true; -} - -static bool _sendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops); - -#ifndef _WIN32 - // Perform connect before to establish association between this peer and - // the remote peer. This is required to use writev. - // Connection association can be changed at any time. - connect(udpConnState->udpListenerSocket, - udpConnState->peerAddress, - udpConnState->peerAddressLength); - - ssize_t writeLength = writev(udpConnState->udpListenerSocket, message, (int)size); - - struct sockaddr any_address = {0}; - any_address.sa_family = AF_UNSPEC; - connect(udpConnState->udpListenerSocket, - &any_address, (socklen_t)sizeof(any_address)); - - if (writeLength < 0) { - return false; - } -#else - - WSABUF *dataBuf = (WSABUF *) malloc(size * sizeof (dataBuf)); - DWORD BytesSent = 0; - - for (int i = 0; i < size; i++) { - dataBuf[i].buf = message[i].iov_base; - dataBuf[i].len = (ULONG)message[i].iov_len; - } - - int rc = WSASendTo(udpConnState->udpListenerSocket, dataBuf, (DWORD)size, - &BytesSent, 0, (SOCKADDR *)udpConnState->peerAddress, - udpConnState->peerAddressLength, NULL, NULL); - free(dataBuf); - if (rc == SOCKET_ERROR) { - return false; - } -#endif - return true; -} - -static list_connections_type _getConnectionType(const IoOperations *ops) { - return CONN_UDP; -} - -static void _sendProbe(IoOperations *ops, uint8_t *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops); - - if(udpConnState->isLocal) - return; - - ssize_t writeLength = - sendto(udpConnState->udpListenerSocket, message, - messageHandler_GetTotalPacketLength(message), 0, udpConnState->peerAddress, - udpConnState->peerAddressLength); - - if (writeLength < 0) { - return; - } -} - -// ================================================================= -// Internal API - -static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair) { - bool success = false; - const Address *remoteAddress = addressPair_GetRemote(pair); - - switch (addressGetType(remoteAddress)) { - case ADDR_INET: { - size_t bytes = sizeof(struct sockaddr_in); - udpConnState->peerAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(udpConnState->peerAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet(remoteAddress, - (struct sockaddr_in *)udpConnState->peerAddress); - udpConnState->peerAddressLength = (socklen_t)bytes; - - success = true; - break; - } - - case ADDR_INET6: { - size_t bytes = sizeof(struct sockaddr_in6); - udpConnState->peerAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(udpConnState->peerAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet6(remoteAddress, - (struct sockaddr_in6 *)udpConnState->peerAddress); - udpConnState->peerAddressLength = (socklen_t)bytes; - - success = true; - break; - } - - default: - if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - char *str = addressToString(remoteAddress); - logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Error, - __func__, "Remote address is not INET or INET6: %s", str); - parcMemory_Deallocate((void **)&str); - } - break; - } - return success; -} - -static void _setConnectionState(_UdpState *udpConnState, bool isUp) { - parcAssertNotNull(udpConnState, "Parameter Udp must be non-null"); - - Messenger *messenger = forwarder_GetMessenger(udpConnState->forwarder); - - bool oldStateIsUp = udpConnState->isUp; - udpConnState->isUp = isUp; - - if (oldStateIsUp && !isUp) { - // bring connection DOWN - Missive *missive = - missive_Create(MissiveType_ConnectionDown, udpConnState->id); - messenger_Send(messenger, missive); - return; - } - - if (!oldStateIsUp && isUp) { - // bring connection UP - Missive *missive = - missive_Create(MissiveType_ConnectionUp, udpConnState->id); - messenger_Send(messenger, missive); - return; - } -} - -static connection_state_t _getState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->state; -} - -static void _setState(IoOperations *ops, connection_state_t state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _UdpState *udpConnState = - (_UdpState *)ioOperations_GetClosure(ops); - udpConnState->state = state; -} - -static connection_state_t _getAdminState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->admin_state; -} - -static void _setAdminState(IoOperations *ops, connection_state_t admin_state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _UdpState *udpConnState = - (_UdpState *)ioOperations_GetClosure(ops); - udpConnState->admin_state = admin_state; -} - -#ifdef WITH_POLICY -static uint32_t _getPriority(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->priority; -} - -static void _setPriority(IoOperations *ops, uint32_t priority) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _UdpState *udpConnState = - (_UdpState *)ioOperations_GetClosure(ops); - udpConnState->priority = priority; -} -#endif /* WITH_POLICY */ - -static const char * _getInterfaceName(const IoOperations *ops) -{ - parcAssertNotNull(ops, "Parameter must be non-null"); - _UdpState *udpConnState = - (_UdpState *)ioOperations_GetClosure(ops); - return udpConnState->interfaceName; -} diff --git a/hicn-light/src/hicn/io/udpConnection.h b/hicn-light/src/hicn/io/udpConnection.h deleted file mode 100644 index 9fbc5348b..000000000 --- a/hicn-light/src/hicn/io/udpConnection.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file udpConnection.h - * @brief Represents a UDP connection (socket) for the connection table - * - * <#Detailed Description#> - * - */ - -#ifndef udpConnection_h -#define udpConnection_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> -#include <hicn/utils/address.h> - -/** - * Creates a UDP connection that can send to the remote address - * - * The address pair must both be same type (i.e. INET or INET6). - * - * @param [in] metis An allocated MetisForwarder (saves reference) - * @param [in] fd The socket to use - * @param [in] pair An allocated address pair for the connection (saves - * reference) - * @param [in] isLocal determines if the remote address is on the current system - * - * @retval non-null An allocated Io operations - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -IoOperations *udpConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd, - const AddressPair *pair, bool isLocal); -#endif // udpConnection_h diff --git a/hicn-light/src/hicn/io/udpListener.c b/hicn-light/src/hicn/io/udpListener.c deleted file mode 100644 index 3b318c500..000000000 --- a/hicn-light/src/hicn/io/udpListener.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 _WIN32 -#include <arpa/inet.h> -#include <unistd.h> -#endif -#include <errno.h> -#include <fcntl.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <hicn/core/messageHandler.h> - -#include <hicn/io/udpConnection.h> -#include <hicn/io/udpListener.h> - -#include <parc/algol/parc_Network.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/connection.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/messagePacketType.h> - -#define IPv4 4 -#define IPv6 6 - -struct udp_listener { - char *listenerName; - Forwarder *forwarder; - Logger *logger; - - PARCEvent *udp_event; - SocketType udp_socket; - uint16_t port; - - unsigned id; - char *interfaceName; - Address *localAddress; -}; - -static void _destroy(ListenerOps **listenerOpsPtr); -static const char *_getListenerName(const ListenerOps *ops); -static unsigned _getInterfaceIndex(const ListenerOps *ops); -static const Address *_getListenAddress(const ListenerOps *ops); -static EncapType _getEncapType(const ListenerOps *ops); -static const char *_getInterfaceName(const ListenerOps *ops); -static int _getSocket(const ListenerOps *ops); -static unsigned _createNewConnection(ListenerOps *listener, int fd, const AddressPair *pair); -static const Connection * _lookupConnection(ListenerOps * listener, const AddressPair *pair); - -static ListenerOps udpTemplate = { - .context = NULL, - .destroy = &_destroy, - .getInterfaceIndex = &_getInterfaceIndex, - .getListenAddress = &_getListenAddress, - .getEncapType = &_getEncapType, - .getSocket = &_getSocket, - .getListenerName = &_getListenerName, - .createConnection = &_createNewConnection, - .lookupConnection = &_lookupConnection, - .getInterfaceName = &_getInterfaceName, -}; - - -static void _readcb(int fd, PARCEventType what, void * listener_void); - -#ifdef __ANDROID__ -extern int bindSocket(int sock, const char* ifname); -#endif - -ListenerOps *udpListener_CreateInet6(Forwarder *forwarder, char *listenerName, - struct sockaddr_in6 sin6, const char *interfaceName) { - ListenerOps *ops = NULL; - - UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener)); - parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(UdpListener)); - udp->forwarder = forwarder; - udp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName)); - udp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName)); - udp->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - udp->localAddress = addressCreateFromInet6(&sin6); - udp->id = forwarder_GetNextConnectionId(forwarder); - - udp->udp_socket = (SocketType)socket(AF_INET6, SOCK_DGRAM, 0); - parcAssertFalse(udp->udp_socket < 0, "Error opening UDP socket: (%d) %s", - errno, strerror(errno)); - - int failure = 0; -#ifndef _WIN32 - // Set non-blocking flag - int flags = fcntl(udp->udp_socket, F_GETFL, NULL); - parcAssertTrue(flags != -1, - "fcntl failed to obtain file descriptor flags (%d)", errno); - failure = fcntl(udp->udp_socket, F_SETFL, flags | O_NONBLOCK); - parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)", - errno); -#else - // Set non-blocking flag - u_long mode = 1; - int result = ioctlsocket(udp->udp_socket, FIONBIO, &mode); - if (result != NO_ERROR) { - parcAssertTrue(result != NO_ERROR, - "ioctlsocket failed to set file descriptor"); - } -#endif - - int one = 1; - // don't hang onto address after listener has closed - failure = setsockopt(udp->udp_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&one, - (socklen_t)sizeof(one)); - parcAssertFalse(failure, "failed to set REUSEADDR on socket(%d)", errno); - - failure = bind(udp->udp_socket, (struct sockaddr *)&sin6, sizeof(sin6)); - - if (failure == 0) { -#ifdef __linux__ - if (strncmp("lo", interfaceName, 2) != 0) { - int ret = setsockopt(udp->udp_socket, SOL_SOCKET, SO_BINDTODEVICE, - interfaceName, strlen(interfaceName) + 1); - if (ret < 0) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "setsockopt(%d, SO_BINDTODEVICE, %s) failed (%d) %s", - udp->udp_socket, interfaceName, errno, strerror(errno)); -#ifdef __ANDROID__ - ret = bindSocket(udp->udp_socket, interfaceName); - if (ret < 0) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "bindSocket(%d, %s) failed", udp->udp_socket, interfaceName); - close(udp->udp_socket); - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - return NULL; - } else { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "bindSocket(%d, %s) success", udp->udp_socket, interfaceName); - } -#else - close(udp->udp_socket); - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - return NULL; -#endif - } - } -#endif - - ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - memcpy(ops, &udpTemplate, sizeof(ListenerOps)); - ops->context = udp; - - udp->udp_event = - dispatcher_CreateNetworkEvent(forwarder_GetDispatcher(forwarder), true, - _readcb, (void*)ops, udp->udp_socket); - dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder), - udp->udp_event); - - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(udp->localAddress); - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "UdpListener %p created for address %s", (void *)udp, str); - parcMemory_Deallocate((void **)&str); - } - } else { - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) { - int myerrno = errno; - char *str = addressToString(udp->localAddress); - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Error binding UDP socket to address %s: (%d) %s", str, - myerrno, strerror(myerrno)); - parcMemory_Deallocate((void **)&str); - } - parcMemory_Deallocate((void **)&udp->listenerName); - parcMemory_Deallocate((void **)&udp->interfaceName); -#ifndef _WIN32 - close(udp->udp_socket); -#else - closesocket(udp->udp_socket); -#endif - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - } - - return ops; -} - -ListenerOps *udpListener_CreateInet(Forwarder *forwarder, char *listenerName, - struct sockaddr_in sin, const char *interfaceName) { - ListenerOps *ops = NULL; - - UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener)); - parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(UdpListener)); - udp->forwarder = forwarder; - udp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName)); - udp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName)); - udp->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - udp->localAddress = addressCreateFromInet(&sin); - udp->id = forwarder_GetNextConnectionId(forwarder); - - udp->udp_socket = (SocketType)socket(AF_INET, SOCK_DGRAM, 0); - parcAssertFalse(udp->udp_socket < 0, "Error opening UDP socket: (%d) %s", - errno, strerror(errno)); - - int failure = 0; -#ifndef _WIN32 - // Set non-blocking flag - int flags = fcntl(udp->udp_socket, F_GETFL, NULL); - parcAssertTrue(flags != -1, - "fcntl failed to obtain file descriptor flags (%d)", errno); - failure = fcntl(udp->udp_socket, F_SETFL, flags | O_NONBLOCK); - parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)", - errno); -#else - u_long mode = 1; - int result = ioctlsocket(udp->udp_socket, FIONBIO, &mode); - if (result != NO_ERROR) { - parcAssertTrue(result != NO_ERROR, - "ioctlsocket failed to set file descriptor"); - } -#endif - - int one = 1; - // don't hang onto address after listener has closed - failure = setsockopt(udp->udp_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&one, - (socklen_t)sizeof(one)); - parcAssertFalse(failure, "failed to set REUSEADDR on socket(%d)", errno); - - failure = bind(udp->udp_socket, (struct sockaddr *)&sin, sizeof(sin)); - if (failure == 0) { -#ifdef __linux__ - if (strncmp("lo", interfaceName, 2) != 0) { - int ret = setsockopt(udp->udp_socket, SOL_SOCKET, SO_BINDTODEVICE, - interfaceName, strlen(interfaceName) + 1); - if (ret < 0) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "setsockopt(%d, SO_BINDTODEVICE, %s) failed (%d) %s", - udp->udp_socket, interfaceName, errno, strerror(errno)); -#ifdef __ANDROID__ - ret = bindSocket(udp->udp_socket, interfaceName); - if (ret < 0) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "bindSocket(%d, %s) failed", udp->udp_socket, interfaceName); - close(udp->udp_socket); - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - return NULL; - } else { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "bindSocket(%d, %s) success", udp->udp_socket, interfaceName); - } -#else - close(udp->udp_socket); - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - return NULL; -#endif - } - } -#endif - ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - memcpy(ops, &udpTemplate, sizeof(ListenerOps)); - ops->context = udp; - - udp->udp_event = - dispatcher_CreateNetworkEvent(forwarder_GetDispatcher(forwarder), true, - _readcb, (void *)ops, udp->udp_socket); - dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder), - udp->udp_event); - - - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(udp->localAddress); - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "UdpListener %p created for address %s", (void *)udp, str); - parcMemory_Deallocate((void **)&str); - } - } else { - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) { - int myerrno = errno; - char *str = addressToString(udp->localAddress); - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Error binding UDP socket to address %s: (%d) %s", str, - myerrno, strerror(myerrno)); - parcMemory_Deallocate((void **)&str); - } - parcMemory_Deallocate((void **)&udp->listenerName); - parcMemory_Deallocate((void **)&udp->interfaceName); -#ifndef _WIN32 - close(udp->udp_socket); -#else - closesocket(udp->udp_socket); -#endif - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - } - - return ops; -} - -static void udpListener_Destroy(UdpListener **listenerPtr) { - parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listenerPtr, - "Parameter must derefernce to non-null pointer"); - - UdpListener *udp = *listenerPtr; - - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "UdpListener %p destroyed", (void *)udp); - } - - parcMemory_Deallocate((void **)&udp->listenerName); - parcMemory_Deallocate((void **)&udp->interfaceName); -#ifndef _WIN32 - close(udp->udp_socket); -#else - closesocket(udp->udp_socket); -#endif - - addressDestroy(&udp->localAddress); - dispatcher_DestroyNetworkEvent(forwarder_GetDispatcher(udp->forwarder), - &udp->udp_event); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - *listenerPtr = NULL; -} - -static const char *_getListenerName(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return udp->listenerName; -} - -static const char *_getInterfaceName(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return udp->interfaceName; -} - -static void _destroy(ListenerOps **listenerOpsPtr) { - ListenerOps *ops = *listenerOpsPtr; - UdpListener *udp = (UdpListener *)ops->context; - udpListener_Destroy(&udp); - parcMemory_Deallocate((void **)&ops); - *listenerOpsPtr = NULL; -} - -static unsigned _getInterfaceIndex(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return udp->id; -} - -static const Address *_getListenAddress(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return udp->localAddress; -} - -static EncapType _getEncapType(const ListenerOps *ops) { return ENCAP_UDP; } - -static int _getSocket(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return (int)udp->udp_socket; -} - -// ===================================================================== - -/** - * @function _constructAddressPair - * @abstract Creates the address pair that uniquely identifies the connection - * @discussion - * The peerIpAddress must be of AF_INET or AF_INET6 family. - * - * @param <#param1#> - * @return Allocated MetisAddressPair, must be destroyed - */ -static AddressPair *_constructAddressPair(UdpListener *udp, - struct sockaddr *peerIpAddress, - socklen_t peerIpAddressLength) { - Address *remoteAddress; - - switch (peerIpAddress->sa_family) { - case AF_INET: - remoteAddress = - addressCreateFromInet((struct sockaddr_in *)peerIpAddress); - break; - - case AF_INET6: - remoteAddress = - addressCreateFromInet6((struct sockaddr_in6 *)peerIpAddress); - break; - - default: - parcTrapIllegalValue(peerIpAddress, - "Peer address unrecognized family for IP: %d", - peerIpAddress->sa_family); - } - - AddressPair *pair = addressPair_Create(udp->localAddress, remoteAddress); - addressDestroy(&remoteAddress); - - return pair; -} - -static const Connection * _lookupConnection(ListenerOps * listener, - const AddressPair *pair) { - UdpListener * udp = (UdpListener *)listener->context; - ConnectionTable *connTable = forwarder_GetConnectionTable(udp->forwarder); - return connectionTable_FindByAddressPair(connTable, pair); - -} - -/** - * @function _createNewConnection - * @abstract Creates a new Metis connection for the peer - * @discussion - * PRECONDITION: you know there's not an existing connection with the address - * pair - * - * Creates a new connection and adds it to the connection table. - * - * @param <#param1#> - * @return The connection id for the new connection - */ - -static unsigned _createNewConnection(ListenerOps * listener, int fd, - const AddressPair *pair) { - UdpListener * udp = (UdpListener *)listener->context; - - //check it the connection is local - bool isLocal = false; - const Address *localAddress = addressPair_GetLocal(pair); - if(addressGetType(localAddress) == ADDR_INET){ - struct sockaddr_in tmpAddr; - addressGetInet(localAddress, &tmpAddr); - if(parcNetwork_IsSocketLocal((struct sockaddr *)&tmpAddr)) - isLocal = true; - }else{ - struct sockaddr_in6 tmpAddr6; - addressGetInet6(localAddress, &tmpAddr6); - if(parcNetwork_IsSocketLocal((struct sockaddr *)&tmpAddr6)) - isLocal = true; - } - - // metisUdpConnection_Create takes ownership of the pair - IoOperations *ops = udpConnection_Create(udp->forwarder, udp->interfaceName, fd, pair, isLocal); - Connection *conn = connection_Create(ops); - // connection_AllowWldrAutoStart(conn); - - connectionTable_Add(forwarder_GetConnectionTable(udp->forwarder), conn); - unsigned connid = ioOperations_GetConnectionId(ops); - - return connid; -} - -static void _handleWldrNotification(UdpListener *udp, unsigned connId, - uint8_t *msgBuffer) { - const Connection *conn = connectionTable_FindById( - forwarder_GetConnectionTable(udp->forwarder), connId); - if (conn == NULL) { - parcMemory_Deallocate((void **)&msgBuffer); - return; - } - - Message *message = message_CreateFromByteArray( - connId, msgBuffer, MessagePacketType_WldrNotification, - forwarder_GetTicks(udp->forwarder), forwarder_GetLogger(udp->forwarder)); - - connection_HandleWldrNotification((Connection *)conn, message); - - message_Release(&message); -} - -static Message *_readMessage(ListenerOps * listener, int fd, - AddressPair *pair, uint8_t * packet, bool * processed) { - UdpListener * udp = (UdpListener *)listener->context; - - Message *message = NULL; - - unsigned connid; - bool foundConnection; - - const Connection *conn = _lookupConnection(listener, pair); - if (conn) { - connid = connection_GetConnectionId(conn); - foundConnection = true; - } else { - connid = 0; - foundConnection = false; - } - - if (messageHandler_IsTCP(packet)) { - *processed = true; - MessagePacketType pktType; - - if (messageHandler_IsData(packet)) { - pktType = MessagePacketType_ContentObject; - if (!foundConnection) { - parcMemory_Deallocate((void **)&packet); - return message; - } - } else if (messageHandler_IsInterest(packet)) { - pktType = MessagePacketType_Interest; - if (!foundConnection) { - connid = _createNewConnection(listener, fd, pair); - } - } else { - printf("Got a packet that is not a data nor an interest, drop it!\n"); - parcMemory_Deallocate((void **)&packet); - return message; - } - - message = message_CreateFromByteArray( - connid, packet, pktType, forwarder_GetTicks(udp->forwarder), - forwarder_GetLogger(udp->forwarder)); - - if (message == NULL) { - parcMemory_Deallocate((void **)&packet); - } - } else if (messageHandler_IsWldrNotification(packet)) { - *processed = true; - _handleWldrNotification(udp, connid, packet); - } else { - - *processed = messageHandler_handleHooks(udp->forwarder, packet, listener, fd, pair); - } - - return message; -} - -static void _readCommand(ListenerOps * listener, int fd, - AddressPair *pair, uint8_t * command) { - UdpListener * udp = (UdpListener *)listener->context; - - if (*command != REQUEST_LIGHT){ - printf("the message received is not a command, drop\n"); - parcMemory_Deallocate((void **) &command); - return; - } - - command_id id = *(command + 1); - - if (id >= LAST_COMMAND_VALUE){ - printf("the message received is not a valid command, drop\n"); - parcMemory_Deallocate((void **) &command); - return; - } - - unsigned connid; - - const Connection *conn = _lookupConnection(listener, pair); - if (conn) { - connid = connection_GetConnectionId(conn); - } else { - connid = _createNewConnection(listener, fd, pair); - } - - struct iovec *request; - if (!(request = (struct iovec *) parcMemory_AllocateAndClear( - sizeof(struct iovec) * 2))) { - return; - } - - request[0].iov_base = command; - request[0].iov_len = sizeof(header_control_message); - request[1].iov_base = command + sizeof(header_control_message); - request[1].iov_len = payloadLengthDaemon(id); - - forwarder_ReceiveCommand(udp->forwarder, id, request, connid); - parcMemory_Deallocate((void **) &command); - //parcMemory_Deallocate((void **) &request); -} - - -static bool _receivePacket(ListenerOps * listener, int fd, - AddressPair *pair, - uint8_t * packet) { - UdpListener * udp = (UdpListener *)listener->context; - bool processed = false; - Message *message = _readMessage(listener, fd, pair, - packet, &processed); - if (message) { - forwarder_Receive(udp->forwarder, message); - } - return processed; -} - -static void _readcb(int fd, PARCEventType what, void * listener_void) { - ListenerOps * listener = (ListenerOps *)listener_void; - UdpListener * udp = (UdpListener *)listener->context; - - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "%s socket %d what %s%s%s%s data %p", __func__, fd, - (what & PARCEventType_Timeout) ? " timeout" : "", - (what & PARCEventType_Read) ? " read" : "", - (what & PARCEventType_Write) ? " write" : "", - (what & PARCEventType_Signal) ? " signal" : "", udp); - } - - if (what & PARCEventType_Read) { - struct sockaddr_storage peerIpAddress; - socklen_t peerIpAddressLength = sizeof(peerIpAddress); - - //packet it deallocated by _receivePacket or _readCommand - uint8_t * packet = parcMemory_AllocateAndClear(1500); //max MTU - ssize_t readLength = recvfrom(fd, packet, 1500, 0, - (struct sockaddr *)&peerIpAddress, &peerIpAddressLength); - -#ifdef __APPLE__ - peerIpAddress.ss_len = 0x00; -#endif - - if(readLength < 0) { - printf("unable to read the message\n"); - parcMemory_Deallocate(packet); - return; - } - - AddressPair *pair = _constructAddressPair( - udp, (struct sockaddr *)&peerIpAddress, peerIpAddressLength); - - bool done = _receivePacket(listener, fd, pair, packet); - if(!done){ - _readCommand(listener, fd, pair, packet); - } - - addressPair_Release(&pair); - } -} diff --git a/hicn-light/src/hicn/io/udpListener.h b/hicn-light/src/hicn/io/udpListener.h deleted file mode 100644 index 62c09e4db..000000000 --- a/hicn-light/src/hicn/io/udpListener.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 udpListener_h -#define udpListener_h - -#ifndef _WIN32 -#include <netinet/in.h> -#endif - -#include <hicn/core/forwarder.h> -#include <hicn/io/listener.h> -#include <stdlib.h> - -struct udp_listener; -typedef struct udp_listener UdpListener; - -ListenerOps *udpListener_CreateInet6(Forwarder *forwarder, char *listenerName, - struct sockaddr_in6 sin6, const char *if_bind); -ListenerOps *udpListener_CreateInet(Forwarder *forwarder, char *listenerName, - struct sockaddr_in sin, const char *if_bind); -// void udpListener_SetPacketType(ListenerOps *ops, MessagePacketType type); -#endif // udpListener_h diff --git a/hicn-light/src/hicn/io/udpTunnel.c b/hicn-light/src/hicn/io/udpTunnel.c deleted file mode 100644 index 9f5249e3c..000000000 --- a/hicn-light/src/hicn/io/udpTunnel.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/io/udpConnection.h> -#include <hicn/io/udpListener.h> -#include <hicn/io/udpTunnel.h> - -IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder, - ListenerOps *localListener, - const Address *remoteAddress) { - parcAssertNotNull(forwarder, "Parameter metis must be non-null"); - parcAssertNotNull(localListener, "Parameter localListener must be non-null"); - parcAssertNotNull(remoteAddress, "Parameter remoteAddress must be non-null"); - - Logger *logger = forwarder_GetLogger(forwarder); - - IoOperations *ops = NULL; - if (localListener->getEncapType(localListener) == ENCAP_UDP) { - const Address *localAddress = - localListener->getListenAddress(localListener); - address_type localType = addressGetType(localAddress); - address_type remoteType = addressGetType(remoteAddress); - - if (localType == remoteType) { - AddressPair *pair = addressPair_Create(localAddress, remoteAddress); - - //check it the connection is local - bool isLocal = false; - if(localType == ADDR_INET){ - struct sockaddr_in tmpAddr; - addressGetInet(localAddress, &tmpAddr); - if(parcNetwork_IsSocketLocal((struct sockaddr *)&tmpAddr)) - isLocal = true; - }else{ - struct sockaddr_in6 tmpAddr6; - addressGetInet6(localAddress, &tmpAddr6); - if(parcNetwork_IsSocketLocal((struct sockaddr *)&tmpAddr6)) - isLocal = true; - } - int fd = localListener->getSocket(localListener); - // udpListener_SetPacketType(localListener, - // MessagePacketType_ContentObject); - ops = udpConnection_Create(forwarder, localListener->getInterfaceName(localListener), fd, pair, isLocal); - - addressPair_Release(&pair); - } else { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Local listener of type %s and remote type %s, cannot " - "establish tunnel", - addressTypeToString(localType), - addressTypeToString(remoteType)); - } - } - } else { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Local listener %p is not type UDP, cannot establish tunnel", - (void *)localListener); - } - } - - return ops; -} - -IoOperations *udpTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress) { - ListenerSet *set = forwarder_GetListenerSet(forwarder); - ListenerOps *listener = listenerSet_Find(set, ENCAP_UDP, localAddress); - IoOperations *ops = NULL; - if (listener) { - ops = udpTunnel_CreateOnListener(forwarder, listener, remoteAddress); - } else { - if (logger_IsLoggable(forwarder_GetLogger(forwarder), LoggerFacility_IO, - PARCLogLevel_Error)) { - char *str = addressToString(localAddress); - logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "Could not find listener to match address %s", str); - parcMemory_Deallocate((void **)&str); - } - } - return ops; -} diff --git a/hicn-light/src/hicn/io/udpTunnel.h b/hicn-light/src/hicn/io/udpTunnel.h deleted file mode 100644 index dacfdbb01..000000000 --- a/hicn-light/src/hicn/io/udpTunnel.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file udpTunnel.h - * @brief Establish a tunnel to a remote system - * - */ - -#ifndef udpTunnel_h -#define udpTunnel_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/ioOperations.h> -#include <hicn/io/listener.h> -#include <hicn/utils/address.h> - -/** - */ -IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder, - ListenerOps *localListener, - const Address *remoteAddress); - -/** - */ -IoOperations *udpTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress); - -#endif // udpTunnel_h diff --git a/hicn-light/src/hicn/messenger/messenger.c b/hicn-light/src/hicn/messenger/messenger.c deleted file mode 100644 index 45437539d..000000000 --- a/hicn-light/src/hicn/messenger/messenger.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * - * The messenger is contructued with a reference to the forwarder's dispatcher - * so it can schedule future events. When someone calls messenger_Send(...), it - * will put the message on a queue. If the queue was empty, it will scheudle - * itself to be run. By running the queue in a future dispatcher slice, it - * guarantees that there will be no re-entrant behavior between callers and - * message listeners. - * - * A recipient will receive a reference counted copy of the missive, so it must - * call - * {@link missive_Release} on it. - * - */ - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Event.h> -#include <parc/algol/parc_EventScheduler.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/messenger/messenger.h> -#include <hicn/messenger/missiveDeque.h> - -struct messenger { - PARCArrayList *callbacklist; - Dispatcher *dispatcher; - MissiveDeque *eventQueue; - - PARCEventTimer *timerEvent; -}; - -static void messenger_Dequeue(int fd, PARCEventType which_event, - void *messengerVoidPtr); - -// ========================================= -// Public API - -Messenger *messenger_Create(Dispatcher *dispatcher) { - Messenger *messenger = parcMemory_AllocateAndClear(sizeof(Messenger)); - parcAssertNotNull(messenger, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Messenger)); - - // NULL destroyer because we're storing structures owned by the caller - messenger->dispatcher = dispatcher; - messenger->callbacklist = parcArrayList_Create(NULL); - messenger->eventQueue = missiveDeque_Create(); - - // creates the timer, but does not start it - messenger->timerEvent = - dispatcher_CreateTimer(dispatcher, false, messenger_Dequeue, messenger); - - return messenger; -} - -void messenger_Destroy(Messenger **messengerPtr) { - parcAssertNotNull(messengerPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*messengerPtr, - "Parameter must dereference to non-null pointer"); - - Messenger *messenger = *messengerPtr; - parcArrayList_Destroy(&messenger->callbacklist); - missiveDeque_Release(&messenger->eventQueue); - dispatcher_DestroyTimerEvent(messenger->dispatcher, &messenger->timerEvent); - parcMemory_Deallocate((void **)&messenger); - *messengerPtr = NULL; -} - -void messenger_Send(Messenger *messenger, Missive *missive) { - parcAssertNotNull(messenger, "Parameter messenger must be non-null"); - parcAssertNotNull(missive, "Parameter event must be non-null"); - - missiveDeque_Append(messenger->eventQueue, missive); - if (missiveDeque_Size(messenger->eventQueue) == 1) { - // We need to scheudle ourself when an event is added to an empty queue - - // precondition: timer should not be running. - struct timeval immediateTimeout = {0, 0}; - dispatcher_StartTimer(messenger->dispatcher, messenger->timerEvent, - &immediateTimeout); - } -} - -static void removeRecipient(Messenger *messenger, - const MessengerRecipient *recipient) { - // don't increment i in the loop - for (size_t i = 0; i < parcArrayList_Size(messenger->callbacklist);) { - const void *p = parcArrayList_Get(messenger->callbacklist, i); - if (p == recipient) { - // removing will compact the list, so next element will also be at i. - parcArrayList_RemoveAndDestroyAtIndex(messenger->callbacklist, i); - } else { - i++; - } - } -} - -/** - * @function eventMessenger_Register - * @abstract Receive all event messages - */ -void messenger_Register(Messenger *messenger, - const MessengerRecipient *recipient) { - parcAssertNotNull(messenger, "Parameter messenger must be non-null"); - parcAssertNotNull(recipient, "Parameter recipient must be non-null"); - - // do not allow duplicates - removeRecipient(messenger, recipient); - - parcArrayList_Add(messenger->callbacklist, recipient); -} - -/** - * @function eventMessenger_Unregister - * @abstract Stop receiving event messages - */ -void messenger_Unregister(Messenger *messenger, - const MessengerRecipient *recipient) { - parcAssertNotNull(messenger, "Parameter messenger must be non-null"); - parcAssertNotNull(recipient, "Parameter recipient must be non-null"); - - removeRecipient(messenger, recipient); -} - -/** - * Called by event scheduler to give us a slice in which to dequeue events - * - * Called inside an event callback, so we now have exclusive access to the - * system. Dequeues all pending events and calls all the listeners for each one. - * - * @param [in] fd unused, required for compliance with function prototype - * @param [in] which_event unused, required for compliance with function - * prototype - * @param [in] messengerVoidPtr A void* to Messenger - */ -static void messenger_Dequeue(int fd, PARCEventType which_event, - void *messengerVoidPtr) { - Messenger *messenger = (Messenger *)messengerVoidPtr; - parcAssertNotNull(messenger, "Called with null messenger pointer"); - - Missive *missive; - while ((missive = missiveDeque_RemoveFirst(messenger->eventQueue)) != NULL) { - for (size_t i = 0; i < parcArrayList_Size(messenger->callbacklist); i++) { - MessengerRecipient *recipient = - parcArrayList_Get(messenger->callbacklist, i); - parcAssertTrue(recipient, "Recipient is null at index %zu", i); - - messengerRecipient_Deliver(recipient, missive_Acquire(missive)); - } - - // now let go of our reference to the missive - missive_Release(&missive); - } -} diff --git a/hicn-light/src/hicn/messenger/messenger.h b/hicn-light/src/hicn/messenger/messenger.h deleted file mode 100644 index 79d65cda6..000000000 --- a/hicn-light/src/hicn/messenger/messenger.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * The EventMessenger is the system that messages events between - * producers and consumers. - * - * Events are delivered in a deferred event cycle to avoid event callbacks - * firing when the event generator is still running. - */ - -#ifndef messenger_h -#define messenger_h - -#include <hicn/core/dispatcher.h> -#include <hicn/messenger/messengerRecipient.h> -#include <hicn/messenger/missive.h> - -struct messenger; -typedef struct messenger Messenger; - -/** - * @function eventmessenger_Create - * @abstract Creates an event notification system - * @discussion - * Typically there's only one of these managed by forwarder. - * - * @param dispatcher is the event dispatcher to use to schedule events. - */ -Messenger *messenger_Create(Dispatcher *dispatcher); - -/** - * @function eventMessenger_Destroy - * @abstract Destroys the messenger system, no notification is sent - */ -void messenger_Destroy(Messenger **messengerPtr); - -/** - * @function eventMessenger_Send - * @abstract Send an event message, takes ownership of the event memory - */ -void messenger_Send(Messenger *messenger, Missive *missive); - -/** - * @function eventMessenger_Register - * @abstract Receive all event messages - */ -void messenger_Register(Messenger *messenger, - const MessengerRecipient *recipient); - -/** - * @function eventMessenger_Unregister - * @abstract Stop receiving event messages - */ -void messenger_Unregister(Messenger *messenger, - const MessengerRecipient *recipient); -#endif // messenger_h diff --git a/hicn-light/src/hicn/messenger/messengerRecipient.c b/hicn-light/src/hicn/messenger/messengerRecipient.c deleted file mode 100644 index 17407030a..000000000 --- a/hicn-light/src/hicn/messenger/messengerRecipient.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/messenger/messenger.h> -#include <hicn/messenger/messengerRecipient.h> - -struct messenger_recipient { - void *context; - MessengerRecipientCallback *notify; -}; - -MessengerRecipient *messengerRecipient_Create( - void *recipientContext, MessengerRecipientCallback *recipientCallback) { - parcAssertNotNull(recipientCallback, - "Parameter recipientCallback must be non-null"); - - MessengerRecipient *recipient = - parcMemory_AllocateAndClear(sizeof(MessengerRecipient)); - parcAssertNotNull(recipient, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(MessengerRecipient)); - recipient->context = recipientContext; - recipient->notify = recipientCallback; - return recipient; -} - -void messengerRecipient_Destroy(MessengerRecipient **recipientPtr) { - parcAssertNotNull(recipientPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*recipientPtr, - "Parameter must dereference to non-null pointer"); - - parcMemory_Deallocate((void **)recipientPtr); - *recipientPtr = NULL; -} - -void *messengerRecipient_GetRecipientContext(MessengerRecipient *recipient) { - parcAssertNotNull(recipient, "Parameter must be non-null"); - - return recipient->context; -} - -void messengerRecipient_Deliver(MessengerRecipient *recipient, - Missive *missive) { - parcAssertNotNull(recipient, "Parameter must be non-null"); - recipient->notify(recipient, missive); -} diff --git a/hicn-light/src/hicn/messenger/messengerRecipient.h b/hicn-light/src/hicn/messenger/messengerRecipient.h deleted file mode 100644 index cb5705b3a..000000000 --- a/hicn-light/src/hicn/messenger/messengerRecipient.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file messengerRecipient.h - * @brief A recipient represents the entity that will recieve a Missive from the - * Messenger. - * - * A recipient is identified by the pair (contenxt, callback). The context is - * the recipients context, such as it's object pointer. The callback is the - * function the recipient uses to receive a Missive. - * - * If the receiver is going to do a lot of work or potentially send other - * missives, the receiver should queue the received notifications and process - * them in its own slice. - * - * A recipient will receive a reference counted copy of the missive, so it must - * call - * {@link missive_Release} on it. - * - * - */ - -#ifndef messengerRecipient_h -#define messengerRecipient_h - -#include <hicn/messenger/missive.h> - -struct messenger_recipient; -typedef struct messenger_recipient MessengerRecipient; - -/** - * @typedef MessengerRecipientCallback - * @abstract A recipient implements a callback to receive Missives. - * @constant recipient The recipient to recieve the missive - * @constant missive The missive, recipient must call {@link missive_Release} on - * it - */ -typedef void(MessengerRecipientCallback)(MessengerRecipient *recipient, - Missive *missive); - -/** - * Creates a Recipient, which represents a reciever of missives. - * - * Creates a Recipient that can be registerd with the Messenger using {@link - * messenger_Register}. - * - * @param [in] recipientContext This pointer will be passed back to the - * recipient with each missive, may be NULL - * @param [in] recipientCallback The function that receives the missive, must be - * non-NULL. - * - * @return non-null A recipient object - */ -MessengerRecipient *messengerRecipient_Create( - void *recipientContext, MessengerRecipientCallback *recipientCallback); - -/** - * Destroys a recipient. You should unregister it first. - * - * Destroying a recipient does not unregister it, so be sure to call - * {@link messenger_Unregister} first. - * - * @param [in,out] recipientPtr Double pointer to the recipient to destroy, will - * be NULL'd. - */ -void messengerRecipient_Destroy(MessengerRecipient **recipientPtr); - -/** - * Returns the recipient context passed on Create - * - * @param [in] recipient The recipient object - * - * @return pointer The context pointer used to create the object, maybe NULL - */ -void *messengerRecipient_GetRecipientContext(MessengerRecipient *recipient); - -/** - * Delivers a Missive to the recipient - * - * Passes the missive to the recipients callback. - * - * A recipient will receive a reference counted copy of the missive, so it must - * call - * {@link missive_Release} on it. - * - * @param [in] recipient The receiver - * @param [in] missive The message to send - */ -void messengerRecipient_Deliver(MessengerRecipient *recipient, - Missive *missive); -#endif // messengerRecipient_h diff --git a/hicn-light/src/hicn/messenger/missive.c b/hicn-light/src/hicn/messenger/missive.c deleted file mode 100644 index 5162e683d..000000000 --- a/hicn-light/src/hicn/messenger/missive.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/messenger/missive.h> - -struct missive { - MissiveType missiveType; - unsigned connectionid; -}; - -parcObject_Override(Missive, PARCObject, .isLockable = false); - -Missive *missive_Create(MissiveType missiveType, unsigned connectionid) { - Missive *missive = parcObject_CreateInstance(Missive); - missive->missiveType = missiveType; - missive->connectionid = connectionid; - return missive; -} - -Missive *missive_Acquire(const Missive *missive) { - return parcObject_Acquire(missive); -} - -void missive_Release(Missive **missivePtr) { - parcObject_Release((void **)missivePtr); -} - -MissiveType missive_GetType(const Missive *missive) { - parcAssertNotNull(missive, "Parameter missive must be non-null"); - return missive->missiveType; -} - -unsigned missive_GetConnectionId(const Missive *missive) { - parcAssertNotNull(missive, "Parameter missive must be non-null"); - return missive->connectionid; -} diff --git a/hicn-light/src/hicn/messenger/missive.h b/hicn-light/src/hicn/messenger/missive.h deleted file mode 100644 index fdeddce83..000000000 --- a/hicn-light/src/hicn/messenger/missive.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file missive.h - * @brief A Missive is a status message sent over a broadcast channel inside - * hicn-light - * - * Recipients use {@link messenger_Register} to receive missives. They are - * broadcast to all recipients. - * - */ -#ifndef missive_h -#define missive_h - -#include <hicn/messenger/missiveType.h> - -struct missive; -typedef struct missive Missive; - -/** - * Creates a Missive and sets the reference count to 1 - * - * A Missive may be sent to listeners of the Messenger to inform them of events - * on a connection id. - * - * @param [in] MissiveType The event type - * @param [in] connectionid The relevant conneciton id - * - * @return non-null A message - * @retrun null An error - */ -Missive *missive_Create(MissiveType missiveType, unsigned connectionid); - -/** - * Acquire a reference counted copy - * - * Increases the reference count by 1 and returns the original object. - * - * @param [in] missive An allocated missive - * - * @return non-null The original missive with increased reference count - */ -Missive *missive_Acquire(const Missive *missive); - -/** - * Releases a reference counted copy. - * - * If it is the last reference, the missive is freed. - * - * @param [in,out] missivePtr Double pointer to a missive, will be nulled. - */ -void missive_Release(Missive **missivePtr); - -/** - * Returns the type of the missive - * - * Returns the type of event the missive represents - * - * @param [in] missive An allocated missive - * - * @return MissiveType The event type - */ -MissiveType missive_GetType(const Missive *missive); - -/** - * Returns the connection ID of the missive - * - * An event is usually associated with a connection id (i.e. the I/O channel - * that originaged the event). - * - * @param [in] missive An allocated missive - * - * @return number The relevant connection id. - */ -unsigned missive_GetConnectionId(const Missive *missive); -#endif // missive_h diff --git a/hicn-light/src/hicn/messenger/missiveDeque.c b/hicn-light/src/hicn/messenger/missiveDeque.c deleted file mode 100644 index ab94a4f18..000000000 --- a/hicn-light/src/hicn/messenger/missiveDeque.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * A type-safe wrapper for Missives around a {@link PARCDeque}. We only - * implement the subset of functions used. - * - */ - -#include <parc/algol/parc_Deque.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/messenger/missive.h> -#include <hicn/messenger/missiveDeque.h> - -struct missive_deque { - PARCDeque *queue; -}; - -MissiveDeque *missiveDeque_Create(void) { - MissiveDeque *missiveDeque = - parcMemory_AllocateAndClear(sizeof(MissiveDeque)); - parcAssertNotNull(missiveDeque, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(MissiveDeque)); - missiveDeque->queue = parcDeque_Create(); - return missiveDeque; -} - -void missiveDeque_Release(MissiveDeque **dequePtr) { - parcAssertNotNull(dequePtr, "Double pointer must be non-null"); - parcAssertNotNull(*dequePtr, "Double pointer must dereference to non-null"); - MissiveDeque *missiveDeque = *dequePtr; - - // flush the queue - while (!parcDeque_IsEmpty(missiveDeque->queue)) { - Missive *missive = missiveDeque_RemoveFirst(missiveDeque); - missive_Release(&missive); - } - - parcDeque_Release(&missiveDeque->queue); - parcMemory_Deallocate((void **)&missiveDeque); - *dequePtr = NULL; -} - -MissiveDeque *missiveDeque_Append(MissiveDeque *deque, Missive *missive) { - parcAssertNotNull(deque, "Parameter deque must be non-null"); - parcAssertNotNull(missive, "Parameter missive must be non-null"); - - parcDeque_Append(deque->queue, missive); - return deque; -} - -Missive *missiveDeque_RemoveFirst(MissiveDeque *deque) { - parcAssertNotNull(deque, "Parameter deque must be non-null"); - return (Missive *)parcDeque_RemoveFirst(deque->queue); -} - -size_t missiveDeque_Size(const MissiveDeque *deque) { - parcAssertNotNull(deque, "Parameter deque must be non-null"); - return parcDeque_Size(deque->queue); -} diff --git a/hicn-light/src/hicn/messenger/missiveDeque.h b/hicn-light/src/hicn/messenger/missiveDeque.h deleted file mode 100644 index c6f955ce0..000000000 --- a/hicn-light/src/hicn/messenger/missiveDeque.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file missiveDeque - * @brief Double ended queue of Missives - * - * Used to queue Missives. This is a type-safe wrapper around {@link PARCDeque} - * - */ - -#ifndef missiveDeque_h -#define missiveDeque_h - -struct missive_deque; - -typedef struct missive_deque MissiveDeque; - -/** - * Create a `PARCDeque` instance with the default element equals function. - * - * The queue is created with no elements. - * - * The default element equals function is used by the `parcDeque_Equals` - * function and simply compares the values using the `==` operator. Users that - * need more sophisticated comparisons of the elements need to supply their own - * function via the `parcDeque_CreateCustom` function. - * - * @return non-NULL A pointer to a PARCDeque instance. - */ -MissiveDeque *missiveDeque_Create(void); - -void missiveDeque_Release(MissiveDeque **dequePtr); - -/** - * Appends the missive to the queue, taking ownership of the memory - */ -MissiveDeque *missiveDeque_Append(MissiveDeque *deque, Missive *missive); - -Missive *missiveDeque_RemoveFirst(MissiveDeque *deque); - -size_t missiveDeque_Size(const MissiveDeque *deque); -#endif // missiveDeque_h diff --git a/hicn-light/src/hicn/messenger/missiveType.h b/hicn-light/src/hicn/messenger/missiveType.h deleted file mode 100644 index b0d9c7704..000000000 --- a/hicn-light/src/hicn/messenger/missiveType.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file missiveType - * @brief Defines what a Missive represents - * - * Currently, missives only carry information about the state of a connection - * (created, up, down, closed, destroyed). - * - */ - -#ifndef missiveType_h -#define missiveType_h - -/** - * @typedef Represents the state of a connection - * @abstract CREATE is the initial state. UP & DOWN are recurrent states. - * CLOSED is transient. DESTROYED is the terminal state. - * @constant MissiveType_ConnectionCreate Connection created (new) - * @constant MissiveType_ConnectionUp Connection is active and passing - * data - * @constant MissiveType_ConnectionDown Connection is inactive and cannot - * pass data - * @constant MissiveType_ConnectionClosed Connection closed and will be - * destroyed - * @constant MissiveType_ConnectionDestroyed Connection destroyed - * @discussion State transitions: - * initial -> CREATE - * CREATE -> (UP | DOWN) - * UP -> (DOWN | DESTROYED) - * DOWN -> (UP | CLOSED | DESTROYED) - * CLOSED -> DESTROYED - * DESTROYED -> terminal - */ -typedef enum { - MissiveType_ConnectionCreate, - MissiveType_ConnectionUp, - MissiveType_ConnectionDown, - MissiveType_ConnectionClosed, - MissiveType_ConnectionDestroyed -} MissiveType; -#endif // missiveType_h diff --git a/hicn-light/src/hicn/platforms/CMakeLists.txt b/hicn-light/src/hicn/platforms/CMakeLists.txt index 4073e0558..14237c976 100644 --- a/hicn-light/src/hicn/platforms/CMakeLists.txt +++ b/hicn-light/src/hicn/platforms/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: diff --git a/hicn-light/src/hicn/platforms/README.txt b/hicn-light/src/hicn/platforms/README.txt index a1293944c..18c63a5f9 100644 --- a/hicn-light/src/hicn/platforms/README.txt +++ b/hicn-light/src/hicn/platforms/README.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -14,4 +14,3 @@ */ Operating system dependent modules. - diff --git a/hicn-light/src/hicn/platforms/android/system.c b/hicn-light/src/hicn/platforms/android/system.c index ba91748a0..80ca864ea 100644 --- a/hicn-light/src/hicn/platforms/android/system.c +++ b/hicn-light/src/hicn/platforms/android/system.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,6 +13,7 @@ * limitations under the License. */ +#if 0 #include <errno.h> #include <hicn/hicn-light/config.h> #include <stdio.h> @@ -181,3 +182,4 @@ unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) { return mtu; } +#endif
\ No newline at end of file diff --git a/hicn-light/src/hicn/platforms/darwin/system.c b/hicn-light/src/hicn/platforms/darwin/system.c index d817248a8..b80fa9b69 100644 --- a/hicn-light/src/hicn/platforms/darwin/system.c +++ b/hicn-light/src/hicn/platforms/darwin/system.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,6 +13,8 @@ * limitations under the License. */ +#if 0 + #include <errno.h> #include <ifaddrs.h> #include <hicn/hicn-light/config.h> @@ -144,3 +146,5 @@ unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) { } return mtu; } + +#endif diff --git a/hicn-light/src/hicn/platforms/linux/system.c b/hicn-light/src/hicn/platforms/linux/system.c index 3bf23cf57..4c14271a7 100644 --- a/hicn-light/src/hicn/platforms/linux/system.c +++ b/hicn-light/src/hicn/platforms/linux/system.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,6 +13,8 @@ * limitations under the License. */ +#if 0 + #include <errno.h> #include <ifaddrs.h> #include <hicn/hicn-light/config.h> @@ -37,8 +39,6 @@ #include <parc/assert/parc_Assert.h> -#include <hicn/utils/addressList.h> - /** * Returns the MTU for a named interface * @@ -66,11 +66,9 @@ static int getMtu(const char *ifname) { return ifr.ifr_mtu; } -InterfaceSet *system_Interfaces(Forwarder *forwarder) { +InterfaceSet *system_Interfaces(forwarder_t * forwarder) { InterfaceSet *set = interfaceSetCreate(); - Logger *logger = forwarder_GetLogger(forwarder); - // this is the dynamically allocated head of the list struct ifaddrs *ifaddr; int failure = getifaddrs(&ifaddr); @@ -93,60 +91,18 @@ InterfaceSet *system_Interfaces(Forwarder *forwarder) { interfaceSetAdd(set, iface); } - int family = next->ifa_addr->sa_family; - switch (family) { - case AF_INET: { - Address *address = - addressCreateFromInet((struct sockaddr_in *)next->ifa_addr); - interfaceAddAddress(iface, address); - break; - } - - case AF_INET6: { - Address *address = - addressCreateFromInet6((struct sockaddr_in6 *)next->ifa_addr); - interfaceAddAddress(iface, address); - break; - } - - case AF_PACKET: { - struct sockaddr_ll *addr_ll = (struct sockaddr_ll *)next->ifa_addr; - - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "sockaddr_ll family %d proto %d ifindex %d hatype %d " - "pkttype %d halen %d", - addr_ll->sll_family, addr_ll->sll_protocol, - addr_ll->sll_ifindex, addr_ll->sll_hatype, - addr_ll->sll_pkttype, addr_ll->sll_halen); - } - - switch (addr_ll->sll_hatype) { - // list of the ARP hatypes we can extract a MAC address from - case ARPHRD_ETHER: - // fallthrough - case ARPHRD_IEEE802: { - Address *address = addressCreateFromLink( - (uint8_t *)addr_ll->sll_addr, addr_ll->sll_halen); - interfaceAddAddress(iface, address); - break; - } - default: - break; - } - - break; - } - } + address_t * address = (address_t *)next->ifa_addr; + interfaceAddAddress(iface, address); } freeifaddrs(ifaddr); return set; } -Address *system_GetMacAddressByName(Forwarder *forwarder, +#if 0 +address_t *system_GetMacAddressByName(Forwarder *forwarder, const char *interfaceName) { - Address *linkAddress = NULL; + address_t *linkAddress = NULL; InterfaceSet *interfaceSet = system_Interfaces(forwarder); Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName); @@ -156,7 +112,7 @@ Address *system_GetMacAddressByName(Forwarder *forwarder, size_t length = addressListLength(addressList); for (size_t i = 0; i < length && !linkAddress; i++) { - const Address *a = addressListGetItem(addressList, i); + const address_t *a = addressListGetItem(addressList, i); if (addressGetType(a) == ADDR_LINK) { linkAddress = addressCopy(a); } @@ -167,6 +123,7 @@ Address *system_GetMacAddressByName(Forwarder *forwarder, return linkAddress; } +#endif unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) { unsigned mtu = 0; @@ -182,3 +139,5 @@ unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) { return mtu; } + +#endif diff --git a/hicn-light/src/hicn/platforms/windows/system.c b/hicn-light/src/hicn/platforms/windows/system.c index 55d89f63a..6bd36a372 100644 --- a/hicn-light/src/hicn/platforms/windows/system.c +++ b/hicn-light/src/hicn/platforms/windows/system.c @@ -1,223 +1,223 @@ -/*
- * Copyright (c) 2019 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.
- */
-
-#include <parc/assert/parc_Assert.h>
-#include <hicn/hicn-light/config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <string.h>
-
-#define WORKING_BUFFER_SIZE 15000
-#define MAX_TRIES 3
-
-#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
-#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
-
-#include <hicn/core/forwarder.h>
-#include <hicn/utils/interfaceSet.h>
-
-#include <hicn/utils/addressList.h>
-
-/**
- * Returns the MTU for a named interface
- *
- * On linux, we get the MTU by opening a socket and reading SIOCGIFMTU
- *
- * @param [in] ifname Interface name (e.g. "eth0")
- *
- * @retval number The MTU in bytes
- *
- * Example:
- * @code
- * <#example#>
- * @endcode
- */
-static int getMtu(const char *ifname) {
- PIP_ADAPTER_ADDRESSES pAddresses = NULL;
- PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
- ULONG outBufLen = 0;
- ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
- ULONG family = AF_UNSPEC;
-
- DWORD dwSize = 0;
- DWORD dwRetVal = 0;
- ULONG Iterations = 0;
- do {
- pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
- if (pAddresses == NULL) {
- printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
- exit(1);
- }
-
- dwRetVal =
- GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
-
- if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
- FREE(pAddresses);
- pAddresses = NULL;
- } else {
- break;
- }
-
- Iterations++;
-
- } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
-
- if (dwRetVal == NO_ERROR) {
- pCurrAddresses = pAddresses;
- while (pCurrAddresses) {
- if (strcmp(pCurrAddresses->AdapterName, ifname)) {
- int mtu = pCurrAddresses->Mtu;
- if (pAddresses) {
- FREE(pAddresses);
- }
- return mtu;
- }
- pCurrAddresses = pCurrAddresses->Next;
- }
- }
-
- if (pAddresses) {
- FREE(pAddresses);
- }
- return -1;
-}
-
-InterfaceSet *system_Interfaces(Forwarder *forwarder) {
- InterfaceSet *set = interfaceSetCreate();
-
- Logger *logger = forwarder_GetLogger(forwarder);
-
- DWORD dwSize = 0;
- DWORD dwRetVal = 0;
- unsigned int i = 0;
- // Set the flags to pass to GetAdaptersAddresses
- ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
-
- // default to unspecified address family (both)
- ULONG family = AF_UNSPEC;
-
- LPVOID lpMsgBuf = NULL;
-
- PIP_ADAPTER_ADDRESSES pAddresses = NULL;
- ULONG outBufLen = 0;
- ULONG Iterations = 0;
-
- PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
- PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
- PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
- PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
- IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
- IP_ADAPTER_PREFIX *pPrefix = NULL;
-
- outBufLen = WORKING_BUFFER_SIZE;
-
- do {
- pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
- parcAssertNotNull(
- pAddresses,
- "Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
- dwRetVal =
- GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
-
- if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
- FREE(pAddresses);
- pAddresses = NULL;
- } else {
- break;
- }
-
- Iterations++;
-
- } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
- if (dwRetVal == NO_ERROR) {
- // If successful, output some information from the data we received
- pCurrAddresses = pAddresses;
- while (pCurrAddresses) {
- if (pCurrAddresses->OperStatus == IfOperStatusUp) {
- Interface *iface =
- interfaceSetGetByName(set, pCurrAddresses->AdapterName);
- if (iface == NULL) {
- pMulticast = pCurrAddresses->FirstMulticastAddress;
- if (pMulticast) {
- for (i = 0; pMulticast != NULL; i++) pMulticast = pMulticast->Next;
- }
-
- iface = interfaceCreate(
- pCurrAddresses->AdapterName,
- forwarder_GetNextConnectionId(forwarder),
- pCurrAddresses->IfType == IF_TYPE_SOFTWARE_LOOPBACK, i > 0,
- pCurrAddresses->Mtu);
-
- interfaceSetAdd(set, iface);
- for (pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast != NULL;
- pUnicast = pUnicast->Next) {
- int family = pUnicast->Address.lpSockaddr->sa_family;
-
- switch (family) {
- case AF_INET: {
- char *ip = inet_ntoa(
- ((struct sockaddr_in *)(pUnicast->Address.lpSockaddr))
- ->sin_addr);
- Address *address = addressCreateFromInet(
- (struct sockaddr_in *)(pUnicast->Address.lpSockaddr));
- interfaceAddAddress(iface, address);
- break;
- }
-
- case AF_INET6: {
- char str[INET6_ADDRSTRLEN];
- inet_ntop(
- AF_INET6,
- &((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))
- ->sin6_addr,
- str, INET6_ADDRSTRLEN);
- Address *address = addressCreateFromInet6(
- (struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr));
- interfaceAddAddress(iface, address);
- break;
- }
-
- default:
- break;
- }
- }
- }
- }
- pCurrAddresses = pCurrAddresses->Next;
- }
- }
-
- if (pAddresses) {
- FREE(pAddresses);
- }
- return set;
-}
-
-Address *system_GetMacAddressByName(Forwarder *forwarder,
- const char *interfaceName) {
- return NULL;
-}
-
-unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) {
- unsigned mtu = 0;
-
- return mtu;
-}
+/* + * Copyright (c) 2021 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. + */ + +#include <parc/assert/parc_Assert.h> +#include <hicn/hicn-light/config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <sys/types.h> + +#include <errno.h> +#include <string.h> + +#define WORKING_BUFFER_SIZE 15000 +#define MAX_TRIES 3 + +#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) + +#include <hicn/core/forwarder.h> +#include <hicn/utils/interfaceSet.h> + +#include <hicn/utils/addressList.h> + +/** + * Returns the MTU for a named interface + * + * On linux, we get the MTU by opening a socket and reading SIOCGIFMTU + * + * @param [in] ifname Interface name (e.g. "eth0") + * + * @retval number The MTU in bytes + * + * Example: + * @code + * <#example#> + * @endcode + */ +static int getMtu(const char *ifname) { + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + ULONG outBufLen = 0; + ULONG flags = GAA_FLAG_INCLUDE_PREFIX; + ULONG family = AF_UNSPEC; + + DWORD dwSize = 0; + DWORD dwRetVal = 0; + ULONG Iterations = 0; + do { + pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen); + if (pAddresses == NULL) { + printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n"); + exit(1); + } + + dwRetVal = + GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); + + if (dwRetVal == ERROR_BUFFER_OVERFLOW) { + FREE(pAddresses); + pAddresses = NULL; + } else { + break; + } + + Iterations++; + + } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES)); + + if (dwRetVal == NO_ERROR) { + pCurrAddresses = pAddresses; + while (pCurrAddresses) { + if (strcmp(pCurrAddresses->AdapterName, ifname)) { + int mtu = pCurrAddresses->Mtu; + if (pAddresses) { + FREE(pAddresses); + } + return mtu; + } + pCurrAddresses = pCurrAddresses->Next; + } + } + + if (pAddresses) { + FREE(pAddresses); + } + return -1; +} + +InterfaceSet *system_Interfaces(Forwarder *forwarder) { + InterfaceSet *set = interfaceSetCreate(); + + Logger *logger = forwarder_GetLogger(forwarder); + + DWORD dwSize = 0; + DWORD dwRetVal = 0; + unsigned int i = 0; + // Set the flags to pass to GetAdaptersAddresses + ULONG flags = GAA_FLAG_INCLUDE_PREFIX; + + // default to unspecified address family (both) + ULONG family = AF_UNSPEC; + + LPVOID lpMsgBuf = NULL; + + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + ULONG outBufLen = 0; + ULONG Iterations = 0; + + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; + PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; + PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; + IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL; + IP_ADAPTER_PREFIX *pPrefix = NULL; + + outBufLen = WORKING_BUFFER_SIZE; + + do { + pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen); + parcAssertNotNull( + pAddresses, + "Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n"); + dwRetVal = + GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); + + if (dwRetVal == ERROR_BUFFER_OVERFLOW) { + FREE(pAddresses); + pAddresses = NULL; + } else { + break; + } + + Iterations++; + + } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES)); + if (dwRetVal == NO_ERROR) { + // If successful, output some information from the data we received + pCurrAddresses = pAddresses; + while (pCurrAddresses) { + if (pCurrAddresses->OperStatus == IfOperStatusUp) { + Interface *iface = + interfaceSetGetByName(set, pCurrAddresses->AdapterName); + if (iface == NULL) { + pMulticast = pCurrAddresses->FirstMulticastAddress; + if (pMulticast) { + for (i = 0; pMulticast != NULL; i++) pMulticast = pMulticast->Next; + } + + iface = interfaceCreate( + pCurrAddresses->AdapterName, + forwarder_GetNextConnectionId(forwarder), + pCurrAddresses->IfType == IF_TYPE_SOFTWARE_LOOPBACK, i > 0, + pCurrAddresses->Mtu); + + interfaceSetAdd(set, iface); + for (pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast != NULL; + pUnicast = pUnicast->Next) { + int family = pUnicast->Address.lpSockaddr->sa_family; + + switch (family) { + case AF_INET: { + char *ip = inet_ntoa( + ((struct sockaddr_in *)(pUnicast->Address.lpSockaddr)) + ->sin_addr); + Address *address = addressCreateFromInet( + (struct sockaddr_in *)(pUnicast->Address.lpSockaddr)); + interfaceAddAddress(iface, address); + break; + } + + case AF_INET6: { + char str[INET6_ADDRSTRLEN]; + inet_ntop( + AF_INET6, + &((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr)) + ->sin6_addr, + str, INET6_ADDRSTRLEN); + Address *address = addressCreateFromInet6( + (struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr)); + interfaceAddAddress(iface, address); + break; + } + + default: + break; + } + } + } + } + pCurrAddresses = pCurrAddresses->Next; + } + } + + if (pAddresses) { + FREE(pAddresses); + } + return set; +} + +Address *system_GetMacAddressByName(Forwarder *forwarder, + const char *interfaceName) { + return NULL; +} + +unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) { + unsigned mtu = 0; + + return mtu; +} diff --git a/hicn-light/src/hicn/platforms/windows/win_portability.c b/hicn-light/src/hicn/platforms/windows/win_portability.c index 3138640dd..e063cec24 100644 --- a/hicn-light/src/hicn/platforms/windows/win_portability.c +++ b/hicn-light/src/hicn/platforms/windows/win_portability.c @@ -1,50 +1,54 @@ -/*
- * Copyright (c) 2019 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.
- */
-
-#pragma once
-
-#include <hicn/platforms/windows/win_portability.h>
-
-int getline(char **lineptr, size_t *n, FILE *stream) {
- static char line[256];
- char *ptr;
- unsigned int len;
-
- if (lineptr == NULL || n == NULL) {
- errno = EINVAL;
- return -1;
- }
-
- if (ferror(stream)) return -1;
-
- if (feof(stream)) return -1;
-
- fgets(line, 256, stream);
-
- ptr = strchr(line, '\n');
- if (ptr) *ptr = '\0';
-
- len = (unsigned int)strlen(line);
-
- if ((len + 1) < 256) {
- ptr = (char *)realloc(*lineptr, 256);
- if (ptr == NULL) return (-1);
- *lineptr = ptr;
- *n = 256;
- }
-
- strcpy(*lineptr, line);
- return (len);
+/* + * Copyright (c) 2021 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. + */ + +#pragma once + +#include <hicn/platforms/windows/win_portability.h> +#include <hicn/util/sstrncpy.h> + +int getline(char **lineptr, size_t *n, FILE *stream) { + static char line[256]; + char *ptr; + unsigned int len; + int rc; + + if (lineptr == NULL || n == NULL) { + errno = EINVAL; + return -1; + } + + if (ferror(stream)) return -1; + + if (feof(stream)) return -1; + + fgets(line, 256, stream); + + ptr = strchr(line, '\n'); + if (ptr) *ptr = '\0'; + + len = (unsigned int)strlen(line); + + if ((len + 1) < 256) { + ptr = (char *)realloc(*lineptr, 256); + if (ptr == NULL) return (-1); + *lineptr = ptr; + *n = 256; + } + + rc = strcpy_s(*lineptr, 256, line); + if (rc != EOK) return -1; + + return (len); }
\ No newline at end of file diff --git a/hicn-light/src/hicn/platforms/windows/win_portability.h b/hicn-light/src/hicn/platforms/windows/win_portability.h index 5c25f4bb2..f42bf9d53 100644 --- a/hicn-light/src/hicn/platforms/windows/win_portability.h +++ b/hicn-light/src/hicn/platforms/windows/win_portability.h @@ -1,45 +1,45 @@ -/*
- * Copyright (c) 2019 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.
- */
-
-#pragma once
-#include <parc/windows/parc_Utils.h>
-#include <afunix.h>
-#include <io.h>
-#include <iphlpapi.h>
-#include <process.h>
-#include <stdio.h>
-#pragma comment(lib, "IPHLPAPI.lib")
-
-#ifndef in_port_t
-#define in_port_t uint16_t
-#endif
-
-#ifndef in_addr_t
-#define in_addr_t uint32_t
-#endif
-
-#ifndef strncasecmp
-#define strncasecmp _strnicmp
-#endif
-
-#ifndef strcasecmp
-#define strcasecmp _stricmp
-#endif
-
-#define HAVE_STRUCT_TIMESPEC
-
-#ifndef getline
-int getline(char **lineptr, size_t *n, FILE *stream);
+/* + * Copyright (c) 2021 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. + */ + +#pragma once +#include <parc/windows/parc_Utils.h> +#include <afunix.h> +#include <io.h> +#include <iphlpapi.h> +#include <process.h> +#include <stdio.h> +#pragma comment(lib, "IPHLPAPI.lib") + +#ifndef in_port_t +#define in_port_t uint16_t +#endif + +#ifndef in_addr_t +#define in_addr_t uint32_t +#endif + +#ifndef strncasecmp +#define strncasecmp _strnicmp +#endif + +#ifndef strcasecmp +#define strcasecmp _stricmp +#endif + +#define HAVE_STRUCT_TIMESPEC + +#ifndef getline +int getline(char **lineptr, size_t *n, FILE *stream); #endif
\ No newline at end of file diff --git a/hicn-light/src/hicn/processor/CMakeLists.txt b/hicn-light/src/hicn/processor/CMakeLists.txt deleted file mode 100644 index 17c3b1f88..000000000 --- a/hicn-light/src/hicn/processor/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2017-2019 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. - -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/fibEntry.h - ${CMAKE_CURRENT_SOURCE_DIR}/fibEntryList.h - ${CMAKE_CURRENT_SOURCE_DIR}/messageProcessor.h - ${CMAKE_CURRENT_SOURCE_DIR}/hashTableFunction.h - ${CMAKE_CURRENT_SOURCE_DIR}/pit.h - ${CMAKE_CURRENT_SOURCE_DIR}/fib.h - ${CMAKE_CURRENT_SOURCE_DIR}/pitEntry.h - ${CMAKE_CURRENT_SOURCE_DIR}/pitVerdict.h - ${CMAKE_CURRENT_SOURCE_DIR}/pitStandard.h -) - -list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/hashTableFunction.c - ${CMAKE_CURRENT_SOURCE_DIR}/fib.c - ${CMAKE_CURRENT_SOURCE_DIR}/fibEntry.c - ${CMAKE_CURRENT_SOURCE_DIR}/fibEntryList.c - ${CMAKE_CURRENT_SOURCE_DIR}/messageProcessor.c - ${CMAKE_CURRENT_SOURCE_DIR}/pit.c - ${CMAKE_CURRENT_SOURCE_DIR}/pitEntry.c - ${CMAKE_CURRENT_SOURCE_DIR}/pitStandard.c -) - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/processor/fib.c b/hicn-light/src/hicn/processor/fib.c deleted file mode 100644 index de0d1e2ef..000000000 --- a/hicn-light/src/hicn/processor/fib.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/core/forwarder.h> -#include <hicn/processor/fib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> - -#include <parc/assert/parc_Assert.h> - -struct node; -typedef struct node FibNode; - -struct node { - FibNode *left; - FibNode *right; - FibEntry *entry; - bool is_used; -}; - -struct fib { - Forwarder *forwarder; - FibNode *root; - unsigned size; -}; - -// ===================================================== -// Public API - -FibNode *_createNode(FibNode *left, FibNode *right, FibEntry *entry, - bool is_used) { - FibNode *n = parcMemory_AllocateAndClear(sizeof(FibNode)); - parcAssertNotNull(n, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(FibNode)); - - n->left = left; - n->right = right; - n->entry = entry; - n->is_used = is_used; - - return n; -} - -FIB *fib_Create(Forwarder *forwarder) { - FIB *hicnFib = parcMemory_AllocateAndClear(sizeof(FIB)); - parcAssertNotNull(hicnFib, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(FIB)); - - hicnFib->forwarder = forwarder; - hicnFib->root = NULL; - hicnFib->size = 0; - - return hicnFib; -} - -void _destroyNode(FibNode *n) { - fibEntry_Release(&n->entry); - parcMemory_Deallocate((void **)&n); - n = NULL; -} - -void _destroyFib(FibNode *n) { - if(n != NULL){ - _destroyFib(n->right); - _destroyFib(n->left); - _destroyNode(n); - } -} - -void fib_Destroy(FIB **fibPtr) { - parcAssertNotNull(fibPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*fibPtr, "Parameter must dereference to non-null pointer"); - - FIB *fib = *fibPtr; - _destroyFib(fib->root); - - parcMemory_Deallocate((void **)&fib); - *fibPtr = NULL; -} - -void fib_Add(FIB *fib, FibEntry *entry) { - parcAssertNotNull(fib, "Parameter must be non-null"); - parcAssertNotNull(entry, "Parameter must be non-null"); - - NameBitvector *new_prefix = name_GetContentName(fibEntry_GetPrefix(entry)); - uint32_t new_prefix_len = nameBitvector_GetLength(new_prefix); - FibNode * curr = fib->root; - FibNode * last = NULL; - - NameBitvector *curr_name; - uint32_t curr_prefix_len; - uint32_t match_len; - - while(curr != NULL){ - curr_name = name_GetContentName(fibEntry_GetPrefix(curr->entry)); - - match_len = nameBitvector_lpm(new_prefix, curr_name); - curr_prefix_len = nameBitvector_GetLength(curr_name); - - if(curr_prefix_len != match_len || //the new entry does not match the curr - curr_prefix_len >= new_prefix_len) //in this case we cannot procede anymore - break; - - last = curr; - bool bit; - int res = nameBitvector_testBit(new_prefix, curr_prefix_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (fib_add)"); - if(bit) - curr = curr->right; - else - curr = curr->left; - } - - //this is the root (empty trie) or an empty child - if(curr == NULL){ - FibNode * new_node = _createNode(NULL, NULL, entry, true); - if(last == NULL){ - fib->root = new_node; - }else{ - uint32_t last_prefix_len = nameBitvector_GetLength( - name_GetContentName(fibEntry_GetPrefix(last->entry))); - bool bit; - int res = nameBitvector_testBit(new_prefix, last_prefix_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (fib_add)"); - if(bit) - last->right = new_node; - else - last->left = new_node; - } - fib->size++; - return; - } - - //curr is not null - - //the node already exist - //if is not in use we turn it on and we set the rigth fib entry - if(curr_prefix_len == match_len && new_prefix_len == match_len){ - if(!curr->is_used){ - curr->is_used = true; - curr->entry = entry; - fib->size++; - return; - }else{ - //this case should never happen beacuse of the way we add - //entries in the fib - const NumberSet * next_hops = fibEntry_GetNexthops(entry); - unsigned size = (unsigned)fibEntry_NexthopCount(entry); - for(unsigned i = 0; i < size; i++) - fibEntry_AddNexthop(curr->entry,numberSet_GetItem(next_hops, i)); - } - } - - //key is prefix of the curr node (so new_prefix_len < curr_prefix_len) - if(new_prefix_len == match_len){ - FibNode * new_node = _createNode(NULL, NULL, entry, true); - if(last == NULL){ - fib->root = new_node; - }else{ - uint32_t last_prefix_len = nameBitvector_GetLength( - name_GetContentName(fibEntry_GetPrefix(last->entry))); - - bool bit; - int res = nameBitvector_testBit(new_prefix, last_prefix_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (fib_add)"); - if(bit) - last->right = new_node; - else - last->left = new_node; - } - bool bit; - int res = nameBitvector_testBit(curr_name, match_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (fib_add)"); - if(bit) - new_node->right = curr; - else - new_node->left = curr; - fib->size++; - return; - } - - //in the last case we need to add an inner node - Name * inner_prefix = name_Copy(fibEntry_GetPrefix(entry)); - nameBitvector_clear(name_GetContentName(inner_prefix), match_len); - name_setLen(inner_prefix, match_len); - - //this is an inner node, we don't want an acctive strategy - //like low_latency that sends probes in this node - FibEntry * inner_entry = fibEntry_Create(inner_prefix, - SET_STRATEGY_LOADBALANCER, fib->forwarder); - - FibNode * inner_node = _createNode(NULL, NULL, inner_entry, false); - FibNode * new_node = _createNode(NULL, NULL, entry, true); - - if(last == NULL){ - //we need to place the inner_node at the root - fib->root = inner_node; - }else{ - uint32_t last_prefix_len = nameBitvector_GetLength( - name_GetContentName(fibEntry_GetPrefix(last->entry))); - bool bit; - int res = nameBitvector_testBit(name_GetContentName(inner_prefix), - last_prefix_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (fib_add)"); - if(bit) - last->right = inner_node; - else - last->left = inner_node; - } - - bool bit; - int res = nameBitvector_testBit(new_prefix, match_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (fib_add)"); - - if(bit){ - inner_node -> left = curr; - inner_node ->right = new_node; - }else{ - inner_node -> left = new_node; - inner_node ->right = curr; - } - fib->size ++; - - name_Release(&inner_prefix); -} - -FibEntry *fib_Contains(const FIB *fib, const Name *prefix) { - parcAssertNotNull(fib, "Parameter must be non-null"); - parcAssertNotNull(prefix, "Parameter must be non-null"); - - NameBitvector *key_name = name_GetContentName(prefix); - uint32_t key_prefix_len = nameBitvector_GetLength(key_name); - - FibNode * curr = fib->root; - - while(curr != NULL){ - NameBitvector *curr_name = - name_GetContentName(fibEntry_GetPrefix(curr->entry)); - uint32_t match_len = nameBitvector_lpm(key_name, curr_name); - uint32_t curr_prefix_len = nameBitvector_GetLength(curr_name); - - if(match_len < curr_prefix_len){ - //the current node does not match completelly the key, so - //the key is not in the trie - //this implies curr_prefix_len > key_prefix_len - return NULL; - } - - if(curr_prefix_len == key_prefix_len){ //== match_len - //this is an exact match - if(curr->is_used){ - //we found the key - return curr->entry; - }else{ - //the key does not exists - return NULL; - } - } - - bool bit; - int res = nameBitvector_testBit(key_name, curr_prefix_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (fib_contains)"); - - if(bit) - curr = curr->right; - else - curr = curr->left; - } - - return NULL; -} - -void _removeNode(FIB *fib, const Name *prefix){ - parcAssertNotNull(fib, "Parameter must be non-null"); - parcAssertNotNull(prefix, "Parameter must be non-null"); - - NameBitvector *key_name = name_GetContentName(prefix); - uint32_t key_prefix_len = nameBitvector_GetLength(key_name); - - FibNode * curr = fib->root; - FibNode * parent = NULL; - FibNode * grandpa = NULL; - - uint32_t match_len; - uint32_t curr_prefix_len; - while(curr != NULL){ - NameBitvector *curr_name = - name_GetContentName(fibEntry_GetPrefix(curr->entry)); - match_len = nameBitvector_lpm(key_name, curr_name); - curr_prefix_len = nameBitvector_GetLength(curr_name); - - if(match_len < curr_prefix_len || - curr_prefix_len == key_prefix_len){ - break; - } - - grandpa = parent; - parent = curr; - - bool bit; - int res = nameBitvector_testBit(key_name, curr_prefix_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (_removeNode)"); - - if(bit) - curr = curr->right; - else - curr = curr->left; - } - - if(curr == NULL || - !curr->is_used || - (curr_prefix_len != key_prefix_len)){ - //the node does not exists - return; - } - - //curr has 2 children, leave it there and mark it as inner - if(curr->right != NULL && curr->left != NULL){ - curr->is_used = false; - fib->size--; - return; - } - - //curr has no children - if(curr->right == NULL && curr->left == NULL){ - if (parent == NULL){ - //curr is the root and is the only node in the fib - fib->root = NULL; - fib->size--; - _destroyNode(curr); - return; - } - if(grandpa == NULL){ - //parent is the root - if(fib->root->left == curr) - fib->root->left = NULL; - else - fib->root->right = NULL; - fib->size--; - _destroyNode(curr); - return; - } - if(!parent->is_used){ - //parent is an inner node - //remove curr and inner_node (parent), connect the other child - //of the parent to the grandpa - FibNode * tmp; - if(parent->right == curr) - tmp = parent->left; - else - tmp = parent->right; - - if(grandpa->right == parent) - grandpa->right = tmp; - else - grandpa->left = tmp; - - fib->size--; - _destroyNode(curr); - _destroyNode(parent); - return; - } - //parent is node not an inner_node - //just remove curr the node - if(parent->right == curr) - parent->right = NULL; - else - parent->left = NULL; - fib->size--; - _destroyNode(curr); - return; - } - - //curr has one child - if(curr->right != NULL || curr->left != NULL){ - if(parent == NULL){ - //curr is the root - if(fib->root->right != NULL) - fib->root = fib->root->right; - else - fib->root = fib->root->left; - fib->size--; - _destroyNode(curr); - return; - } - //attach the child of curr to parent - FibNode * tmp; - if(curr->right != NULL) - tmp = curr->right; - else - tmp = curr->left; - - if(parent->right == curr) - parent->right = tmp; - else - parent->left = tmp; - - fib->size--; - _destroyNode(curr); - return; - } -} - -void fib_Remove(FIB *fib, const Name *name, unsigned connId) { - parcAssertNotNull(fib, "Parameter must be non-null"); - parcAssertNotNull(name, "Parameter must be non-null"); - - FibEntry *entry = fib_Contains(fib, name); - - if (entry == NULL) { - return; - } - - fibEntry_RemoveNexthopByConnectionId(entry, connId); -#ifndef WITH_MAPME - if (fibEntry_NexthopCount(entry) == 0) - _removeNode(fib, name); -#endif /* WITH_MAPME */ - - // XXX We never release the FIB entry here it seems, including the inner - // prefix - -} - -void _removeConnectionId(FibNode *n, unsigned connectionId, - FibEntryList *list) { - if(n != NULL){ - if(n->is_used){ - fibEntry_RemoveNexthopByConnectionId(n->entry, connectionId); -#ifndef WITH_MAPME - if (fibEntry_NexthopCount(n->entry) == 0) { - fibEntryList_Append(list, n->entry); - } -#endif /* WITH_MAPME */ - } - _removeConnectionId(n->right, connectionId, list); - _removeConnectionId(n->left, connectionId, list); - } -} - -void fib_RemoveConnectionId(FIB *fib, unsigned connectionId) { - parcAssertNotNull(fib, "Parameter must be non-null"); - - FibEntryList *list = fibEntryList_Create(); - _removeConnectionId(fib->root, connectionId, list); - - for (int i = 0; i < fibEntryList_Length(list); i++) { - _removeNode(fib, fibEntry_GetPrefix(fibEntryList_Get(list, i))); - } - - fibEntryList_Destroy(&list); -} - -size_t fib_Length(const FIB *fib) { - parcAssertNotNull(fib, "Parameter must be non-null"); - return fib->size; -} - -FibEntry *fib_MatchMessage(const FIB *fib, const Message *interestMessage) { - parcAssertNotNull(fib, "Parameter must be non-null"); - parcAssertNotNull(interestMessage, "Parameter must be non-null"); - return fib_MatchBitvector(fib, name_GetContentName( - message_GetName(interestMessage))); -} - -FibEntry *fib_MatchName(const FIB *fib, const Name *name) { - parcAssertNotNull(fib, "Parameter must be non-null"); - parcAssertNotNull(name, "Parameter must be non-null"); - return fib_MatchBitvector(fib, name_GetContentName(name)); -} - - -FibEntry *fib_MatchBitvector(const FIB *fib, const NameBitvector *name){ - parcAssertNotNull(fib, "Parameter must be non-null"); - parcAssertNotNull(name, "Parameter must be non-null"); - - uint32_t key_prefix_len = nameBitvector_GetLength(name); - - FibNode * curr = fib->root; - FibNode * candidate = NULL; - - while(curr != NULL){ - NameBitvector *curr_name = - name_GetContentName(fibEntry_GetPrefix(curr->entry)); - uint32_t match_len = nameBitvector_lpm(name, curr_name); - uint32_t curr_prefix_len = nameBitvector_GetLength(curr_name); - - if(match_len < curr_prefix_len){ - //the current node does not match completelly the key, so - //return the parent of this node (saved in candidate) - break; - } - - if(curr->is_used) - candidate = curr; - - //if we are here match_len == curr_prefix_len (can't be larger) - //so this node is actually a good candidate for a match - if(curr_prefix_len == key_prefix_len){ - //this an exact match, do not continue - break; - } - - bool bit; - int res = nameBitvector_testBit(name, curr_prefix_len, &bit); - parcAssertFalse(res < 0, "error testing name bit (fib_MatchBitvector)"); - - if(bit) - curr = curr->right; - else - curr = curr->left; - } - - if(candidate != NULL){ - return candidate->entry; - } - - return NULL; -} - -void _collectFibEntries(FibNode *n, FibEntryList *list){ - if(n != NULL){ - if(n->is_used) - fibEntryList_Append(list, n->entry); - _collectFibEntries(n->right, list); - _collectFibEntries(n->left, list); - } -} - -FibEntryList *fib_GetEntries(const FIB *fib) { - parcAssertNotNull(fib, "Parameter must be non-null"); - FibEntryList *list = fibEntryList_Create(); - - _collectFibEntries(fib->root, list); - - return list; -} diff --git a/hicn-light/src/hicn/processor/fib.h b/hicn-light/src/hicn/processor/fib.h deleted file mode 100644 index ef9e121b8..000000000 --- a/hicn-light/src/hicn/processor/fib.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 fib_h -#define fib_h - -#include <hicn/core/message.h> -#include <hicn/core/name.h> -#include <hicn/processor/fibEntry.h> -#include <hicn/processor/fibEntryList.h> - -struct fib; -typedef struct fib FIB; - -FIB *fib_Create(Forwarder *forwarder); - -void fib_Destroy(FIB **fibPtr); - -void fib_Add(FIB *fib, FibEntry *node); - -FibEntry *fib_Contains(const FIB *fib, const Name *prefix); - -void fib_Remove(FIB *fib, const Name *prefix, unsigned connId); - -void fib_RemoveConnectionId(FIB *fib, unsigned connectionId); - -FibEntry *fib_MatchMessage(const FIB *fib, const Message *interestMessage); -FibEntry *fib_MatchName(const FIB *fib, const Name *name); -FibEntry *fib_MatchBitvector(const FIB *fib, const NameBitvector *name); - -size_t fib_Length(const FIB *fib); - -FibEntryList *fib_GetEntries(const FIB *fib); -#endif // fib_h diff --git a/hicn-light/src/hicn/processor/fibEntry.c b/hicn-light/src/hicn/processor/fibEntry.c deleted file mode 100644 index 00e8dfa11..000000000 --- a/hicn-light/src/hicn/processor/fibEntry.c +++ /dev/null @@ -1,894 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/core/numberSet.h> -#include <hicn/processor/fibEntry.h> - -#include <hicn/core/nameBitvector.h> - -#include <hicn/strategies/loadBalancer.h> -#include <hicn/strategies/lowLatency.h> -#include <hicn/strategies/rnd.h> -#include <hicn/strategies/strategyImpl.h> -#ifdef WITH_MAPME -#include <parc/algol/parc_HashMap.h> -#include <hicn/core/ticks.h> -#endif /* WITH_MAPME */ - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> - -#include <hicn/utils/commands.h> -#include <hicn/core/connectionState.h> - -#ifdef WITH_POLICY -#include <hicn/core/forwarder.h> -#include <hicn/policy.h> - -#ifdef WITH_MAPME -#include <hicn/core/mapme.h> -#endif /* WITH_MAPME */ - -#define ALPHA 0.5 - -#endif /* WITH_POLICY */ - -struct fib_entry { - Name *name; - unsigned refcount; - StrategyImpl *fwdStrategy; -#ifdef WITH_POLICY - NumberSet *nexthops; - const Forwarder * forwarder; - hicn_policy_t policy; - policy_counters_t policy_counters; -// NumberSet *available_nexthops; -#ifdef WITH_MAPME - /* In case of no multipath, this stores the previous decision taken by policy */ -#endif /* WITH_MAPME */ -#endif /* WITH_POLICY */ -#ifdef WITH_MAPME - NumberSet * previous_nexthops; - const void *userDataOwner; - void *userData; - void (*userDataRelease)(const void *owner, void **userData); -#endif /* WITH_MAPME */ -}; - -#ifdef WITH_POLICY -FibEntry *fibEntry_Create(Name *name, strategy_type fwdStrategy, const Forwarder * forwarder) { -#else -FibEntry *fibEntry_Create(Name *name, strategy_type fwdStrategy) { -#endif /* WITH_POLICY */ - FibEntry *fibEntry = parcMemory_AllocateAndClear(sizeof(FibEntry)); - parcAssertNotNull(fibEntry, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(FibEntry)); - fibEntry->name = name_Acquire(name); - - switch (fwdStrategy) { - case SET_STRATEGY_LOADBALANCER: - fibEntry->fwdStrategy = strategyLoadBalancer_Create(); - break; - - case SET_STRATEGY_RANDOM: - fibEntry->fwdStrategy = strategyRnd_Create(); - - case SET_STRATEGY_LOW_LATENCY: - fibEntry->fwdStrategy = strategyLowLatency_Create(); - break; - - default: - // LB is the default strategy - fwdStrategy = SET_STRATEGY_LOADBALANCER; - fibEntry->fwdStrategy = strategyLoadBalancer_Create(); - break; - } - - fibEntry->refcount = 1; - -#ifdef WITH_MAPME - fibEntry->userDataOwner = NULL; - fibEntry->userData = NULL; - fibEntry->userDataRelease = NULL; -#endif /* WITH_MAPME */ - -#ifdef WITH_POLICY - fibEntry->nexthops = numberSet_Create(); - fibEntry->forwarder = forwarder; - fibEntry->policy = POLICY_NONE; - fibEntry->policy_counters = POLICY_COUNTERS_NONE; -#endif /* WITH_POLICY */ - - if(fwdStrategy == SET_STRATEGY_LOW_LATENCY){ - strategyLowLatency_SetStrategy(fibEntry->fwdStrategy, - fibEntry->forwarder, fibEntry, - 0, NULL); - } - return fibEntry; -} - -FibEntry *fibEntry_Acquire(const FibEntry *fibEntry) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); - FibEntry *copy = (FibEntry *)fibEntry; - copy->refcount++; - return copy; -} - -void fibEntry_Release(FibEntry **fibEntryPtr) { - FibEntry *fibEntry = *fibEntryPtr; - parcAssertTrue(fibEntry->refcount > 0, "Illegal state: refcount is 0"); - fibEntry->refcount--; - if (fibEntry->refcount == 0) { - name_Release(&fibEntry->name); - fibEntry->fwdStrategy->destroy(&(fibEntry->fwdStrategy)); -#ifdef WITH_MAPME - if (fibEntry->userData) { - fibEntry->userDataRelease(fibEntry->userDataOwner, &fibEntry->userData); - } -#endif /* WITH_MAPME */ -#ifdef WITH_POLICY - numberSet_Release(&fibEntry->nexthops); -#endif /* WITH_POLICY */ - parcMemory_Deallocate((void **)&fibEntry); - } - *fibEntryPtr = NULL; -} - -void fibEntry_SetStrategy(FibEntry *fibEntry, strategy_type strategy, - unsigned related_prefixes_len, - Name **related_prefixes) { - StrategyImpl *fwdStrategyImpl; - - switch (strategy) { - case SET_STRATEGY_LOADBALANCER: - fwdStrategyImpl = strategyLoadBalancer_Create(); - break; - - case SET_STRATEGY_RANDOM: - fwdStrategyImpl = strategyRnd_Create(); - break; - - case SET_STRATEGY_LOW_LATENCY: - fwdStrategyImpl = strategyLowLatency_Create(); - break; - - default: - // LB is the default strategy - strategy = SET_STRATEGY_LOADBALANCER; - fwdStrategyImpl = strategyLoadBalancer_Create(); - break; - } - - if(strategy == SET_STRATEGY_LOW_LATENCY){ - strategyLowLatency_SetStrategy(fwdStrategyImpl, - fibEntry->forwarder, fibEntry, - related_prefixes_len, related_prefixes); - } - - const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry); - unsigned size = (unsigned)fibEntry_NexthopCount(fibEntry); - for (unsigned i = 0; i < size; i++) { - fwdStrategyImpl->addNexthop(fwdStrategyImpl, - numberSet_GetItem(nexthops, i)); - } - fibEntry->fwdStrategy->destroy(&(fibEntry->fwdStrategy)); - fibEntry->fwdStrategy = fwdStrategyImpl; -} - -#ifdef WITH_POLICY - -/* - * Update available next hops following policy update. - */ -NumberSet * -fibEntry_GetAvailableNextHops(const FibEntry *fibEntry, unsigned in_connection) { - ConnectionTable * table = forwarder_GetConnectionTable(fibEntry->forwarder); - NumberSet * nexthops; - bool dealloc_nexthops = false; - hicn_policy_t policy = fibEntry_GetPolicy(fibEntry); - - /* Reset available next hops and start filtering */ - NumberSet * available_nexthops = numberSet_Create(); - - /* - * Give absolute preference to local faces, with no policy, unless - * in_connection == ~0, which means we are searching faces on which to - * advertise our prefix - */ - if (in_connection == ~0) { - /* We might advertise among all available up connections */ - nexthops = numberSet_Create(); - dealloc_nexthops = true; - - ConnectionList * list = connectionTable_GetEntries(table); - for (size_t i = 0; i < connectionList_Length(list); i++) { - Connection *conn = connectionList_Get(list, i); - if (connection_IsLocal(conn)) - continue; - if (connection_GetAdminState(conn) == CONNECTION_STATE_DOWN) - continue; - if (connection_GetState(conn) == CONNECTION_STATE_DOWN) - continue; - numberSet_Add(nexthops, connection_GetConnectionId(conn)); - } - connectionList_Destroy(&list); - } else { - nexthops = (NumberSet*)fibEntry_GetNexthops(fibEntry); - for (size_t k = 0; k < numberSet_Length(nexthops); k++) { - unsigned conn_id = numberSet_GetItem(nexthops, k); - /* Filtering out ingress face */ - if (conn_id == in_connection) - continue; - /* Filtering out DOWN faces */ - const Connection * conn = connectionTable_FindById(table, conn_id); - if (!conn) - continue; - if (connection_GetAdminState(conn) == CONNECTION_STATE_DOWN) - continue; - if (connection_GetState(conn) == CONNECTION_STATE_DOWN) - continue; - if (!connection_IsLocal(conn)) - continue; - numberSet_Add(available_nexthops, conn_id); - } - - /* Terminate selection if there are any local face available */ - if (numberSet_Length(available_nexthops) > 0){ - if(dealloc_nexthops){ - numberSet_Release(&nexthops); - } - /* No filtering as all local faces are considered equivalent */ - return available_nexthops; - } - } - - for (size_t k = 0; k < numberSet_Length(nexthops); k++) { - unsigned conn_id = numberSet_GetItem(nexthops, k); - const Connection * conn; - - /* Filtering out ingress face */ - if (conn_id == in_connection) - continue; - - /* Filtering out DOWN faces */ - conn = connectionTable_FindById(table, conn_id); - if (!conn) - continue; - if (connection_GetAdminState(conn) == CONNECTION_STATE_DOWN) - continue; - if (connection_GetState(conn) == CONNECTION_STATE_DOWN) - continue; - - /* Policy filtering : next hops */ - if ((policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_REQUIRE) && - (!connection_HasTag(conn, POLICY_TAG_WIRED))) - continue; - if ((policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_PROHIBIT) && - (connection_HasTag(conn, POLICY_TAG_WIRED))) - continue; - if ((policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_REQUIRE) && - (!connection_HasTag(conn, POLICY_TAG_WIFI))) - continue; - if ((policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_PROHIBIT) && - (connection_HasTag(conn, POLICY_TAG_WIFI))) - continue; - if ((policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_REQUIRE) && - (!connection_HasTag(conn, POLICY_TAG_CELLULAR))) - continue; - if ((policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_PROHIBIT) && - (connection_HasTag(conn, POLICY_TAG_CELLULAR))) - continue; - if ((policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE) && - (!connection_HasTag(conn, POLICY_TAG_TRUSTED))) - continue; - if ((policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_PROHIBIT) && - (connection_HasTag(conn, POLICY_TAG_TRUSTED))) - continue; - - numberSet_Add(available_nexthops, conn_id); - } - - if(dealloc_nexthops) - numberSet_Release(&nexthops); - - if (numberSet_Length(available_nexthops) == 0) - return available_nexthops; - - /* We have at least one matching next hop, implement heuristic */ - - /* - * As VPN connections might trigger duplicate uses of one interface, we start - * by filtering out interfaces based on trust status. - */ - NumberSet * filtered_nexthops = numberSet_Create(); - if ((policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE) || - (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_PREFER)) { - /* Try to filter out NON TRUSTED faces */ - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (!connection_HasTag(conn, POLICY_TAG_TRUSTED)) - continue; - numberSet_Add(filtered_nexthops, conn_id); - } - } else { - /* Try to filter out TRUSTED faces */ - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (connection_HasTag(conn, POLICY_TAG_TRUSTED)) - continue; - numberSet_Add(filtered_nexthops, conn_id); - } - } - if (numberSet_Length(filtered_nexthops) > 0) { - numberSet_Release(&available_nexthops); - available_nexthops = numberSet_Create(); - numberSet_AddSet(available_nexthops, filtered_nexthops); - } - numberSet_Release(&filtered_nexthops); - - /* Other preferences */ - if (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_AVOID) { - filtered_nexthops = numberSet_Create(); - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (connection_HasTag(conn, POLICY_TAG_WIRED)) - continue; - numberSet_Add(filtered_nexthops, conn_id); - } - if (numberSet_Length(filtered_nexthops) > 0) { - numberSet_Release(&available_nexthops); - available_nexthops = numberSet_Create(); - numberSet_AddSet(available_nexthops, filtered_nexthops); - } - numberSet_Release(&filtered_nexthops); - } - if (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_AVOID) { - filtered_nexthops = numberSet_Create(); - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (connection_HasTag(conn, POLICY_TAG_WIFI)) - continue; - numberSet_Add(filtered_nexthops, conn_id); - } - if (numberSet_Length(filtered_nexthops) > 0) { - numberSet_Release(&available_nexthops); - available_nexthops = numberSet_Create(); - numberSet_AddSet(available_nexthops, filtered_nexthops); - } - numberSet_Release(&filtered_nexthops); - } - if (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_AVOID) { - filtered_nexthops = numberSet_Create(); - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (connection_HasTag(conn, POLICY_TAG_CELLULAR)) - continue; - numberSet_Add(filtered_nexthops, conn_id); - } - if (numberSet_Length(filtered_nexthops) > 0) { - numberSet_Release(&available_nexthops); - available_nexthops = numberSet_Create(); - numberSet_AddSet(available_nexthops, filtered_nexthops); - } - numberSet_Release(&filtered_nexthops); - } - - if (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_PREFER) { - filtered_nexthops = numberSet_Create(); - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (!connection_HasTag(conn, POLICY_TAG_WIRED)) - continue; - numberSet_Add(filtered_nexthops, conn_id); - } - if (numberSet_Length(filtered_nexthops) > 0) { - numberSet_Release(&available_nexthops); - available_nexthops = numberSet_Create(); - numberSet_AddSet(available_nexthops, filtered_nexthops); - } - numberSet_Release(&filtered_nexthops); - } - if (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_PREFER) { - filtered_nexthops = numberSet_Create(); - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (!connection_HasTag(conn, POLICY_TAG_WIFI)) - continue; - numberSet_Add(filtered_nexthops, conn_id); - } - if (numberSet_Length(filtered_nexthops) > 0) { - numberSet_Release(&available_nexthops); - available_nexthops = numberSet_Create(); - numberSet_AddSet(available_nexthops, filtered_nexthops); - } - numberSet_Release(&filtered_nexthops); - } - if (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_PREFER) { - filtered_nexthops = numberSet_Create(); - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (!connection_HasTag(conn, POLICY_TAG_CELLULAR)) - continue; - numberSet_Add(filtered_nexthops, conn_id); - } - if (numberSet_Length(filtered_nexthops) > 0) { - numberSet_Release(&available_nexthops); - available_nexthops = numberSet_Create(); - numberSet_AddSet(available_nexthops, filtered_nexthops); - } - numberSet_Release(&filtered_nexthops); - } - - /* Priority */ - NumberSet * priority_nexthops = numberSet_Create(); - - uint32_t max_priority = 0; - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - uint32_t priority = connection_GetPriority(conn); - if (priority < max_priority) { - continue; - } else if (priority == max_priority) { - numberSet_Add(priority_nexthops, conn_id); - } else { /* priority > max_priority */ - numberSet_Release(&priority_nexthops); - priority_nexthops = numberSet_Create(); - numberSet_Add(priority_nexthops, conn_id); - max_priority = priority; - } - } - - numberSet_Release(&available_nexthops); - - return priority_nexthops; -} - -hicn_policy_t fibEntry_GetPolicy(const FibEntry *fibEntry) { - return fibEntry->policy; -} - -void fibEntry_SetPolicy(FibEntry *fibEntry, hicn_policy_t policy) { - fibEntry->policy = policy; - mapme_reconsiderFibEntry(forwarder_getMapmeInstance(fibEntry->forwarder), fibEntry); -} - -NumberSet * -fibEntry_GetPreviousNextHops(const FibEntry *fibEntry) -{ - return fibEntry->previous_nexthops; -} -#endif /* WITH_POLICY */ - -void -fibEntry_SetPreviousNextHops(FibEntry *fibEntry, const NumberSet * nexthops) -{ - if (fibEntry->previous_nexthops) - numberSet_Release(&fibEntry->previous_nexthops); - fibEntry->previous_nexthops = numberSet_Create(); - numberSet_AddSet(fibEntry->previous_nexthops, nexthops); -} - - -void fibEntry_AddNexthop(FibEntry *fibEntry, unsigned connectionId) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); -#ifdef WITH_POLICY - if (!numberSet_Contains(fibEntry->nexthops, connectionId)) { - numberSet_Add(fibEntry->nexthops, connectionId); - } -#endif /* WITH_POLICY */ - fibEntry->fwdStrategy->addNexthop(fibEntry->fwdStrategy, connectionId); -} - -void fibEntry_RemoveNexthopByConnectionId(FibEntry *fibEntry, - unsigned connectionId) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); -#ifdef WITH_POLICY - if (numberSet_Contains(fibEntry->nexthops, connectionId)) { - numberSet_Remove(fibEntry->nexthops, connectionId); - } -#endif /* WITH_POLICY */ - fibEntry->fwdStrategy->removeNexthop(fibEntry->fwdStrategy, connectionId); -} - -size_t fibEntry_NexthopCount(const FibEntry *fibEntry) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); -#ifdef WITH_POLICY - return numberSet_Length(fibEntry->nexthops); -#else - return fibEntry->fwdStrategy->countNexthops(fibEntry->fwdStrategy); -#endif /* WITH_POLICY */ -} - -const NumberSet *fibEntry_GetNexthops(const FibEntry *fibEntry) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); -#ifdef WITH_POLICY - return fibEntry->nexthops; -#else - return fibEntry->fwdStrategy->returnNexthops(fibEntry->fwdStrategy); -#endif /* WITH_POLICY */ -} - -const NumberSet *fibEntry_GetNexthopsFromForwardingStrategy( -#ifdef WITH_POLICY - FibEntry *fibEntry, const Message *interestMessage, bool is_retransmission) { -#else - const FibEntry *fibEntry, const Message *interestMessage) { -#endif /* WITH_POLICY */ - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); -#ifdef WITH_POLICY - ConnectionTable * table = forwarder_GetConnectionTable(fibEntry->forwarder); - unsigned in_connection = message_GetIngressConnectionId(interestMessage); - - hicn_policy_t policy = fibEntry_GetPolicy(fibEntry); - - NumberSet * out; - - /* Filtering */ - NumberSet * available_nexthops = fibEntry_GetAvailableNextHops(fibEntry, in_connection); - if (numberSet_Length(available_nexthops) == 0) { - numberSet_Release(&available_nexthops); - out = numberSet_Create(); - return out; - } - - /* - * Update statistics about loss rates. We only detect losses upon - * retransmissions, and assume for the computation that the candidate set of - * output faces is the same as previously (i.e. does not take into account - * event such as face up/down, policy update, etc. Otherwise we would need to - * know what was the previous choice ! - */ - if (is_retransmission) { - for (size_t k = 0; k < numberSet_Length(available_nexthops); k++) { - unsigned conn_id = numberSet_GetItem(available_nexthops, k); - const Connection * conn = connectionTable_FindById(table, conn_id); - - if (connection_HasTag(conn, POLICY_TAG_WIRED)) - fibEntry->policy_counters.wired.num_losses++; - if (connection_HasTag(conn, POLICY_TAG_WIFI)) - fibEntry->policy_counters.wifi.num_losses++; - if (connection_HasTag(conn, POLICY_TAG_CELLULAR)) - fibEntry->policy_counters.cellular.num_losses++; - fibEntry->policy_counters.all.num_losses++; - } - } - - /* - * NOTE: We might want to call a forwarding strategy even with no nexthop to - * take a fallback decision. - */ - if (numberSet_Length(available_nexthops) == 0) { - out = numberSet_Create(); - } else { - /* Multipath */ - if ((policy.tags[POLICY_TAG_MULTIPATH].state != POLICY_STATE_PROHIBIT) && - (policy.tags[POLICY_TAG_MULTIPATH].state != POLICY_STATE_AVOID)) { - out = fibEntry->fwdStrategy->lookupNexthop(fibEntry->fwdStrategy, available_nexthops, - interestMessage); - } else { - unsigned nexthop = numberSet_GetItem(available_nexthops, 0); - out = numberSet_Create(); - numberSet_Add(out, nexthop); - } - } - - numberSet_Release(&available_nexthops); - - return out; -#else - return fibEntry->fwdStrategy->lookupNexthop(fibEntry->fwdStrategy, - interestMessage); -#endif /* WITH_POLICY */ -} - -#ifdef WITH_POLICY -void fibEntry_ReceiveObjectMessage(FibEntry *fibEntry, -#else -void fibEntry_ReceiveObjectMessage(const FibEntry *fibEntry, -#endif /* WITH_POLICY */ - const NumberSet *egressId, - const Message *objectMessage, - Ticks pitEntryCreation, - Ticks objReception) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); - -#ifdef WITH_POLICY - ConnectionTable * table = forwarder_GetConnectionTable(fibEntry->forwarder); - - /* Update statistic counters : */ - - size_t msg_size = message_Length(objectMessage); - Ticks rtt = objReception - pitEntryCreation; - - for (unsigned i = 0; i < numberSet_Length(egressId); i++) { - unsigned conn_id = numberSet_GetItem(egressId, i); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (!conn) - continue; - if (connection_HasTag(conn, POLICY_TAG_WIRED)) { - fibEntry->policy_counters.wired.num_packets++; - fibEntry->policy_counters.wired.num_bytes += (uint32_t)msg_size; - fibEntry->policy.stats.wired.latency = (float) (\ - ALPHA * fibEntry->policy.stats.wired.latency + \ - (1 - ALPHA) * (double)rtt); - fibEntry->policy_counters.wired.latency_idle = 0; - } - if (connection_HasTag(conn, POLICY_TAG_WIFI)) { - fibEntry->policy_counters.wifi.num_packets++; - fibEntry->policy_counters.wifi.num_bytes += (uint32_t)msg_size; - fibEntry->policy.stats.wifi.latency = (float)(\ - ALPHA * fibEntry->policy.stats.wifi.latency + \ - (1 - ALPHA) * (double)rtt); - fibEntry->policy_counters.wifi.latency_idle = 0; - - } - if (connection_HasTag(conn, POLICY_TAG_CELLULAR)) { - fibEntry->policy_counters.cellular.num_packets++; - fibEntry->policy_counters.cellular.num_bytes += (uint32_t)msg_size; - fibEntry->policy.stats.cellular.latency = (float)(\ - ALPHA * fibEntry->policy.stats.cellular.latency + \ - (1 - ALPHA) * (double)rtt); - fibEntry->policy_counters.cellular.latency_idle = 0; - } - } - - fibEntry->policy.stats.all.latency = (float)(\ - ALPHA * fibEntry->policy.stats.all.latency + \ - (1 - ALPHA) * (double)rtt); - fibEntry->policy_counters.all.latency_idle = 0; - - fibEntry->policy_counters.all.num_packets++; - fibEntry->policy_counters.all.num_bytes += (uint32_t)msg_size; - -#endif /* WITH_POLICY */ - - fibEntry->fwdStrategy->receiveObject(fibEntry->fwdStrategy, egressId, - objectMessage, pitEntryCreation, objReception); -} - -#ifdef WITH_POLICY -void fibEntry_OnTimeout(FibEntry *fibEntry, const NumberSet *egressId) { -#else -void fibEntry_OnTimeout(const FibEntry *fibEntry, const NumberSet *egressId) { -#endif /* WITH_POLICY */ - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); - -#ifdef WITH_POLICY - - ConnectionTable * table = forwarder_GetConnectionTable(fibEntry->forwarder); - - for (unsigned i = 0; i < numberSet_Length(egressId); i++) { - unsigned conn_id = numberSet_GetItem(egressId, i); - const Connection * conn = connectionTable_FindById(table, conn_id); - if (!conn) - continue; - if (connection_HasTag(conn, POLICY_TAG_WIRED)) { - fibEntry->policy_counters.wired.num_losses++; - } - if (connection_HasTag(conn, POLICY_TAG_WIFI)) { - fibEntry->policy_counters.wifi.num_losses++; - } - if (connection_HasTag(conn, POLICY_TAG_CELLULAR)) { - fibEntry->policy_counters.cellular.num_losses++; - } - } - - fibEntry->policy_counters.all.num_losses++; - -#endif /* WITH_POLICY */ - - fibEntry->fwdStrategy->onTimeout(fibEntry->fwdStrategy, egressId); -} - -#ifdef WITH_POLICY -void fibEntry_UpdateStats(FibEntry *fibEntry, uint64_t now) { - double throughput; - double loss_rate; - - if (now == fibEntry->policy_counters.last_update) - return ; - - /* WIRED */ - - /* a) throughput */ - if (fibEntry->policy_counters.wired.num_bytes > 0) { - throughput = (float)(fibEntry->policy_counters.wired.num_bytes / \ - (now - fibEntry->policy_counters.last_update)) ; - throughput = throughput * 8 / 1024; - if (throughput < 0) - throughput = 0; - } else { - throughput = 0; - } - fibEntry->policy.stats.wired.throughput = (float)(\ - ALPHA * fibEntry->policy.stats.wired.throughput + \ - (1-ALPHA) * throughput); - - /* b) loss rate */ - if ((fibEntry->policy_counters.wired.num_losses > 0) && \ - (fibEntry->policy_counters.wired.num_packets > 0)){ - loss_rate = fibEntry->policy_counters.wired.num_losses / \ - fibEntry->policy_counters.wired.num_packets; - loss_rate *= 100; - } else { - loss_rate = 0; - } - fibEntry->policy.stats.wired.loss_rate = (float)(\ - ALPHA * fibEntry->policy.stats.wired.loss_rate + \ - (1-ALPHA) * loss_rate); - - /* Latency */ - fibEntry->policy_counters.wired.latency_idle++; - if (fibEntry->policy_counters.wired.latency_idle > 1) - fibEntry->policy.stats.wired.latency = 0; - fibEntry->policy_counters.wifi.latency_idle++; - if (fibEntry->policy_counters.wifi.latency_idle > 1) - fibEntry->policy.stats.wifi.latency = 0; - fibEntry->policy_counters.cellular.latency_idle++; - if (fibEntry->policy_counters.cellular.latency_idle > 1) - fibEntry->policy.stats.cellular.latency = 0; - fibEntry->policy_counters.all.latency_idle++; - if (fibEntry->policy_counters.all.latency_idle > 1) - fibEntry->policy.stats.all.latency = 0; - - fibEntry->policy_counters.wired.num_bytes = 0; - fibEntry->policy_counters.wired.num_losses = 0; - fibEntry->policy_counters.wired.num_packets = 0; - - /* WIFI */ - - /* a) throughput */ - if (fibEntry->policy_counters.wifi.num_bytes > 0) { - throughput = (float)(fibEntry->policy_counters.wifi.num_bytes / \ - (now - fibEntry->policy_counters.last_update)); - throughput = throughput * 8 / 1024; - if (throughput < 0) - throughput = 0; - } else { - throughput = 0; - } - fibEntry->policy.stats.wifi.throughput = (float)( \ - ALPHA * fibEntry->policy.stats.wifi.throughput + \ - (1-ALPHA) * throughput); - - /* b) loss rate */ - if ((fibEntry->policy_counters.wifi.num_losses > 0) && \ - (fibEntry->policy_counters.wifi.num_packets > 0)) { - loss_rate = fibEntry->policy_counters.wifi.num_losses / \ - fibEntry->policy_counters.wifi.num_packets; - loss_rate *= 100; - } else { - loss_rate = 0; - } - fibEntry->policy.stats.wifi.loss_rate = (float)(\ - ALPHA * fibEntry->policy.stats.wifi.loss_rate + \ - (1-ALPHA) * loss_rate); - - fibEntry->policy_counters.wifi.num_bytes = 0; - fibEntry->policy_counters.wifi.num_losses = 0; - fibEntry->policy_counters.wifi.num_packets = 0; - - /* CELLULAR */ - - /* a) throughput */ - if (fibEntry->policy_counters.cellular.num_bytes > 0) { - throughput = (float)(fibEntry->policy_counters.cellular.num_bytes / \ - (now - fibEntry->policy_counters.last_update)) ; - throughput = throughput * 8 / 1024; - if (throughput < 0) - throughput = 0; - } else { - throughput = 0; - } - fibEntry->policy.stats.cellular.throughput = (float)( \ - ALPHA * fibEntry->policy.stats.cellular.throughput + \ - (1-ALPHA) * throughput); - - /* b) loss rate */ - if ((fibEntry->policy_counters.cellular.num_losses > 0) && \ - (fibEntry->policy_counters.cellular.num_packets > 0)) { - loss_rate = fibEntry->policy_counters.cellular.num_losses / \ - fibEntry->policy_counters.cellular.num_packets; - loss_rate *= 100; - } else { - loss_rate = 0; - } - fibEntry->policy.stats.cellular.loss_rate = (float)( \ - ALPHA * fibEntry->policy.stats.cellular.loss_rate + \ - (1-ALPHA) * loss_rate); - - fibEntry->policy_counters.cellular.num_bytes = 0; - fibEntry->policy_counters.cellular.num_losses = 0; - fibEntry->policy_counters.cellular.num_packets = 0; - - /* ALL */ - - /* a) throughput */ - if (fibEntry->policy_counters.all.num_bytes > 0) { - throughput = (float)( fibEntry->policy_counters.all.num_bytes / \ - (now - fibEntry->policy_counters.last_update)); - throughput = throughput * 8 / 1024; - if (throughput < 0) - throughput = 0; - } else { - throughput = 0; - } - fibEntry->policy.stats.all.throughput = (float)(\ - ALPHA * fibEntry->policy.stats.all.throughput + \ - (1-ALPHA) * throughput); - - /* b) loss rate */ - if ((fibEntry->policy_counters.all.num_losses > 0) && \ - (fibEntry->policy_counters.all.num_packets > 0)) { - loss_rate = fibEntry->policy_counters.all.num_losses / \ - fibEntry->policy_counters.all.num_packets; - loss_rate *= 100; - } else { - loss_rate = 0; - } - fibEntry->policy.stats.all.loss_rate = (float)(\ - ALPHA * fibEntry->policy.stats.all.loss_rate + \ - (1-ALPHA) * loss_rate); - - fibEntry->policy_counters.all.num_bytes = 0; - fibEntry->policy_counters.all.num_losses = 0; - fibEntry->policy_counters.all.num_packets = 0; - - fibEntry->policy_counters.last_update = now; -} -#endif /* WITH_POLICY */ - -Name *fibEntry_GetPrefix(const FibEntry *fibEntry) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); - return fibEntry->name; - // return metisName_Acquire(fibEntry->name); -} - -strategy_type fibEntry_GetFwdStrategyType(const FibEntry *fibEntry) { - return fibEntry->fwdStrategy->getStrategy(fibEntry->fwdStrategy); -} - -StrategyImpl *fibEntry_GetFwdStrategy(const FibEntry *fibEntry) { - return fibEntry->fwdStrategy; -} - -#ifdef WITH_MAPME - -void *fibEntry_getUserData(const FibEntry *fibEntry) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); - return fibEntry->userData; -} - -void fibEntry_setUserData(FibEntry *fibEntry, const void *userDataOwner, const - void *userData, void (*userDataRelease)(const void *, void **)) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); - fibEntry->userDataOwner = userDataOwner; - fibEntry->userData = (void *)userData; - fibEntry->userDataRelease = userDataRelease; -} - -#endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/processor/fibEntry.h b/hicn-light/src/hicn/processor/fibEntry.h deleted file mode 100644 index cf267d6a6..000000000 --- a/hicn-light/src/hicn/processor/fibEntry.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file fibEntry.h - * @brief A forwarding entry in the FIB table - * - * A Forwarding Information Base (FIB) entry (FibEntry) is a - * set of nexthops for a name. It also indicates the forwarding strategy. - * - * Each nexthop contains the ConnectionId assocaited with it. This could be - * something specific like a MAC address or point-to-point tunnel. Or, it - * could be something general like a MAC group address or ip multicast overlay. - * - * See strategy.h for a description of forwarding strategies. - * In short, a strategy is the algorithm used to select one or more nexthops - * from the set of available nexthops. - * - * Each nexthop also contains a void* to a forwarding strategy data container. - * This allows a strategy to keep proprietary information about each nexthop. - * - * - */ - -#ifndef fibEntry_h -#define fibEntry_h - -#include <hicn/core/name.h> -#include <hicn/strategies/strategyImpl.h> - -#ifdef WITH_POLICY -#include <hicn/core/connectionTable.h> -#endif /* WITH_POLICY */ - -#ifdef WITH_MAPME -#include <parc/algol/parc_EventTimer.h> -#include <parc/algol/parc_Iterator.h> -#endif /* WITH_MAPME */ - -struct fib_entry; -typedef struct fib_entry FibEntry; - -#ifdef WITH_POLICY -struct forwarder; -FibEntry *fibEntry_Create(Name *name, strategy_type fwdStrategy, const struct forwarder * table); -#else -FibEntry *fibEntry_Create(Name *name, strategy_type fwdStrategy); -#endif - -/** - * Decrements the reference count by one, and destroys the memory after last - * release - * - */ -void fibEntry_Release(FibEntry **fibEntryPtr); - -/** - * Returns a reference counted copy of the fib entry - * - * The reference count is increased by one. The returned value must be - * released via fibEnty_Release(). - * - * @param [in] fibEntry An allocated FibEntry - * - * @return non-null A reference counted copy of the fibEntry - * - */ -FibEntry *fibEntry_Acquire(const FibEntry *fibEntry); - -void fibEntry_SetStrategy(FibEntry *fibEntry, strategy_type strategy, - unsigned related_prefixes_len, - Name **related_prefixes); - -void fibEntry_AddNexthop(FibEntry *fibEntry, unsigned connectionId); - -void fibEntry_RemoveNexthopByConnectionId(FibEntry *fibEntry, - unsigned connectionId); - -size_t fibEntry_NexthopCount(const FibEntry *fibEntry); - -/** - * @function fibEntry_GetNexthops - * @abstract Returns the nexthop set of the FIB entry. You must Acquire if it - * will be saved. - * @discussion - * Returns the next hop set for the FIB entry. - */ -const NumberSet *fibEntry_GetNexthops(const FibEntry *fibEntry); - -#ifdef WITH_POLICY -void fibEntry_ReceiveObjectMessage(FibEntry *fibEntry, -#else -void fibEntry_ReceiveObjectMessage(const FibEntry *fibEntry, -#endif /* WITH_POLICY */ - const NumberSet *egressId, - const Message *objectMessage, - Ticks pitEntryCreation, - Ticks objReception); - -#ifdef WITH_POLICY -hicn_policy_t fibEntry_GetPolicy(const FibEntry *fibEntry); -void fibEntry_ReconsiderPolicy(FibEntry *fibEntry); -void fibEntry_SetPolicy(FibEntry *fibEntry, hicn_policy_t policy); -void fibEntry_UpdateStats(FibEntry *fibEntry, uint64_t now); -NumberSet * fibEntry_GetAvailableNextHops(const FibEntry *fibEntry, unsigned in_connection); -NumberSet * fibEntry_GetPreviousNextHops(const FibEntry *fibEntry); -void fibEntry_SetPreviousNextHops(FibEntry *fibEntry, const NumberSet * nexthops); - -void fibEntry_OnTimeout(FibEntry *fibEntry, const NumberSet *egressId); -const NumberSet *fibEntry_GetNexthopsFromForwardingStrategy( - FibEntry *fibEntry, const Message *interestMessage, bool is_retransmission); - -#else -void fibEntry_OnTimeout(const FibEntry *fibEntry, const NumberSet *egressId); -const NumberSet *fibEntry_GetNexthopsFromForwardingStrategy( - const FibEntry *fibEntry, const Message *interestMessage); -#endif /* WITH_POLICY */ - - -strategy_type fibEntry_GetFwdStrategyType(const FibEntry *fibEntry); - -StrategyImpl *fibEntry_GetFwdStrategy(const FibEntry *fibEntry); - -/** - * @function fibEntry_GetPrefix - * @abstract Returns a copy of the prefix. - * @return A reference counted copy that you must destroy - */ -Name *fibEntry_GetPrefix(const FibEntry *fibEntry); - -#ifdef WITH_MAPME - -/** - * @function fibEntry_getUserData - * @abstract Returns user data associated to the FIB entry. - * @param [in] fibEntry - Pointer to the FIB entry. - * @return User data as a void pointer - */ -void *fibEntry_getUserData(const FibEntry *fibEntry); - -/** - * @function fibEntry_getUserData - * @abstract Associates user data and release callback to a FIB entry. - * @param [in] fibEntry - Pointer to the FIB entry. - * @param [in] userData - Generic pointer to user data - * @param [in@ userDataRelease - Callback used to release user data upon change - * of FIB entry removal. - */ -void fibEntry_setUserData(FibEntry *fibEntry, const void *userDataOwner, - const void *userData, void (*userDataRelease)(const void *, void **)); - -#endif /* WITH_MAPME */ - -#endif // fibEntry_h diff --git a/hicn-light/src/hicn/processor/fibEntryList.c b/hicn-light/src/hicn/processor/fibEntryList.c deleted file mode 100644 index 56d7b8bea..000000000 --- a/hicn-light/src/hicn/processor/fibEntryList.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/processor/fibEntryList.h> - -struct fib_entry_list { - PARCArrayList *listOfFibEntries; -}; - -static void fibEntryList_ListDestroyer(void **voidPtr) { - FibEntry **entryPtr = (FibEntry **)voidPtr; - fibEntry_Release(entryPtr); -} - -FibEntryList *fibEntryList_Create() { - FibEntryList *fibEntryList = - parcMemory_AllocateAndClear(sizeof(FibEntryList)); - parcAssertNotNull(fibEntryList, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(FibEntryList)); - fibEntryList->listOfFibEntries = - parcArrayList_Create(fibEntryList_ListDestroyer); - return fibEntryList; -} - -void fibEntryList_Destroy(FibEntryList **listPtr) { - parcAssertNotNull(listPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listPtr, "Parameter must dereference to non-null pointer"); - - FibEntryList *list = *listPtr; - parcArrayList_Destroy(&list->listOfFibEntries); - parcMemory_Deallocate((void **)&list); - listPtr = NULL; -} - -void fibEntryList_Append(FibEntryList *list, FibEntry *fibEntry) { - parcAssertNotNull(list, "Parameter list must be non-null pointer"); - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null pointer"); - - FibEntry *copy = fibEntry_Acquire(fibEntry); - parcArrayList_Add(list->listOfFibEntries, copy); -} - -size_t fibEntryList_Length(const FibEntryList *list) { - parcAssertNotNull(list, "Parameter list must be non-null pointer"); - return parcArrayList_Size(list->listOfFibEntries); -} - -const FibEntry *fibEntryList_Get(const FibEntryList *list, size_t index) { - parcAssertNotNull(list, "Parameter list must be non-null pointer"); - FibEntry *entry = parcArrayList_Get(list->listOfFibEntries, index); - return entry; -} diff --git a/hicn-light/src/hicn/processor/fibEntryList.h b/hicn-light/src/hicn/processor/fibEntryList.h deleted file mode 100644 index 072a1b369..000000000 --- a/hicn-light/src/hicn/processor/fibEntryList.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file fibEntryList.h - * @brief A typesafe list of FibEntry - * - * <#Detailed Description#> - * - */ - -#ifndef fibEntryList_h -#define fibEntryList_h - -#include <hicn/processor/fibEntry.h> - -struct fib_entry_list; -typedef struct fib_entry_list FibEntryList; - -/** - * Creates an emtpy FIB entry list - * - * Must be destroyed with fibEntryList_Destroy. - * - * @retval non-null An allocated FibEntryList - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -FibEntryList *fibEntryList_Create(void); - -/** - * @function FibEntryList_Detroy - * @abstract Destroys the list and all entries. - * @discussion - * <#Discussion#> - * - * @param <#param1#> - */ -void fibEntryList_Destroy(FibEntryList **listPtr); - -/** - * @function fibEntryList_Append - * @abstract Will store a reference counted copy of the entry. - * @discussion - * Will create and store a reference counted copy. You keep ownership - * of the parameter <code>fibEntry</code>. - * - * @param <#param1#> - * @return <#return#> - */ -void fibEntryList_Append(FibEntryList *list, FibEntry *fibEntry); - -/** - * Returns the number of entries in the list - * - * <#Paragraphs Of Explanation#> - * - * @param [in] list An allocated FibEntryList - * - * @retval number The number of entries in the list - * - * Example: - * @code - * <#example#> - * @endcode - */ -size_t fibEntryList_Length(const FibEntryList *list); - -/** - * @function fibEntryList_Get - * @abstract Gets an element. This is the internal reference, do not destroy. - * @discussion - * Returns an internal reference from the list. You must not destroy it. - * Will assert if you go off the end of the list. - * - * @param <#param1#> - * @return <#return#> - */ -const FibEntry *fibEntryList_Get(const FibEntryList *list, size_t index); -#endif // fibEntryList_h diff --git a/hicn-light/src/hicn/processor/hashTableFunction.c b/hicn-light/src/hicn/processor/hashTableFunction.c deleted file mode 100644 index 98afa1294..000000000 --- a/hicn-light/src/hicn/processor/hashTableFunction.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> - -#include <hicn/core/message.h> -#include <hicn/processor/hashTableFunction.h> - -#include <parc/assert/parc_Assert.h> - -// ====================================================================== -// Hash table key functions -// We use a Message as the key data type - -bool hashTableFunction_MessageNameEquals(const void *messageA, - const void *messageB) { - const Message *a = (const Message *)messageA; - const Message *b = (const Message *)messageB; - - return name_Equals(message_GetName(a), message_GetName(b)); -} - -HashCodeType hashTableFunction_MessageNameHashCode(const void *messageA) { - const Message *message = (const Message *)messageA; - Name *name = message_GetName(message); - - // we want the cumulative hash for the whole name - uint32_t hash = name_HashCode(name); - - return hash; -}
\ No newline at end of file diff --git a/hicn-light/src/hicn/processor/hashTableFunction.h b/hicn-light/src/hicn/processor/hashTableFunction.h deleted file mode 100644 index eb9989086..000000000 --- a/hicn-light/src/hicn/processor/hashTableFunction.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file hashTableFunction.h - * @brief These functions are used in PARCHashCodeTables by the - * MatchingRulesTable and ContentStore and PIT. They perform the equality - * and has generation needed by the PARCHashCodeTable. - * - */ -#ifndef hashTableFunction_h -#define hashTableFunction_h - -#include <parc/algol/parc_HashCodeTable.h> - -// ========================================================== -// These functions operate on a message as the key in the HashTable. -// The functions use void * rather than message instances in the function -// signature because it is using generic has code tables from PARC Library - -/** - * Determine if the Names of two `message` instances are equal. - * - * The following equivalence relations on non-null `message` instances are - * maintained: - * - * * It is reflexive: for any non-null reference value x, - * `hashTableFunction_MessageNameEquals(x, x)` must return true. - * - * * It is symmetric: for any non-null reference values x and y, - * `message_Equals(x, y)` must return true if and only if - * `hashTableFunction_MessageNameEquals(y, x)` returns true. - * - * * It is transitive: for any non-null reference values x, y, and z, if - * `hashTableFunction_MessageNameEquals(x, y)` returns true and - * `hashTableFunction_MessageNameEquals(y, z)` returns true, - * then `hashTableFunction_MessageNameEquals(x, z)` must return true. - * - * * It is consistent: for any non-null reference values x and y, multiple - * invocations of `hashTableFunction_MessageNameEquals(x, y)` consistently - * return true or consistently return false. - * - * * For any non-null reference value x, - * `hashTableFunction_MessageNameEquals(x, NULL)` must return false. - * - * @param a A pointer to a `message` instance. - * @param b A pointer to a `message` instance. - * @return true if the names of the two `message` instances are equal. - */ -bool hashTableFunction_MessageNameEquals(const void *messageA, - const void *messageB); - -/** - * @function hashTableFunction_NameHashCode - * @abstract Computes the hash of the entire name in a message - * - * @param messageA is a message - * @return A non-cryptographic hash of Name - */ -HashCodeType hashTableFunction_MessageNameHashCode(const void *messageA); -#endif // hashTableFunction_h
\ No newline at end of file diff --git a/hicn-light/src/hicn/processor/matchingRulesTable.c b/hicn-light/src/hicn/processor/matchingRulesTable.c deleted file mode 100644 index e57239321..000000000 --- a/hicn-light/src/hicn/processor/matchingRulesTable.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/processor/hashTableFunction.h> -#include <hicn/processor/matchingRulesTable.h> - -struct matching_rules_table { - // using this wrapper we can manatain multiple hash tables indexed in - // different ways - // for now we use only a table indexed by name - - PARCHashCodeTable *tableByName; - PARCHashCodeTable_Destroyer dataDestroyer; -}; - -static PARCHashCodeTable *matchingRulesTable_GetTableForMessage( - const MatchingRulesTable *pit, const Message *interestMessage); - -// ====================================================================== - -MatchingRulesTable *matchingRulesTable_Create( - PARCHashCodeTable_Destroyer dataDestroyer) { - size_t initialSize = 65535; - - MatchingRulesTable *table = - parcMemory_AllocateAndClear(sizeof(MatchingRulesTable)); - parcAssertNotNull(table, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(MatchingRulesTable)); - table->dataDestroyer = dataDestroyer; - - table->tableByName = parcHashCodeTable_Create_Size( - hashTableFunction_MessageNameEquals, - hashTableFunction_MessageNameHashCode, NULL, dataDestroyer, initialSize); - - return table; -} - -void matchingRulesTable_Destroy(MatchingRulesTable **tablePtr) { - parcAssertNotNull(tablePtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*tablePtr, - "Parameter must dereference to non-null pointer"); - - MatchingRulesTable *table = *tablePtr; - - parcHashCodeTable_Destroy(&table->tableByName); - - parcMemory_Deallocate((void **)&table); - *tablePtr = NULL; -} - -void *matchingRulesTable_Get(const MatchingRulesTable *rulesTable, - const Message *message) { - parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - - PARCHashCodeTable *hashTable = - matchingRulesTable_GetTableForMessage(rulesTable, message); - return parcHashCodeTable_Get(hashTable, message); -} - -PARCArrayList *matchingRulesTable_GetUnion(const MatchingRulesTable *table, - const Message *message) { - PARCArrayList *list = parcArrayList_Create_Capacity(NULL, NULL, 3); - - void *dataByName = parcHashCodeTable_Get(table->tableByName, message); - if (dataByName) { - parcArrayList_Add(list, dataByName); - } - - return list; -} - -void matchingRulesTable_RemoveFromBest(MatchingRulesTable *rulesTable, - const Message *message) { - parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - - PARCHashCodeTable *hashTable = - matchingRulesTable_GetTableForMessage(rulesTable, message); - parcHashCodeTable_Del(hashTable, message); -} - -void matchingRulesTable_RemoveFromAll(MatchingRulesTable *rulesTable, - const Message *message) { - parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - - parcHashCodeTable_Del(rulesTable->tableByName, message); -} - -bool matchingRulesTable_AddToBestTable(MatchingRulesTable *rulesTable, - Message *key, void *data) { - parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null"); - parcAssertNotNull(key, "Parameter key must be non-null"); - parcAssertNotNull(data, "Parameter data must be non-null"); - - PARCHashCodeTable *hashTable = - matchingRulesTable_GetTableForMessage(rulesTable, key); - - bool success = parcHashCodeTable_Add(hashTable, key, data); - - return success; -} - -// ======================================================================================== - -static PARCHashCodeTable *matchingRulesTable_GetTableForMessage( - const MatchingRulesTable *pit, const Message *interestMessage) { - PARCHashCodeTable *table; - table = pit->tableByName; - - return table; -} diff --git a/hicn-light/src/hicn/processor/matchingRulesTable.h b/hicn-light/src/hicn/processor/matchingRulesTable.h deleted file mode 100644 index 64a57d854..000000000 --- a/hicn-light/src/hicn/processor/matchingRulesTable.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @header matchingRulesTable - * @abstract A generic table (void *) that matches a Message - * @discussion - * Matching is done based on Name - * - * When used in the PIT, one calls - * <code>matchingRulesTable_AddToBestTable()</code> to add an interest to the - * "best" (i.e. most restrictive match) table, then calls - * <code>matchingRulesTable_GetUnion()</code> on a content object to match - * against all of them. - * - * When used in a ContentStore, one calls - * <code>matchingRulesTable_AddToAllTables()</code> to index a Content Object in - * all the tables. one then calls <code>matchingRulesTable_Get()</code> with an - * Interest to do the "best" matching (i.e by hash first, then keyid, then just - * by name). - * - */ - -#ifndef matchingRulesTable_h -#define matchingRulesTable_h - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_HashCodeTable.h> -#include <hicn/core/message.h> - -struct matching_rules_table; -typedef struct matching_rules_table MatchingRulesTable; - -/** - * Creates a MatchigRulesTable and specifies the function to call to de-allocate - * an entry - * - * The datadestroyer will be called when an entry is removed from a table. It - * may be NULL. - */ -MatchingRulesTable *matchingRulesTable_Create( - PARCHashCodeTable_Destroyer dataDestroyer); - -/** - * Destroys the table and removes all stored elements. - * - */ -void matchingRulesTable_Destroy(MatchingRulesTable **tablePtr); - -/** - * @function matchingRulesTable_Get - * @abstract Returns the data item that best matches the message. - * @discussion - * Indexed by NameAndContentObjectHash, NameAndKeyId, and Name, in that order. - * - * @return NULL if nothing matches, otherwise the stored value - */ -void *matchingRulesTable_Get(const MatchingRulesTable *table, - const Message *message); - -/** - * @function matchingRulesTable_GetUnion - * @abstract Returns matching data items from all index tables. - * @discussion - * The PARCArrayList does not have an item destructor, so destroying it will - * not affect the underlying data. - * - * @return Will not be NULL, but may be empty - */ -PARCArrayList *matchingRulesTable_GetUnion(const MatchingRulesTable *table, - const Message *message); - -/** - * @function matchingRulesTable_Add - * @abstract Adds the data to the best table - * @discussion - * The key must be derived from the data and destroyed when the data is - * destroyed. Only the data destroyer is called. - * - * No duplicates are allowed, will return false if not added. - * - * @return true if unique key and added, false if duplicate and no action taken. - */ -bool matchingRulesTable_AddToBestTable(MatchingRulesTable *rulesTable, - Message *key, void *data); - -/** - * @function matchingRulesTable_Remove - * @abstract Removes the matching entry from the best match table, calling the - * destroyer on the data. - */ -void matchingRulesTable_RemoveFromBest(MatchingRulesTable *rulesTable, - const Message *message); - -/** - * @function matchingRulesTable_RemoveFromAll - * @abstract Removes the message from all tables - */ -void matchingRulesTable_RemoveFromAll(MatchingRulesTable *rulesTable, - const Message *message); -#endif // matchingRulesTable_h diff --git a/hicn-light/src/hicn/processor/messageProcessor.c b/hicn-light/src/hicn/processor/messageProcessor.c deleted file mode 100644 index d3f07cbda..000000000 --- a/hicn-light/src/hicn/processor/messageProcessor.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <string.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Memory.h> -#ifdef WITH_POLICY -#include <parc/algol/parc_EventTimer.h> -#ifdef WITH_MAPME -#include <hicn/core/connection.h> -#endif /* WITH_MAPME */ -#endif /* WITH_POLICY */ -#include <hicn/processor/messageProcessor.h> - -#include <hicn/processor/fib.h> -#include <hicn/processor/pitStandard.h> - -#include <hicn/content_store/contentStoreInterface.h> -#include <hicn/content_store/contentStoreLRU.h> - -#include <hicn/strategies/loadBalancer.h> -#include <hicn/strategies/lowLatency.h> -#include <hicn/strategies/rnd.h> -#include <hicn/strategies/strategyImpl.h> - -#include <hicn/io/streamConnection.h> -#include <hicn/io/udpListener.h> - -#include <parc/assert/parc_Assert.h> - -#include <hicn/utils/commands.h> -#include <hicn/utils/utils.h> - -#include <hicn/utils/address.h> -#include <hicn/core/messageHandler.h> - -#ifdef WITH_POLICY -#define STATS_INTERVAL 1000 /* ms */ -#endif /* WITH_POLICY */ - -/* - * Copyright (c) 2017-2019 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. - */ -typedef struct processor_stats { - uint32_t countReceived; - uint32_t countInterestsReceived; - uint32_t countObjectsReceived; - - uint32_t countInterestsAggregated; - - uint32_t countDropped; - uint32_t countInterestsDropped; - uint32_t countDroppedNoRoute; - uint32_t countDroppedNoReversePath; - - uint32_t countDroppedConnectionNotFound; - uint32_t countObjectsDropped; - - uint32_t countSendFailures; - uint32_t countInterestForwarded; - uint32_t countObjectsForwarded; - uint32_t countInterestsSatisfiedFromStore; - - uint32_t countDroppedNoHopLimit; - uint32_t countDroppedZeroHopLimitFromRemote; - uint32_t countDroppedZeroHopLimitToRemote; -} _ProcessorStats; - -struct message_processor { - Forwarder *forwarder; - Logger *logger; - - PIT *pit; - ContentStoreInterface *contentStore; - FIB *fib; - - bool store_in_cache; - bool serve_from_cache; - - _ProcessorStats stats; - -#ifdef WITH_POLICY - void * timer; -#endif /* WITH_POLICY */ -}; - -static void messageProcessor_Drop(MessageProcessor *processor, - Message *message); -static void messageProcessor_ReceiveInterest(MessageProcessor *processor, - Message *interestMessage); -static void messageProcessor_ReceiveContentObject(MessageProcessor *processor, - Message *objectMessage); -static unsigned messageProcessor_ForwardToNexthops(MessageProcessor *processor, - Message *message, - const NumberSet *nexthops); - -static void messageProcessor_ForwardToInterfaceId(MessageProcessor *processor, - Message *message, - unsigned interfaceId); - -// ============================================================ -// Public API - -#ifdef WITH_POLICY -static void -messageProcessor_Tick(int fd, PARCEventType type, void *user_data) -{ - MessageProcessor *processor = (MessageProcessor*)user_data; - uint64_t now = (uint64_t)forwarder_GetTicks(processor->forwarder); - - /* Loop over FIB entries to compute statistics from counters */ - FibEntryList *fibList = forwarder_GetFibEntries(processor->forwarder); - - for (size_t i = 0; i < fibEntryList_Length(fibList); i++) { - FibEntry *entry = (FibEntry *)fibEntryList_Get(fibList, i); - fibEntry_UpdateStats(entry, now); - } - - fibEntryList_Destroy(&fibList); -} -#endif /* WITH_POLICY */ - -MessageProcessor *messageProcessor_Create(Forwarder *forwarder) { - size_t objectStoreSize = - configuration_GetObjectStoreSize(forwarder_GetConfiguration(forwarder)); - - MessageProcessor *processor = - parcMemory_AllocateAndClear(sizeof(MessageProcessor)); - parcAssertNotNull(processor, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(MessageProcessor)); - memset(processor, 0, sizeof(MessageProcessor)); - - processor->forwarder = forwarder; - processor->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - processor->pit = pitStandard_Create(forwarder); - - processor->fib = fib_Create(forwarder); - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "MessageProcessor %p created", (void *)processor); - } - - ContentStoreConfig contentStoreConfig = { - .objectCapacity = objectStoreSize, - }; - - processor->contentStore = - contentStoreLRU_Create(&contentStoreConfig, processor->logger); - - // the two flags for the cache are set to true by default. If the cache - // is active it always work as expected unless the use modifies this - // values using controller - processor->store_in_cache = true; - processor->serve_from_cache = true; - -#ifdef WITH_POLICY - /* Create statistics timer */ - Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder); - if (!dispatcher) - goto ERR; - processor->timer = dispatcher_CreateTimer(dispatcher, /* repeat */ true, - messageProcessor_Tick, processor); - if (!processor->timer) - goto ERR; - struct timeval timeout = {STATS_INTERVAL / 1000, (STATS_INTERVAL % 1000) * 1000}; - dispatcher_StartTimer(dispatcher, processor->timer, &timeout); -ERR: -#endif /* WITH_POLICY */ - - return processor; -} - -void messageProcessor_SetContentObjectStoreSize( - MessageProcessor *processor, size_t maximumContentStoreSize) { - parcAssertNotNull(processor, "Parameter processor must be non-null"); - contentStoreInterface_Release(&processor->contentStore); - - ContentStoreConfig contentStoreConfig = {.objectCapacity = - maximumContentStoreSize}; - - processor->contentStore = - contentStoreLRU_Create(&contentStoreConfig, processor->logger); -} - -void messageProcessor_ClearCache(MessageProcessor *processor) { - parcAssertNotNull(processor, "Parameter processor must be non-null"); - size_t objectStoreSize = configuration_GetObjectStoreSize( - forwarder_GetConfiguration(processor->forwarder)); - - contentStoreInterface_Release(&processor->contentStore); - - ContentStoreConfig contentStoreConfig = { - .objectCapacity = objectStoreSize, - }; - - processor->contentStore = - contentStoreLRU_Create(&contentStoreConfig, processor->logger); -} - -ContentStoreInterface *messageProcessor_GetContentObjectStore( - const MessageProcessor *processor) { - parcAssertNotNull(processor, "Parameter processor must be non-null"); - return processor->contentStore; -} - -void messageProcessor_Destroy(MessageProcessor **processorPtr) { - parcAssertNotNull(processorPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*processorPtr, "Parameter dereference to non-null pointer"); - - MessageProcessor *processor = *processorPtr; - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "MessageProcessor %p destroyed", (void *)processor); - } - - logger_Release(&processor->logger); - fib_Destroy(&processor->fib); - contentStoreInterface_Release(&processor->contentStore); - pit_Release(&processor->pit); - -#ifdef WITH_POLICY - Dispatcher *dispatcher = forwarder_GetDispatcher(processor->forwarder); - if (!dispatcher) - goto ERR; - dispatcher_StopTimer(dispatcher, processor->timer); - dispatcher_DestroyTimerEvent(dispatcher, (PARCEventTimer**)&processor->timer); -ERR: -#endif /* WITH_POLICY */ - - parcMemory_Deallocate((void **)&processor); - *processorPtr = NULL; -} - -void messageProcessor_Receive(MessageProcessor *processor, Message *message) { - parcAssertNotNull(processor, "Parameter processor must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - - processor->stats.countReceived++; - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - char *nameString = name_ToString(message_GetName(message)); - logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "Message %p ingress %3u length %5u received name %s", - (void *)message, message_GetIngressConnectionId(message), - message_Length(message), nameString); - parcMemory_Deallocate((void **)&nameString); - } - - switch (message_GetType(message)) { - case MessagePacketType_Interest: - messageProcessor_ReceiveInterest(processor, message); - break; - - case MessagePacketType_ContentObject: - messageProcessor_ReceiveContentObject(processor, message); - break; - - default: - messageProcessor_Drop(processor, message); - break; - } - - // if someone wanted to save it, they made a copy - message_Release(&message); -} - -bool messageProcessor_AddOrUpdateRoute(MessageProcessor *processor, - add_route_command *control, - unsigned ifidx) { - Configuration *config = forwarder_GetConfiguration(processor->forwarder); - - char *prefixStr = (char *) utils_PrefixLenToString( - control->addressType, &control->address, &control->len); - strategy_type fwdStrategy = - configuration_GetForwardingStrategy(config, prefixStr); - - Name *prefix = name_CreateFromAddress(control->addressType, control->address, - control->len); - FibEntry *entry = fib_Contains(processor->fib, prefix); - if (entry != NULL) { - fibEntry_AddNexthop(entry, ifidx); - } else { -#ifdef WITH_POLICY - entry = fibEntry_Create(prefix, fwdStrategy, processor->forwarder); -#else - entry = fibEntry_Create(prefix, fwdStrategy); -#endif /* WITH_POLICY */ - fibEntry_AddNexthop(entry, ifidx); - fib_Add(processor->fib, entry); - } - - free(prefixStr); - name_Release(&prefix); - - return true; -} - -bool messageProcessor_RemoveRoute(MessageProcessor *processor, - remove_route_command *control, - unsigned ifidx) { - Name *name = name_CreateFromAddress(control->addressType, control->address, - control->len); - fib_Remove(processor->fib, name, ifidx); - name_Release(&name); - - return true; -} - -#ifdef WITH_POLICY - -bool messageProcessor_AddOrUpdatePolicy(MessageProcessor *processor, - add_policy_command *control) { - Configuration *config = forwarder_GetConfiguration(processor->forwarder); - - const char *prefixStr = utils_PrefixLenToString( - control->addressType, &control->address, &control->len); - - Name *prefix = name_CreateFromAddress(control->addressType, control->address, - control->len); - FibEntry *entry = fib_Contains(processor->fib, prefix); - if (!entry) { - strategy_type fwdStrategy = - configuration_GetForwardingStrategy(config, prefixStr); - entry = fibEntry_Create(prefix, fwdStrategy, processor->forwarder); - fib_Add(processor->fib, entry); - } - fibEntry_SetPolicy(entry, control->policy); - - name_Release(&prefix); - - return true; -} - -bool messageProcessor_RemovePolicy(MessageProcessor *processor, - remove_policy_command *control) { - Name *prefix = name_CreateFromAddress(control->addressType, control->address, - control->len); - FibEntry *entry = fib_Contains(processor->fib, prefix); - name_Release(&prefix); - - if (!entry) - return false; - - fibEntry_SetPolicy(entry, POLICY_NONE); - - return true; -} - -#endif /* WITH_POLICY */ - -void messageProcessor_RemoveConnectionIdFromRoutes(MessageProcessor *processor, - unsigned connectionId) { - fib_RemoveConnectionId(processor->fib, connectionId); -} - -void processor_SetStrategy(MessageProcessor *processor, Name *prefix, - strategy_type strategy, - unsigned related_prefixes_len, - Name **related_prefixes){ - FibEntry *entry = fib_Contains(processor->fib, prefix); - if (entry != NULL) { - fibEntry_SetStrategy(entry, strategy, related_prefixes_len, - related_prefixes); - } -} - -FibEntryList *messageProcessor_GetFibEntries(MessageProcessor *processor) { - parcAssertNotNull(processor, "Parameter processor must be non-null"); - return fib_GetEntries(processor->fib); -} - -// ============================================================ -// Internal API - -/** - * @function messageProcessor_Drop - * @abstract Whenever we "drop" a message, increment countes - * @discussion - * This is a bookkeeping function. It increments the appropriate counters. - * - * The default action for a message is to destroy it in - * <code>messageProcessor_Receive()</code>, so this function does not need to do - * that. - * - */ -static void messageProcessor_Drop(MessageProcessor *processor, - Message *message) { - processor->stats.countDropped++; - - switch (message_GetType(message)) { - case MessagePacketType_Interest: - processor->stats.countInterestsDropped++; - break; - - case MessagePacketType_ContentObject: - processor->stats.countObjectsDropped++; - break; - - default: - break; - } - - // dont destroy message here, its done at end of receive -} - -/** - * @function messageProcessor_AggregateInterestInPit - * @abstract Try to aggregate the interest in the PIT - * @discussion - * Tries to aggregate the interest with another interest. - * - * @return true if interest aggregagted (no more forwarding needed), false if - * need to keep processing it. - */ -#ifdef WITH_POLICY -static PITVerdict messageProcessor_AggregateInterestInPit(MessageProcessor *processor, - Message *interestMessage) { -#else -static bool messageProcessor_AggregateInterestInPit(MessageProcessor *processor, - Message *interestMessage) { -#endif /* WITH_POLICY */ - PITVerdict verdict = pit_ReceiveInterest(processor->pit, interestMessage); - - if (verdict == PITVerdict_Aggregate) { - // PIT has it, we're done - processor->stats.countInterestsAggregated++; - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log( - processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "Message %p aggregated in PIT (aggregated count %u)", - (void *)interestMessage, processor->stats.countInterestsAggregated); - } - - return true; - } - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log( - processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "Message %p not aggregated in PIT (aggregated count %u)", - (void *)interestMessage, processor->stats.countInterestsAggregated); - } - - return false; -} - -static bool _satisfyFromContentStore(MessageProcessor *processor, - Message *interestMessage) { - bool result = false; - - if (message_GetInterestLifetimeTicks(interestMessage) == 0) { - return false; - } - - if (!processor->serve_from_cache) { - return result; - } - - // See if there's a match in the store. - Message *objectMessage = contentStoreInterface_MatchInterest( - processor->contentStore, interestMessage, - forwarder_GetTicks(processor->forwarder)); - - if (objectMessage != NULL) { - // Remove it from the PIT. nexthops is allocated, so need to destroy - NumberSet *nexthops = pit_SatisfyInterest(processor->pit, objectMessage); - parcAssertNotNull( - nexthops, - "Illegal state: got a null nexthops for an interest we just inserted."); - - // send message in reply, then done - processor->stats.countInterestsSatisfiedFromStore++; - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug, __func__, - "Message %p satisfied from content store (satisfied count %u)", - (void *)interestMessage, - processor->stats.countInterestsSatisfiedFromStore); - } - - message_ResetPathLabel(objectMessage); - - messageProcessor_ForwardToNexthops(processor, objectMessage, nexthops); - numberSet_Release(&nexthops); - - result = true; - } - - return result; -} - -/** - * @function messageProcessor_ForwardViaFib - * @abstract Try to forward the interest via the FIB - * @discussion - * This calls <code>messageProcessor_ForwardToNexthops()</code>, so if we find - * any nexthops, the interest will be sent on its way. Depending on the - * IoOperations of each nexthop, it may be a deferred write and bump up the - * <code>interestMessage</code> refernce count, or it may copy the data out. - * - * A TRUE return means we did our best to forward it via the routes. If those - * routes are actually down or have errors, we still return TRUE. A FALSE - * return means there were no routes to try. - * - * @return true if we found a route and tried to forward it, false if no route - */ -#ifdef WITH_POLICY -static bool messageProcessor_ForwardViaFib(MessageProcessor *processor, - Message *interestMessage, PITVerdict verdict) { -#else -static bool messageProcessor_ForwardViaFib(MessageProcessor *processor, - Message *interestMessage) { -#endif /* WITH_POLICY */ - FibEntry *fibEntry = fib_MatchMessage(processor->fib, interestMessage); - if (fibEntry == NULL) { - return false; - } - - if(messageHandler_IsAProbe(message_FixedHeader(interestMessage))){ - bool reply_to_probe = false; - ConnectionTable * ct = forwarder_GetConnectionTable(processor->forwarder); - const NumberSet * nexthops = fibEntry_GetNexthops(fibEntry); - unsigned size = (unsigned) numberSet_Length(nexthops); - - for (unsigned i = 0; i < size; i++) { - unsigned nhop = numberSet_GetItem(nexthops, i); - Connection *conn = - (Connection *)connectionTable_FindById(ct, nhop); - if (!conn) - continue; - bool isLocal = connection_IsLocal(conn); - if(isLocal){ - Connection * replyConn = - (Connection *)connectionTable_FindById(ct, - message_GetIngressConnectionId(interestMessage)); - connection_HandleProbe(replyConn, - (uint8_t *) message_FixedHeader(interestMessage)); - reply_to_probe = true; - break; - } - } - if(reply_to_probe) - return false; - } - - - PitEntry *pitEntry = pit_GetPitEntry(processor->pit, interestMessage); - if (pitEntry == NULL) { - return false; - } - - pitEntry_AddFibEntry(pitEntry, fibEntry); - - NumberSet *nexthops = (NumberSet *)fibEntry_GetNexthopsFromForwardingStrategy( -#ifdef WITH_POLICY - fibEntry, interestMessage, verdict); -#else - fibEntry, interestMessage); -#endif /* WITH_POLICY */ - - // this requires some additional checks. It may happen that some of the output - // faces selected by the forwarding strategy are not usable. So far all the - // forwarding strategy return only valid faces (or an empty list) - for (unsigned i = 0; i < numberSet_Length(nexthops); i++) { - pitEntry_AddEgressId(pitEntry, numberSet_GetItem(nexthops, i)); - } - - // The function GetPitEntry encreases the ref counter in the pit entry - // we need to decrease it - pitEntry_Release(&pitEntry); - - if (messageProcessor_ForwardToNexthops(processor, interestMessage, nexthops) > - 0) { - numberSet_Release(&nexthops); - return true; - } else { - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug, __func__, - "Message %p returned an emtpy next hop set", - (void *)interestMessage); - } - } - - numberSet_Release(&nexthops); - return false; -} - -/** - * @function messageProcessor_ReceiveInterest - * @abstract Receive an interest from the network - * @discussion - * (1) if interest in the PIT, aggregate in PIT - * (2) if interest in the ContentStore, reply - * (3) if in the FIB, forward - * (4) drop - * - */ -static void messageProcessor_ReceiveInterest(MessageProcessor *processor, - Message *interestMessage) { - processor->stats.countInterestsReceived++; - - // (1) Try to aggregate in PIT -#ifdef WITH_POLICY - PITVerdict verdict = messageProcessor_AggregateInterestInPit(processor, interestMessage); - switch(verdict) { - case PITVerdict_Aggregate: - //done - return; - - case PITVerdict_Forward: - case PITVerdict_Retransmit: - break; - } -#else - if (messageProcessor_AggregateInterestInPit(processor, interestMessage)) { - // done - return; - } -#endif /* WITH_POLICY */ - - // At this point, we just created a PIT entry. If we don't forward the - // interest, we need to remove the PIT entry. - - // (2) Try to satisfy from content store - if (_satisfyFromContentStore(processor, interestMessage)) { - // done - // If we found a content object in the CS, - // messageProcess_SatisfyFromContentStore already cleared the PIT state - return; - } - - // (3) Try to forward it -#ifdef WITH_POLICY - if (messageProcessor_ForwardViaFib(processor, interestMessage, verdict)) { -#else - if (messageProcessor_ForwardViaFib(processor, interestMessage)) { -#endif /* WITH_POLICY */ - // done - return; - } - - // Remove the PIT entry? - processor->stats.countDroppedNoRoute++; - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "Message %p did not match FIB, no route (count %u)", - (void *)interestMessage, processor->stats.countDroppedNoRoute); - } - - messageProcessor_Drop(processor, interestMessage); -} - -/** - * @function messageProcessor_ReceiveContentObject - * @abstract Process an in-bound content object - * @discussion - * (1) If it does not match anything in the PIT, drop it - * (2) Add to Content Store - * (3) Reverse path forward via PIT entries - * - * @param <#param1#> - */ -static void messageProcessor_ReceiveContentObject(MessageProcessor *processor, - Message *message) { - processor->stats.countObjectsReceived++; - - NumberSet *ingressSetUnion = pit_SatisfyInterest(processor->pit, message); - - if (numberSet_Length(ingressSetUnion) == 0) { - // (1) If it does not match anything in the PIT, drop it - processor->stats.countDroppedNoReversePath++; - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug, __func__, - "Message %p did not match PIT, no reverse path (count %u)", - (void *)message, processor->stats.countDroppedNoReversePath); - } - - //if the packet is a probe we need to analyze it - if(messageHandler_IsAProbe(message_FixedHeader(message))){ - FibEntry *fibEntry = fib_MatchMessage(processor->fib, message); - if(fibEntry && - fibEntry_GetFwdStrategyType(fibEntry) == SET_STRATEGY_LOW_LATENCY){ - unsigned connid = message_GetIngressConnectionId(message); - NumberSet *outFace = numberSet_Create(); - numberSet_Add(outFace, connid); - fibEntry_ReceiveObjectMessage(fibEntry, outFace, message, 0, - forwarder_GetTicks(processor->forwarder)); - numberSet_Release(&(outFace)); - } - } - - // we store the packets in the content store enven in the case where there - // is no match in the PIT table in this way the applications can push the - // content in the CS of the forwarder. We allow this only for local faces - bool isLocal = connection_IsLocal(connectionTable_FindById( - forwarder_GetConnectionTable(processor->forwarder), - message_GetIngressConnectionId((const Message *)message))); - if (processor->store_in_cache && isLocal) { - uint64_t currentTimeTicks = forwarder_GetTicks(processor->forwarder); - contentStoreInterface_PutContent(processor->contentStore, message, - currentTimeTicks); - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug, __func__, - "Message %p sotred in the CS anyway", (void *)message); - } - } - - messageProcessor_Drop(processor, message); - } else { - // (2) Add to Content Store. Store may remove expired content, if necessary, - // depending on store policy. - if (processor->store_in_cache) { - uint64_t currentTimeTicks = forwarder_GetTicks(processor->forwarder); - contentStoreInterface_PutContent(processor->contentStore, message, - currentTimeTicks); - } - // (3) Reverse path forward via PIT entries - messageProcessor_ForwardToNexthops(processor, message, ingressSetUnion); - - } - - numberSet_Release(&ingressSetUnion); -} - -/** - * @function messageProcessor_ForwardToNexthops - * @abstract Try to forward to each nexthop listed in the NumberSet - * @discussion - * Will not forward to the ingress connection. - * - * @return The number of nexthops tried - */ -static unsigned messageProcessor_ForwardToNexthops(MessageProcessor *processor, - Message *message, - const NumberSet *nexthops) { - unsigned forwardedCopies = 0; - - size_t length = numberSet_Length(nexthops); - - unsigned ingressId = message_GetIngressConnectionId(message); - uint32_t old_path_label = 0; - - if (message_GetType(message) == MessagePacketType_ContentObject) { - old_path_label = message_GetPathLabel(message); - } - - for (size_t i = 0; i < length; i++) { - unsigned egressId = numberSet_GetItem(nexthops, i); - if (egressId != ingressId) { - forwardedCopies++; - messageProcessor_ForwardToInterfaceId(processor, message, egressId); - - if (message_GetType(message) == MessagePacketType_ContentObject) { - // everytime we send out a message we need to restore the original path - // label of the message this is important because we keep a single copy - // of the message (single pointer) and we modify the path label at each - // send. - message_SetPathLabel(message, old_path_label); - } - } - } - return forwardedCopies; -} - -/** - * caller has checked that the hop limit is ok. Try to send out the connection. - */ -static void messageProcessor_SendWithGoodHopLimit(MessageProcessor *processor, - Message *message, - unsigned interfaceId, - const Connection *conn) { - bool success = connection_Send(conn, message); - if (success) { - switch (message_GetType(message)) { - case MessagePacketType_Interest: - processor->stats.countInterestForwarded++; - break; - - case MessagePacketType_ContentObject: - processor->stats.countObjectsForwarded++; - break; - - default: - break; - } - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log( - processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "forward message %p to interface %u (int %u, obj %u)", - (void *)message, interfaceId, processor->stats.countInterestForwarded, - processor->stats.countObjectsForwarded); - } - } else { - processor->stats.countSendFailures++; - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug, __func__, - "forward message %p to interface %u send failure (count %u)", - (void *)message, interfaceId, - processor->stats.countSendFailures); - } - messageProcessor_Drop(processor, message); - } -} - -/* - * If the hoplimit is equal to 0, then we may only forward it to local - * applications. Otherwise, we may forward it off the system. - * - */ -static void messageProcessor_ForwardToInterfaceId(MessageProcessor *processor, - Message *message, - unsigned interfaceId) { - ConnectionTable *connectionTable = - forwarder_GetConnectionTable(processor->forwarder); - const Connection *conn = - connectionTable_FindById(connectionTable, interfaceId); - - if (conn != NULL) { - messageProcessor_SendWithGoodHopLimit(processor, message, interfaceId, - conn); - } else { - processor->stats.countDroppedConnectionNotFound++; - - if (logger_IsLoggable(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(processor->logger, LoggerFacility_Processor, - PARCLogLevel_Debug, __func__, - "forward message %p to interface %u not found (count %u)", - (void *)message, interfaceId, - processor->stats.countDroppedConnectionNotFound); - } - - messageProcessor_Drop(processor, message); - } -} - -void messageProcessor_SetCacheStoreFlag(MessageProcessor *processor, bool val) { - processor->store_in_cache = val; -} - -bool messageProcessor_GetCacheStoreFlag(MessageProcessor *processor) { - return processor->store_in_cache; -} - -void messageProcessor_SetCacheServeFlag(MessageProcessor *processor, bool val) { - processor->serve_from_cache = val; -} - -bool messageProcessor_GetCacheServeFlag(MessageProcessor *processor) { - return processor->serve_from_cache; -} - -#ifdef WITH_MAPME - -FIB *messageProcessor_getFib(MessageProcessor *processor) { - return processor->fib; -} - -#endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/processor/messageProcessor.h b/hicn-light/src/hicn/processor/messageProcessor.h deleted file mode 100644 index 6a863aa38..000000000 --- a/hicn-light/src/hicn/processor/messageProcessor.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file messageProcessor.h - * @brief Executes the set of rules dictated by the PacketType - * - * This is a "run-to-completion" handling of a message based on the PacketType. - * - * The MessageProcessor also owns the PIT and FIB tables. - * - */ - -#ifndef messageProcessor_h -#define messageProcessor_h - -#include <hicn/content_store/contentStoreInterface.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/message.h> - -#include <hicn/utils/commands.h> - -#ifdef WITH_POLICY -#ifdef WITH_MAPME -#include <hicn/core/connection.h> -#endif /* WITH_MAPME */ -#endif /* WITH_POLICY */ - -struct message_processor; -typedef struct message_processor MessageProcessor; - -/** - * Allocates a MessageProcessor along with PIT, FIB and ContentStore tables - * - * The hicn-light pointer is primarily used for logging (forwarder_Log), getting - * the configuration, and accessing the connection table. - * - * @param [in] Pointer to owning hicn-light process - * - * @retval non-null An allocated message processor - * @retval null An error - * - */ -MessageProcessor *messageProcessor_Create(Forwarder *forwarder); - -/** - * Deallocates a message processor an all internal tables - * - * @param [in,out] processorPtr Pointer to message processor to de-allocate, - * will be NULL'd. - */ -void messageProcessor_Destroy(MessageProcessor **processorPtr); - -/** - * @function messageProcessor_Receive - * @abstract Process the message, takes ownership of the memory. - * @discussion - * Will call destroy on the memory when done with it, so if the caller wants - * to keep it, make a reference counted copy. - * - * Receive may modify some fields in the message, such as the HopLimit field. - */ -void messageProcessor_Receive(MessageProcessor *procesor, Message *message); - -/** - * Adds or updates a route in the FIB - * - * If the route already exists, it is replaced - * - * @param [in] procesor An allocated message processor - * @param [in] route The route to update - * - * @retval true added or updated - * @retval false An error - */ -bool messageProcessor_AddOrUpdateRoute(MessageProcessor *processor, - add_route_command *control, - unsigned ifidx); - -/** - * Removes a route from the FIB - * - * Removes a specific nexthop for a route. If there are no nexthops left after - * the removal, the entire route is deleted from the FIB. - * - * @param [in] procesor An allocated message processor - * @param [in] route The route to remove - * - * @retval true Route completely removed - * @retval false There is still a nexthop for the route - */ - -bool messageProcessor_RemoveRoute(MessageProcessor *processor, - remove_route_command *control, - unsigned ifidx); - -#ifdef WITH_POLICY - -/** - * Adds or updates a policy in the FIB - * - * If the policy is already set, it is replaced - * - * @param [in] procesor An allocated message processor - * @param [in] control Control message - * - * @retval true added or updated - * @retval false An error - */ -bool messageProcessor_AddOrUpdatePolicy(MessageProcessor *processor, - add_policy_command *control); - -/** - * Removes a policy from the FIB - * - * Reset the policy in the FIB to the default (empty) policy. - * - * @param [in] procesor An allocated message processor - * @param [in] control Control message - * - * @retval true Policy completely removed - * @retval false There is still a nexthop for the policy - */ -bool messageProcessor_RemovePolicy(MessageProcessor *processor, - remove_policy_command *control); - -#endif /* WITH_POLICY */ - -/** - * Removes a given connection id from all FIB entries - * - * Iterates the FIB and removes the given connection ID from every route. - */ -void messageProcessor_RemoveConnectionIdFromRoutes(MessageProcessor *processor, - unsigned connectionId); - -/** - * Returns a list of all FIB entries - * - * You must destroy the list. - * - * @retval non-null The list of FIB entries - * @retval null An error - */ -FibEntryList *messageProcessor_GetFibEntries(MessageProcessor *processor); - -/** - * Adjusts the ContentStore to the given size. - * - * This will destroy and re-create the content store, so any cached objects will - * be lost. - * - */ -void messageProcessor_SetContentObjectStoreSize(MessageProcessor *processor, - size_t maximumContentStoreSize); - -/** - * Return the interface to the currently instantiated ContentStore, if any. - * - * @param [in] processor the `MessageProcessor` from which to return the - * ContentStoreInterface. - * - */ -ContentStoreInterface *messageProcessor_GetContentObjectStore( - const MessageProcessor *processor); - -void messageProcessor_SetCacheStoreFlag(MessageProcessor *processor, bool val); - -bool messageProcessor_GetCacheStoreFlag(MessageProcessor *processor); - -void messageProcessor_SetCacheServeFlag(MessageProcessor *processor, bool val); - -bool messageProcessor_GetCacheServeFlag(MessageProcessor *processor); - -void messageProcessor_ClearCache(MessageProcessor *processor); - -void processor_SetStrategy(MessageProcessor *processor, Name *prefix, - strategy_type strategy, - unsigned related_prefixes_len, - Name **related_prefixes); - -#ifdef WITH_MAPME - -/** - * @function messageProcessor_getFib - * @abstract Returns the hICN processor's FIB. - * @param [in] forwarder - Pointer to the hICN processor. - * @returns Pointer to the hICN FIB. - */ -FIB *messageProcessor_getFib(MessageProcessor *processor); - -#endif /* WITH_MAPME */ - -#endif // messageProcessor_h diff --git a/hicn-light/src/hicn/processor/pit.c b/hicn-light/src/hicn/processor/pit.c deleted file mode 100644 index 66ad85410..000000000 --- a/hicn-light/src/hicn/processor/pit.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * Generic interface to PIT table - * - */ - -#include <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/processor/pit.h> - -void *pit_Closure(const PIT *pit) { return pit->closure; } - -void pit_Release(PIT **pitPtr) { (*pitPtr)->release(pitPtr); } - -PITVerdict pit_ReceiveInterest(PIT *pit, Message *interestMessage) { - return pit->receiveInterest(pit, interestMessage); -} - -NumberSet *pit_SatisfyInterest(PIT *pit, const Message *objectMessage) { - return pit->satisfyInterest(pit, objectMessage); -} - -void pit_RemoveInterest(PIT *pit, const Message *interestMessage) { - pit->removeInterest(pit, interestMessage); -} - -PitEntry *pit_GetPitEntry(const PIT *pit, const Message *interestMessage) { - return pit->getPitEntry(pit, interestMessage); -} diff --git a/hicn-light/src/hicn/processor/pit.h b/hicn-light/src/hicn/processor/pit.h deleted file mode 100644 index 63a9b20e4..000000000 --- a/hicn-light/src/hicn/processor/pit.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file pit.h - * @brief The Pending Interest Table interface - * - * Interface for implementing a PIT table - * - */ - -#ifndef pit_h -#define pit_h - -#include <hicn/core/forwarder.h> -#include <hicn/core/message.h> -#include <hicn/core/numberSet.h> -#include <hicn/processor/pitEntry.h> -#include <hicn/processor/pitVerdict.h> - -struct pit; -typedef struct pit PIT; - -struct pit { - void (*release)(PIT **pitPtr); - PITVerdict (*receiveInterest)(PIT *pit, Message *interestMessage); - NumberSet *(*satisfyInterest)(PIT *pit, const Message *objectMessage); - void (*removeInterest)(PIT *pit, const Message *interestMessage); - PitEntry *(*getPitEntry)(const PIT *pit, const Message *interestMessage); - void *closure; -}; - -void *pit_Closure(const PIT *pit); - -/** - * Destroys the PIT table and all entries contained in it. - * - * PIT entries are reference counted, so if the user has stored one outside the - * PIT table it will still be valid. - * - * @param [in,out] pitPtr Double pointer to PIT table, will be NULLed - */ -void pit_Release(PIT **pitPtr); - -/** - * @function pit_ReceiveInterest - * @abstract Receives an interest and adds to PIT table - * @discussion - * If not present, adds entry to the PIT table and returns - * PIT_VERDICT_NEW_ENTRY. If present and aggregated, returns - * PIT_VERDICT_EXISTING_ENTRY. - * - * Some aggregated interests may return PIT_VERDICT_NEW_ENTRY if the interest - * needs to be forwarded again (e.g. the lifetime is extended). - * - * If the PIT stores the message in its table, it will store a reference - * counted copy. - * - * @return Verdict of receiving the interest - */ -PITVerdict pit_ReceiveInterest(PIT *pit, Message *interestMessage); - -/** - * @function pit_SatisfyInterest - * @abstract Tries to satisfy PIT entries based on the message, returning where - * to send message - * @discussion - * If matching interests are in the PIT, will return the set of reverse - * paths to use to forward the content object. - * - * The return value is allocated and must be destroyed. - * - * @return Set of ConnectionTable id's to forward the message, may be empty or - * NULL. Must be destroyed. - */ -NumberSet *pit_SatisfyInterest(PIT *pit, const Message *objectMessage); - -/** - * @function pit_RemoveInterest - * @abstract Unconditionally remove the interest from the PIT - * @discussion - * The PIT may store a specific name in several tables. This function will - * remove the interest from the specific table it lives it. It will not - * remove PIT entries in different tables with the same name. - * - * The different tables index interests based on their matching criteria, - * such as by name, by name and keyid, etc. - * - */ -void pit_RemoveInterest(PIT *pit, const Message *interestMessage); - -/** - * @function pit_GetPitEntry - * @abstract Retrieve the best matching PIT entry for the message. - * @discussion - * Returns a reference counted copy of the entry, must call - * <code>pitEntry_Destory()</code> on it. - * - * @return NULL if not in table, otherwise a reference counted copy of the entry - */ -PitEntry *pit_GetPitEntry(const PIT *pit, const Message *interestMessage); -#endif // pit_h diff --git a/hicn-light/src/hicn/processor/pitEntry.c b/hicn-light/src/hicn/processor/pitEntry.c deleted file mode 100644 index 99b3f1f2b..000000000 --- a/hicn-light/src/hicn/processor/pitEntry.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_Memory.h> -#include <hicn/core/numberSet.h> -#include <hicn/processor/pitEntry.h> - -#include <parc/assert/parc_Assert.h> - -struct pit_entry { - Message *message; - NumberSet *ingressIdSet; - NumberSet *egressIdSet; - - FibEntry *fibEntry; - - Ticks creationTime; - Ticks expiryTime; - - unsigned refcount; -}; - -PitEntry *pitEntry_Create(Message *message, Ticks expiryTime, - Ticks creationTime) { - PitEntry *pitEntry = parcMemory_AllocateAndClear(sizeof(PitEntry)); - parcAssertNotNull(pitEntry, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(PitEntry)); - pitEntry->message = message; - pitEntry->ingressIdSet = numberSet_Create(); - pitEntry->egressIdSet = numberSet_Create(); - pitEntry->refcount = 1; - - // add the message to the reverse path set - numberSet_Add(pitEntry->ingressIdSet, - message_GetIngressConnectionId(message)); - - // hack in a 4-second timeout - pitEntry->expiryTime = expiryTime; - pitEntry->fibEntry = NULL; - - pitEntry->creationTime = creationTime; - return pitEntry; -} - -void pitEntry_Release(PitEntry **pitEntryPtr) { - parcAssertNotNull(pitEntryPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*pitEntryPtr, - "Parameter must dereference to non-null pointer"); - - PitEntry *pitEntry = *pitEntryPtr; - parcTrapIllegalValueIf(pitEntry->refcount == 0, - "Illegal state: has refcount of 0"); - - pitEntry->refcount--; - if (pitEntry->refcount == 0) { - if (pitEntry->fibEntry != NULL) { - fibEntry_Release(&pitEntry->fibEntry); - } - numberSet_Release(&pitEntry->ingressIdSet); - numberSet_Release(&pitEntry->egressIdSet); - message_Release(&pitEntry->message); - parcMemory_Deallocate((void **)&pitEntry); - } - *pitEntryPtr = NULL; -} - -PitEntry *pitEntry_Acquire(PitEntry *original) { - parcAssertNotNull(original, "Parameter original must be non-null"); - original->refcount++; - return original; -} - -void pitEntry_AddIngressId(PitEntry *pitEntry, unsigned ingressId) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - numberSet_Add(pitEntry->ingressIdSet, ingressId); -} - -void pitEntry_AddEgressId(PitEntry *pitEntry, unsigned egressId) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - numberSet_Add(pitEntry->egressIdSet, egressId); -} - -void pitEntry_AddFibEntry(PitEntry *pitEntry, FibEntry *fibEntry) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); - // the fibEntry should be always the same for all the interests in the same - // pitEntry - if (pitEntry->fibEntry == NULL) { - fibEntry_Acquire(fibEntry); - pitEntry->fibEntry = fibEntry; - } -} - -FibEntry *pitEntry_GetFibEntry(PitEntry *pitEntry) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - return pitEntry->fibEntry; -} - -Ticks pitEntry_GetExpiryTime(const PitEntry *pitEntry) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - return pitEntry->expiryTime; -} - -Ticks pitEntry_GetCreationTime(const PitEntry *pitEntry) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - return pitEntry->creationTime; -} - -void pitEntry_SetExpiryTime(PitEntry *pitEntry, Ticks expiryTime) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - pitEntry->expiryTime = expiryTime; -} - -const NumberSet *pitEntry_GetIngressSet(const PitEntry *pitEntry) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - return pitEntry->ingressIdSet; -} - -const NumberSet *pitEntry_GetEgressSet(const PitEntry *pitEntry) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - return pitEntry->egressIdSet; -} - -Message *pitEntry_GetMessage(const PitEntry *pitEntry) { - parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null"); - return message_Acquire(pitEntry->message); -} diff --git a/hicn-light/src/hicn/processor/pitEntry.h b/hicn-light/src/hicn/processor/pitEntry.h deleted file mode 100644 index 3cd5821bc..000000000 --- a/hicn-light/src/hicn/processor/pitEntry.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file pitEntry.h - * @brief The embodiment of a PIT entry - * - * Embodies a PIT entry - * - */ - -#ifndef pitEntry_h -#define pitEntry_h - -#include <hicn/core/message.h> -#include <hicn/core/numberSet.h> -#include <hicn/core/ticks.h> -#include <hicn/processor/fibEntry.h> - -struct pit_entry; -typedef struct pit_entry PitEntry; - -/** - * @function pitEntry_Create - * @abstract Takes ownership of the message inside the PitEntry - * @discussion - * When the PIT entry is destroyed, will call <code>message_Release()</code> - * on the message. - * - */ -PitEntry *pitEntry_Create(Message *message, Ticks expiryTime, - Ticks CreationTime); - -/** - * Release a previously acquired reference to the specified instance, - * decrementing the reference count for the instance. - * - * The pointer to the instance is set to NULL as a side-effect of this function. - * - * If the invocation causes the last reference to the instance to be released, - * the instance is deallocated and the instance's implementation will perform - * additional cleanup and release other privately held references. - * - * @param [in,out] pitEntryPtr A pointer to a PitEntry instance pointer, which - * will be set to zero on return. - * - */ -void pitEntry_Release(PitEntry **pitEntryPtr); - -/** - * @function pitEntry_Acquire - * @abstract Returns a reference counted copy - * @discussion - * A reference counted copy that shares the same state as the original. - * Caller must use <code>pitEntry_Release()</code> on it when done. - * - * @return A reference counted copy, use Destroy on it. - */ -PitEntry *pitEntry_Acquire(PitEntry *original); - -/** - * @function pitEntry_AddIngressId - * @abstract Add an ingress connection id to the list of reverse paths - * @discussion - * A PitEntry has two NumberSets. The first is the set of ingress ports, - * which make up the reverse path. The second is the set of egress ports, which - * make up its forward path. - * - * This function tracks which reverse paths have sent us the interest. - * - * @param ingressId the reverse path - */ -void pitEntry_AddIngressId(PitEntry *pitEntry, unsigned ingressId); - -/** - * @function pitEntry_AddEgressId - * @abstract Add an egress connection id to the list of attempted paths - * @discussion - * A PitEntry has two NumberSets. The first is the set of ingress ports, - * which make up the reverse path. The second is the set of egress ports, which - * make up its forward path. - * - * This function tracks which forward paths we've tried for the interest. - * - * @param egressId the forwarded path - */ -void pitEntry_AddEgressId(PitEntry *pitEntry, unsigned egressId); - -void pitEntry_AddFibEntry(PitEntry *pitEntry, FibEntry *fibEntry); - -FibEntry *pitEntry_GetFibEntry(PitEntry *pitEntry); - -/** - * @function pitEntry_GetIngressSet - * @abstract The Ingress connection id set - * @discussion - * You must acquire a copy of the number set if you will store the result. - * This is the internal reference. - * - * @return May be empty, will not be null. Must be destroyed. - */ -const NumberSet *pitEntry_GetIngressSet(const PitEntry *pitEntry); - -/** - * @function pitEntry_GetEgressSet - * @abstract The Egress connection id set - * @discussion - * You must acquire a copy of the number set if you will store the result. - * This is the internal reference. - * - * @param <#param1#> - * @return May be empty, will not be null. Must be destroyed. - */ -const NumberSet *pitEntry_GetEgressSet(const PitEntry *pitEntry); - -/** - * @function pitEntry_GetMessage - * @abstract Gets the interest underpinning the PIT entry - * @discussion - * A reference counted copy, call <code>Message_Release()</code> on it. - * - * @return A reference counted copy, call <code>Message_Release()</code> on it. - */ -Message *pitEntry_GetMessage(const PitEntry *pitEntry); - -/** - * Returns the time (in ticks) at which the PIT entry is no longer valid - * - * The ExpiryTime is computed when the PIT entry is added (or via - * pitEntry_SetExpiryTime). It is the aboslute time (in Ticks) at which the Pit - * entry is no longer valid. - * - * @param [in] PitEntry An allocated PIT entry - * - * @retval number The abosolute time (in Ticks) of the Expiry - */ -Ticks pitEntry_GetExpiryTime(const PitEntry *pitEntry); - -Ticks pitEntry_GetCreationTime(const PitEntry *pitEntry); -/** - * Sets the ExpriyTime of the PIT entry to the given value - * - * It is probalby an error to set the expiryTime to a smaller value than - * currently set to, but this is not enforced. PIT entries use lazy delete. - * - * @param [in] pitEntry The allocated PIT entry to modify - * @param [in] expiryTime The new expiryTime (UTC in forwarder Ticks) - * - */ -void pitEntry_SetExpiryTime(PitEntry *pitEntry, Ticks expiryTime); - -#endif // pitEntry_h diff --git a/hicn-light/src/hicn/processor/pitStandard.c b/hicn-light/src/hicn/processor/pitStandard.c deleted file mode 100644 index 04d886261..000000000 --- a/hicn-light/src/hicn/processor/pitStandard.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * The pending interest table. - * - * Interest aggregation strategy: - * - The first Interest for a name is forwarded - * - A second Interest for a name from a different reverse path may be - * aggregated - * - A second Interest for a name from an existing Interest is forwarded - * - The Interest Lifetime is like a subscription time. A reverse path entry is - * removed once the lifetime is exceeded. - * - Whan an Interest arrives or is aggregated, the Lifetime for that reverse - * hop is extended. As a simplification, we only keep a single lifetime not per - * reverse hop. - * - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#define __STDC_FORMAT_MACROS -#include <inttypes.h> - -#include <hicn/processor/hashTableFunction.h> -#include <hicn/processor/pit.h> - -#include <hicn/core/ticks.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_HashCodeTable.h> -#include <parc/algol/parc_Memory.h> - -#include <hicn/core/forwarder.h> - -#include <parc/assert/parc_Assert.h> - -struct standard_pit; -typedef struct standard_pit StandardPIT; - -struct standard_pit { - Forwarder *forwarder; - Logger *logger; - PARCHashCodeTable *table; // PIT indexed by name -}; - -static void _pit_StoreInTable(StandardPIT *pit, Message *interestMessage); - -static void _pit_PitEntryDestroyer(void **dataPtr) { - pitEntry_Release((PitEntry **)dataPtr); -} - -static bool _pit_IngressSetContains(PitEntry *pitEntry, unsigned connectionId) { - const NumberSet *set = pitEntry_GetIngressSet(pitEntry); - bool numberInSet = numberSet_Contains(set, connectionId); - return numberInSet; -} - -static Ticks _pit_CalculateLifetime(StandardPIT *pit, - Message *interestMessage) { - uint64_t interestLifetimeTicks = - message_GetInterestLifetimeTicks(interestMessage); - if (interestLifetimeTicks == 0) { - interestLifetimeTicks = forwarder_NanosToTicks(4000000000ULL); - } - - Ticks expiryTime = forwarder_GetTicks(pit->forwarder) + interestLifetimeTicks; - return expiryTime; -} - -static void _pit_StoreInTable(StandardPIT *pit, Message *interestMessage) { - Message *key = message_Acquire(interestMessage); - - Ticks expiryTime = _pit_CalculateLifetime(pit, interestMessage); - - PitEntry *pitEntry = - pitEntry_Create(key, expiryTime, forwarder_GetTicks(pit->forwarder)); - - parcHashCodeTable_Add(pit->table, key, pitEntry); - - if (logger_IsLoggable(pit->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, - "Message %p added to PIT (expiry %" PRIu64 ") ingress %u", - (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry), - message_GetIngressConnectionId(interestMessage)); - } -} - -static void _pit_ExtendLifetime(StandardPIT *pit, PitEntry *pitEntry, - Message *interestMessage) { - Ticks expiryTime = _pit_CalculateLifetime(pit, interestMessage); - - if (expiryTime > pitEntry_GetExpiryTime(pitEntry)) - pitEntry_SetExpiryTime(pitEntry, expiryTime); -} - -// ====================================================================== -// Interface API - -static void _pitStandard_Destroy(PIT **pitPtr) { - parcAssertNotNull(pitPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*pitPtr, "Parameter must dereference to non-null pointer"); - - StandardPIT *pit = pit_Closure(*pitPtr); - - if (logger_IsLoggable(pit->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "PIT %p destroyed", (void *)pit); - } - - parcHashCodeTable_Destroy(&pit->table); - logger_Release(&pit->logger); - parcMemory_Deallocate(pitPtr); -} - -static PITVerdict _pitStandard_ReceiveInterest(PIT *generic, - Message *interestMessage) { - parcAssertNotNull(generic, "Parameter pit must be non-null"); - parcAssertNotNull(interestMessage, - "Parameter interestMessage must be non-null"); - - StandardPIT *pit = pit_Closure(generic); - - PitEntry *pitEntry = parcHashCodeTable_Get(pit->table, interestMessage); - - if (pitEntry) { - // has it expired? - Ticks now = forwarder_GetTicks(pit->forwarder); - if (now < pitEntry_GetExpiryTime(pitEntry)) { - _pit_ExtendLifetime(pit, pitEntry, interestMessage); - - // Is the reverse path already in the PIT entry? - if (_pit_IngressSetContains( - pitEntry, message_GetIngressConnectionId(interestMessage))) { - // It is already in the PIT entry, so this is a retransmission, so - // forward it. - - if (logger_IsLoggable(pit->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, - "Message %p existing entry (expiry %" PRIu64 - ") and reverse path, forwarding", - (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry)); - } -#ifdef WITH_POLICY - return PITVerdict_Retransmit; -#else - return PITVerdict_Forward; -#endif /* WITH_POLICY */ - } - - // It is in the PIT but this is the first interest for the reverse path - pitEntry_AddIngressId(pitEntry, - message_GetIngressConnectionId(interestMessage)); - - if (logger_IsLoggable(pit->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, - "Message %p existing entry (expiry %" PRIu64 - ") and reverse path is new, aggregate", - (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry)); - } - - return PITVerdict_Aggregate; - } - // this is a timeout.... - FibEntry *fibEntry = pitEntry_GetFibEntry(pitEntry); - if (fibEntry != NULL) { - fibEntry_OnTimeout(fibEntry, pitEntry_GetEgressSet(pitEntry)); - } - - // it's an old entry, remove it - parcHashCodeTable_Del(pit->table, interestMessage); - } - - _pit_StoreInTable(pit, interestMessage); - - return PITVerdict_Forward; -} - -static NumberSet *_pitStandard_SatisfyInterest(PIT *generic, - const Message *objectMessage) { - parcAssertNotNull(generic, "Parameter pit must be non-null"); - parcAssertNotNull(objectMessage, "Parameter objectMessage must be non-null"); - - StandardPIT *pit = pit_Closure(generic); - - NumberSet *ingressSet = numberSet_Create(); - - PitEntry *pitEntry = parcHashCodeTable_Get(pit->table, objectMessage); - if (pitEntry) { - // here we need to check if the PIT entry is expired - // if so, remove the PIT entry. - Ticks now = forwarder_GetTicks(pit->forwarder); - if (now < pitEntry_GetExpiryTime(pitEntry)) { - // PIT entry is not expired, use it - FibEntry *fibEntry = pitEntry_GetFibEntry(pitEntry); - if (fibEntry != NULL) { - fibEntry_ReceiveObjectMessage(fibEntry, pitEntry_GetEgressSet(pitEntry), - objectMessage, - pitEntry_GetCreationTime(pitEntry), - forwarder_GetTicks(pit->forwarder)); - } - const NumberSet *is = pitEntry_GetIngressSet(pitEntry); - numberSet_AddSet(ingressSet, is); // with this we do a copy so we can - // remove the entry from the PIT - } - // remove the entry from the PIT. Key is a reference counted copy of the - // pit entry message - Message *key = pitEntry_GetMessage(pitEntry); - parcHashCodeTable_Del(pit->table, key); - message_Release(&key); - } - - return ingressSet; -} - -static void _pitStandard_RemoveInterest(PIT *generic, - const Message *interestMessage) { - parcAssertNotNull(generic, "Parameter pit must be non-null"); - parcAssertNotNull(interestMessage, - "Parameter interestMessage must be non-null"); - - StandardPIT *pit = pit_Closure(generic); - - if (logger_IsLoggable(pit->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "Message %p removed from PIT", - (void *)interestMessage); - } - - parcHashCodeTable_Del(pit->table, interestMessage); -} - -static PitEntry *_pitStandard_GetPitEntry(const PIT *generic, - const Message *interestMessage) { - parcAssertNotNull(generic, "Parameter pit must be non-null"); - parcAssertNotNull(interestMessage, - "Parameter interestMessage must be non-null"); - - StandardPIT *pit = pit_Closure(generic); - - PitEntry *entry = parcHashCodeTable_Get(pit->table, interestMessage); - if (entry) { - return pitEntry_Acquire(entry); - } - return NULL; -} - -// ====================================================================== -// Public API - -PIT *pitStandard_Create(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - - size_t allocation = sizeof(PIT) + sizeof(StandardPIT); - - PIT *generic = parcMemory_AllocateAndClear(allocation); - parcAssertNotNull(generic, "parcMemory_AllocateAndClear(%zu) returned NULL", - allocation); - generic->closure = (uint8_t *)generic + sizeof(PIT); - - StandardPIT *pit = pit_Closure(generic); - pit->forwarder = forwarder; - pit->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - size_t initialSize = 65535; - pit->table = - parcHashCodeTable_Create_Size(hashTableFunction_MessageNameEquals, - hashTableFunction_MessageNameHashCode, NULL, - _pit_PitEntryDestroyer, initialSize); - - if (logger_IsLoggable(pit->logger, LoggerFacility_Processor, - PARCLogLevel_Debug)) { - logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug, - __func__, "PIT %p created", (void *)pit); - } - - generic->getPitEntry = _pitStandard_GetPitEntry; - generic->receiveInterest = _pitStandard_ReceiveInterest; - generic->release = _pitStandard_Destroy; - generic->removeInterest = _pitStandard_RemoveInterest; - generic->satisfyInterest = _pitStandard_SatisfyInterest; - - return generic; -} diff --git a/hicn-light/src/hicn/processor/pitStandard.h b/hicn-light/src/hicn/processor/pitStandard.h deleted file mode 100644 index 9d7ce6a23..000000000 --- a/hicn-light/src/hicn/processor/pitStandard.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file pitStandard.h - * @brief The Pending Interest Table - * - * Implements the standard Pending Interest Table. - * - */ - -#ifndef pitStandard_h -#define pitStandard_h - -#include <hicn/processor/pit.h> - -/** - * Creates a PIT table - * - * Creates and allocates an emtpy PIT table. The Forwarder reference is - * used for logging and for time functions. - * - * @param [in] hicn-light The releated Forwarder - * - * @return non-null a PIT table - * @return null An error - */ -PIT *pitStandard_Create(Forwarder *forwarder); -#endif // pit_h diff --git a/hicn-light/src/hicn/processor/pitVerdict.h b/hicn-light/src/hicn/processor/pitVerdict.h deleted file mode 100644 index f37242027..000000000 --- a/hicn-light/src/hicn/processor/pitVerdict.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file pitVerdict.h - * @brief Adding an entry to the PIT will return NEW or EXISTING - * - * Adding an entry to the PIT will return NEW or EXISTING - * - */ - -#ifndef pitVerdict_h -#define pitVerdict_h - -/** - * @typedef PitVerdict - * @abstract The verdit of the PIT for receiving a message - * @constant PITVerdict_Forward The message made a new PIT entry, the interest - * should be forwarded - * @constant PITVerdict_Aggregate The Interest was aggregated in the PIT, does - * not need to be forwarded - */ -#ifdef WITH_POLICY -typedef enum { PITVerdict_Forward, PITVerdict_Aggregate, PITVerdict_Retransmit } PITVerdict; -#else -typedef enum { PITVerdict_Forward, PITVerdict_Aggregate } PITVerdict; -#endif /* WITH_POLICY */ -#endif // pitVerdict_h diff --git a/hicn-light/src/hicn/socket/CMakeLists.txt b/hicn-light/src/hicn/socket/CMakeLists.txt index 8c8a757fb..41dbd2342 100644 --- a/hicn-light/src/hicn/socket/CMakeLists.txt +++ b/hicn-light/src/hicn/socket/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -25,11 +25,5 @@ if (UNIX AND NOT APPLE) ) endif() -set(TO_INSTALL_HEADER_FILES - ${TO_INSTALL_HEADER_FILES} - ${HEADER_FILES} - PARENT_SCOPE -) - set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/socket/api.c b/hicn-light/src/hicn/socket/api.c index 34c0aae54..e39ebf4b5 100644 --- a/hicn-light/src/hicn/socket/api.c +++ b/hicn-light/src/hicn/socket/api.c @@ -10,8 +10,12 @@ #include <unistd.h> // close #include "api.h" -#include "error.h" #include "ops.h" +#include <hicn/util/sstrncpy.h> + +#if __linux__ +#include "error.h" +#endif #define INET_MAX_ADDRSTRLEN INET6_ADDRSTRLEN @@ -72,8 +76,7 @@ hicn_socket_helper_t *hicn_create() { } hicn->conf = malloc(sizeof(hicn_conf_t)); - if (hicn->conf < 0) - goto ERR_CONF; + if (hicn->conf < 0) goto ERR_CONF; memcpy(hicn->conf, &hicn_default_conf, sizeof(hicn_conf_t)); /* Initialize socket tree to empty */ @@ -133,20 +136,16 @@ void hicn_destroy() { /* Restore default rules */ printf("Restoring default configuration.\n"); rc = ops.del_lo_prio_rule(NULL, AF_INET6, LOCAL_PRIORITY); - if (rc < 0) - ret = -1; + if (rc < 0) ret = -1; rc = ops.del_lo_prio_rule(NULL, AF_INET, LOCAL_PRIORITY); - if (rc < 0) - ret = -1; + if (rc < 0) ret = -1; rc = ops.add_lo_prio_rule(NULL, AF_INET6, 0); - if (rc < 0) - ret = -1; + if (rc < 0) ret = -1; rc = ops.add_lo_prio_rule(NULL, AF_INET, 0); - if (rc < 0) - ret = -1; + if (rc < 0) ret = -1; for (i = 0; i < rules_counter; i++) { if (strcmp(rules_to_remove[i].tun_name, "NONE") != 0) { @@ -158,20 +157,17 @@ void hicn_destroy() { &rules_to_remove[i].prefix, rules_to_remove[i].address_family, rules_to_remove[i].priority, rules_to_remove[i].table_id); } - if (rc < 0) - ret = -1; + if (rc < 0) ret = -1; } for (i = 0; i < routes_counter; i++) { rc = ops.del_out_route(routes_to_remove[i].remote_ip_address, routes_to_remove[i].address_family, routes_to_remove[i].table_id); - if (rc < 0) - ret = -1; + if (rc < 0) ret = -1; } - if (ret < 0) - printf("Unexpected exit. Some state may not be deleted.\n"); + if (ret < 0) printf("Unexpected exit. Some state may not be deleted.\n"); } void hicn_free(hicn_socket_helper_t *hicn) { @@ -259,10 +255,10 @@ int hicn_get_local_address(const ip_prefix_t *remote_address, ip_prefix_t *local_address) { int rc = 0; uint32_t interface_id; - char remote_address_str[INET_MAX_ADDRSTRLEN + 4 ]; + char remote_address_str[INET_MAX_ADDRSTRLEN + 4]; rc = ip_prefix_ntop_short(remote_address, remote_address_str, - sizeof(remote_address_str)); + sizeof(remote_address_str)); if (rc < 0) { rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR; goto ERR; @@ -331,7 +327,8 @@ int hicn_set_remote_endpoint(hicn_socket_t *socket, ///// /* Convert to representation format */ - rc = ip_prefix_ntop_short(&addr, local_ip_address, sizeof(local_ip_address)); + rc = + ip_prefix_ntop_short(&addr, local_ip_address, sizeof(local_ip_address)); if (rc < 0) { rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR; goto ERR; @@ -466,7 +463,9 @@ int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix) { return rc; } - strcpy(rules_to_remove[rules_counter].tun_name, "NONE"); + rc = strcpy_s(rules_to_remove[rules_counter].tun_name, + sizeof(rules_to_remove[rules_counter].tun_name), "NONE"); + if (rc != EOK) return -1; rules_to_remove[rules_counter].prefix = ip_prefix; rules_to_remove[rules_counter].address_family = ip_prefix.family; @@ -533,7 +532,10 @@ int hicn_bind(hicn_socket_helper_t *hicn, int fd, goto ERR; } - strcpy(rules_to_remove[rules_counter].tun_name, socket->tun_name); + rc = strcpy_s(rules_to_remove[rules_counter].tun_name, + sizeof(rules_to_remove[rules_counter].tun_name), + socket->tun_name); + if (rc != EOK) return -1; rules_to_remove[rules_counter].address_family = addr_family; rules_to_remove[rules_counter].table_id = socket->connection.table_id; ++rules_counter; @@ -563,7 +565,13 @@ int hicn_bind(hicn_socket_helper_t *hicn, int fd, goto ERR; } - strcpy(routes_to_remove[routes_counter].remote_ip_address, remote_ip_address); + rc = strcpy_s(routes_to_remove[routes_counter].remote_ip_address, + sizeof(rules_to_remove[rules_counter].tun_name), + remote_ip_address); + if (rc != EOK) { + rc = HICN_SOCKET_ERROR_UNSPEC; + goto ERR; + } routes_to_remove[routes_counter].table_id = socket->connection.table_id; routes_to_remove[routes_counter].address_family = (uint8_t)addr_family; ++routes_counter; diff --git a/hicn-light/src/hicn/socket/api.h b/hicn-light/src/hicn/socket/api.h index 1a7f5c700..a0356e035 100644 --- a/hicn-light/src/hicn/socket/api.h +++ b/hicn-light/src/hicn/socket/api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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. @@ -29,7 +29,6 @@ #include <stdlib.h> #include <hicn/hicn.h> -#include "error.h" #define BUFSIZE 4096 #define MAX_CONNECTIONS \ diff --git a/hicn-light/src/hicn/socket/ops_linux.c b/hicn-light/src/hicn/socket/ops_linux.c index 8bfc438f3..d741fd2e6 100644 --- a/hicn-light/src/hicn/socket/ops_linux.c +++ b/hicn-light/src/hicn/socket/ops_linux.c @@ -24,6 +24,8 @@ #include <stdint.h> #include <stdlib.h> +#include <hicn/ctrl/api.h> +#include <hicn/util/sstrncpy.h> /* Public interface */ @@ -338,7 +340,8 @@ uint32_t _nl_get_ifid(const char *interface_name) { struct nlmsghdr *hdr = (struct nlmsghdr *)buffer; size_t n; int fd; - size_t len = interface_name ? strlen(interface_name) + 1 : 0; + size_t len = + interface_name ? strnlen_s(interface_name, INTERFACE_LEN) + 1 : 0; uint8_t padding[RTA_ALIGNTO] = {0, 0, 0, 0}; if (len == 0) { @@ -353,8 +356,8 @@ uint32_t _nl_get_ifid(const char *interface_name) { .hdr.nlmsg_flags = FLAGS_GET, .payload.ifi_family = AF_UNSPEC, .payload.ifi_index = 0}; - struct rtattr a_ifname = {RTA_LENGTH(strlen(interface_name) + 1), - IFLA_IFNAME}; + struct rtattr a_ifname = { + RTA_LENGTH(strnlen_s(interface_name, INTERFACE_LEN) + 1), IFLA_IFNAME}; struct iovec iov[] = {{&msg, sizeof(msg)}, {&a_ifname, sizeof(a_ifname)}, @@ -621,13 +624,12 @@ int _nl_set_ip_addr(uint32_t interface_id, ip_prefix_t *prefix) { /* Set attributes = length/type/value */ struct rtattr ifa_address = {RTA_LENGTH(ip_address_len(prefix->family)), IFA_ADDRESS}; - const void * address = ip_address_get_buffer(&prefix->address, prefix->family); - if (!address) - goto ERR_ADDRESS; + const void *address = ip_address_get_buffer(&prefix->address, prefix->family); + if (!address) goto ERR_ADDRESS; const struct iovec iov[] = { {&msg, sizeof(msg)}, {&ifa_address, sizeof(ifa_address)}, - {(void*)address, ip_address_len(prefix->family)}, + {(void *)address, ip_address_len(prefix->family)}, }; msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov)); @@ -993,17 +995,15 @@ int _nl_del_lo_route(const ip_prefix_t *prefix) { uint32_t one = 1; struct rtattr a_dst = {RTA_LENGTH(ip_address_len(prefix->family)), RTA_DST}; struct rtattr a_ifid_lo = {RTA_LENGTH(sizeof(uint32_t)), RTA_OIF}; - const void * address = ip_address_get_buffer(&prefix->address, prefix->family); - if (!address) - goto ERR; - const struct iovec iov[] = { - {&msg, sizeof(msg)}, - /* Ip address */ - {&a_dst, sizeof(a_dst)}, - {(void*)address, ip_address_len(prefix->family)}, - /* Interface id */ - {&a_ifid_lo, sizeof(a_ifid_lo)}, - {&one, sizeof(one)}}; + const void *address = ip_address_get_buffer(&prefix->address, prefix->family); + if (!address) goto ERR; + const struct iovec iov[] = {{&msg, sizeof(msg)}, + /* Ip address */ + {&a_dst, sizeof(a_dst)}, + {(void *)address, ip_address_len(prefix->family)}, + /* Interface id */ + {&a_ifid_lo, sizeof(a_ifid_lo)}, + {&one, sizeof(one)}}; msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov)); fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); @@ -1048,7 +1048,7 @@ int _nl_add_rule(const char *interface_name, uint8_t address_family, _nl_payload_rule(table_id, address_family, (uint8_t *)buffer, BUFSIZE); addAttr(hdr, BUFSIZE, FRA_IIFNAME, (void *)interface_name, - strlen(interface_name)); + strnlen_s(interface_name, INTERFACE_LEN)); fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (fd < 0) { @@ -1094,7 +1094,7 @@ int _nl_del_rule(const char *interface_name, uint8_t address_family, _nl_payload_rule(table_id, address_family, (uint8_t *)buffer, BUFSIZE); addAttr(hdr, BUFSIZE, FRA_IIFNAME, (void *)interface_name, - strlen(interface_name)); + strnlen_s(interface_name, INTERFACE_LEN)); fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (fd < 0) { @@ -1158,16 +1158,15 @@ int _nl_add_neigh_proxy(const ip_prefix_t *prefix, /* Message attributes = length/type/value */ struct rtattr a_dst = {RTA_LENGTH(ip_address_len(prefix->family)), NDA_DST}; - const void * address = ip_address_get_buffer(&prefix->address, prefix->family); - if (!address) - goto ERR; + const void *address = ip_address_get_buffer(&prefix->address, prefix->family); + if (!address) goto ERR; /* Iovec describing the packets */ const struct iovec iov[] = { {&msg, sizeof(msg)}, /* Ip address */ {&a_dst, sizeof(a_dst)}, - {(void*)address, ip_address_len(prefix->family)}, + {(void *)address, ip_address_len(prefix->family)}, }; msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov)); @@ -1240,16 +1239,15 @@ int _nl_add_in_route_table(const ip_prefix_t *prefix, struct rtattr a_dst = {RTA_LENGTH(ip_address_len(prefix->family)), RTA_DST}; struct rtattr a_oif = {RTA_LENGTH(sizeof(uint32_t)), RTA_OIF}; - const void * address = ip_address_get_buffer(&prefix->address, prefix->family); - if (!address) - goto ERR; + const void *address = ip_address_get_buffer(&prefix->address, prefix->family); + if (!address) goto ERR; /* Iovec describing the packets */ const struct iovec iov[] = { {&msg, sizeof(msg)}, /* Destination prefix / ip address */ {&a_dst, sizeof(a_dst)}, - {(void*)address, ip_address_len(prefix->family)}, + {(void *)address, ip_address_len(prefix->family)}, /* Output interface */ {&a_oif, sizeof(a_oif)}, {(void *)&interface_id, sizeof(uint32_t)}, @@ -1346,15 +1344,15 @@ int _nl_add_prio_rule(const ip_prefix_t *prefix, uint8_t address_family, struct rtattr a_src = {RTA_LENGTH(ip_address_len(prefix->family)), FRA_SRC}; struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY}; - const void * address = ip_address_get_buffer(&prefix->address, prefix->family); - if (!address) - goto ERR; + const void *address = + ip_address_get_buffer(&prefix->address, prefix->family); + if (!address) goto ERR; /* Iovec describing the packets */ const struct iovec iov[] = { {&msg, sizeof(msg)}, /* Source prefix / prefix */ {&a_src, sizeof(a_src)}, - {(void*)address, ip_address_len(prefix->family)}, + {(void *)address, ip_address_len(prefix->family)}, /* Priority */ {&a_prio, sizeof(a_prio)}, {(void *)&priority, sizeof(uint32_t)}, @@ -1407,8 +1405,7 @@ ERR: int _nl_add_lo_prio_rule(const ip_prefix_t *prefix, uint8_t address_family, const uint32_t priority) { - return _nl_add_prio_rule(prefix, address_family, priority, - RT_TABLE_LOCAL); + return _nl_add_prio_rule(prefix, address_family, priority, RT_TABLE_LOCAL); } /* ip -6 rule del from all prio 0 table local */ @@ -1450,16 +1447,16 @@ int _nl_del_prio_rule(const ip_prefix_t *prefix, uint8_t address_family, struct rtattr a_src = {RTA_LENGTH(ip_address_len(prefix->family)), FRA_SRC}; struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY}; - const void * address = ip_address_get_buffer(&prefix->address, prefix->family); - if (!address) - goto ERR; + const void *address = + ip_address_get_buffer(&prefix->address, prefix->family); + if (!address) goto ERR; /* Iovec describing the packets */ const struct iovec iov[] = { {&msg, sizeof(msg)}, /* Source prefix / prefix */ {&a_src, sizeof(a_src)}, - {(void*)address, ip_address_len(prefix->family)}, + {(void *)address, ip_address_len(prefix->family)}, /* Priority */ {&a_prio, sizeof(a_prio)}, {(void *)&priority, sizeof(uint32_t)}, @@ -1539,7 +1536,7 @@ int _nl_del_lo_prio_rule(const ip_prefix_t *ip_address, uint8_t address_family, int tun_alloc(char *dev, int flags) { struct ifreq ifr; - int fd, err; + int fd, err, rc; char *clonedev = "/dev/net/tun"; /* Arguments taken by the function: @@ -1563,7 +1560,8 @@ int tun_alloc(char *dev, int flags) { /* if a device name was specified, put it in the structure; otherwise, * the kernel will try to allocate the "next" device of the * specified type */ - strncpy(ifr.ifr_name, dev, IF_NAMESIZE - 1); + rc = strcpy_s(ifr.ifr_name, IF_NAMESIZE - 1, dev); + if (rc != EOK) return -1; } /* try to create the device */ @@ -1576,7 +1574,8 @@ int tun_alloc(char *dev, int flags) { * interface to the variable "dev", so the caller can know * it. Note that the caller MUST reserve space in *dev (see calling * code below) */ - strcpy(dev, ifr.ifr_name); + rc = strcpy_s(dev, IF_NAMESIZE, ifr.ifr_name); + if (rc != EOK) return -1; /* this is the special file descriptor that the caller will use to talk * with the virtual interface */ diff --git a/hicn-light/src/hicn/strategies/CMakeLists.txt b/hicn-light/src/hicn/strategies/CMakeLists.txt index 886aa137c..15ae93fea 100644 --- a/hicn-light/src/hicn/strategies/CMakeLists.txt +++ b/hicn-light/src/hicn/strategies/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -12,20 +12,23 @@ # limitations under the License. list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/strategyImpl.h - ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancer.h - ${CMAKE_CURRENT_SOURCE_DIR}/lowLatency.h - ${CMAKE_CURRENT_SOURCE_DIR}/nexthopState.h - ${CMAKE_CURRENT_SOURCE_DIR}/nexthopStateLowLatency.h - ${CMAKE_CURRENT_SOURCE_DIR}/rnd.h + ${CMAKE_CURRENT_SOURCE_DIR}/load_balancer.h + ${CMAKE_CURRENT_SOURCE_DIR}/low_latency.h + ${CMAKE_CURRENT_SOURCE_DIR}/random.h + ${CMAKE_CURRENT_SOURCE_DIR}/replication.h + ${CMAKE_CURRENT_SOURCE_DIR}/best_path.h + ${CMAKE_CURRENT_SOURCE_DIR}/local_prefixes.h + ${CMAKE_CURRENT_SOURCE_DIR}/probe_generator.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancer.c - ${CMAKE_CURRENT_SOURCE_DIR}/lowLatency.c - ${CMAKE_CURRENT_SOURCE_DIR}/nexthopState.c - ${CMAKE_CURRENT_SOURCE_DIR}/nexthopStateLowLatency.c - ${CMAKE_CURRENT_SOURCE_DIR}/rnd.c + ${CMAKE_CURRENT_SOURCE_DIR}/load_balancer.c + ${CMAKE_CURRENT_SOURCE_DIR}/low_latency.c + ${CMAKE_CURRENT_SOURCE_DIR}/random.c + ${CMAKE_CURRENT_SOURCE_DIR}/replication.c + ${CMAKE_CURRENT_SOURCE_DIR}/best_path.c + ${CMAKE_CURRENT_SOURCE_DIR}/local_prefixes.c + ${CMAKE_CURRENT_SOURCE_DIR}/probe_generator.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/strategies/best_path.c b/hicn-light/src/hicn/strategies/best_path.c new file mode 100644 index 000000000..35a07c43f --- /dev/null +++ b/hicn-light/src/hicn/strategies/best_path.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <hicn/hicn-light/config.h> + +#include <hicn/core/forwarder.h> +#include <hicn/core/nexthops.h> +#include <hicn/core/strategy.h> +#include <hicn/core/strategy_vft.h> + +#include "best_path.h" + +#define MAX_NEXTHOP_COST 100 +#define MAX_RTT_ALLOWED 300.0 // ms +#define MAX_LOSSES_ALLOWED 0.4 // 40% + +#define MAX_PROBING_DURATION 5000 // ticks (= ms) +#define PROBES_WAINTING_TIME 500 // ticks (= ms) +#define MAX_PROBES 50 + +/* Shorthand */ +#define nexthop_state_t strategy_bestpath_nexthop_state_t +#define strategy_state_t strategy_bestpath_state_t +#define nexthop_state(nexthops, i) (&nexthops->state[i].bestpath) + +// nexthop state functions + +static const nexthop_state_t NEXTHOP_STATE_INIT = { + .sent_probes = 0, + .recv_probes = 0, + .rtt_sum = 0, +}; + +static inline unsigned int get_sent_probes(nexthop_state_t *state) { + return state->sent_probes; +} + +static inline unsigned int inc_sent_probes(nexthop_state_t *state) { + state->sent_probes++; + return state->sent_probes; +} + +static inline void add_rtt_sample(nexthop_state_t *state, Ticks rtt) { + state->recv_probes++; + state->rtt_sum += rtt; +} + +static inline unsigned int get_nexthop_cost(nexthop_state_t *state) { + if (state->recv_probes == 0) + return 100; // we have no info for this nexthop, return max cost + + assert(state->recv_probes <= state->sent_probes); + + double rtt = (double)state->rtt_sum / (double)state->recv_probes; + double delay_cost = rtt / MAX_RTT_ALLOWED; + if (delay_cost > 1) delay_cost = 1; + + double loss_rate = (double)(state->sent_probes - state->recv_probes) / + (double)state->sent_probes; + double loss_cost = loss_rate / MAX_LOSSES_ALLOWED; + if (loss_cost > 1) loss_cost = 1; + + double total_cost = delay_cost * 0.5 + loss_cost * 0.5; + return round(total_cost * 100); +} + +// options functions +static void bestpath_update_remote_node(strategy_entry_t *entry, + nexthops_t *nexthops) { + strategy_state_t *state = &entry->state.bestpath; + strategy_bestpath_options_t *options = &entry->options.bestpath; + off_t offset = nexthops_find(nexthops, state->best_nexthop); + nexthops_select(nexthops, offset); + update_remote_node_paths(nexthops, entry->forwarder, options->local_prefixes); +} + +// probing functions + +static void start_probing(strategy_entry_t *entry) { + strategy_state_t *state = &entry->state.bestpath; + if (state->probing_state == PROBING_OFF) { + state->probing_state = PROBING_ON; + state->probing_time = ticks_now(); + } +} + +static void stop_probing(strategy_entry_t *entry, nexthops_t *nexthops) { + strategy_state_t *state = &entry->state.bestpath; + nexthop_t best_nexthop, nexthop; + best_nexthop = state->best_nexthop; + unsigned i; + unsigned int min_cost = ~0; + unsigned current_nexthop_cost = ~0; + + nexthops_enumerate(nexthops, i, nexthop, { + unsigned int cost = get_nexthop_cost(nexthop_state(nexthops, i)); + if (cost < min_cost) { + min_cost = cost; + best_nexthop = nexthop; + } + if (nexthop == state->best_nexthop) current_nexthop_cost = cost; + + nexthops->state[i].bestpath = NEXTHOP_STATE_INIT; + }); + + if (best_nexthop != state->best_nexthop) { + if (current_nexthop_cost > min_cost) { + // update best face + state->best_nexthop = best_nexthop; + } + } + + // always update remote node + bestpath_update_remote_node(entry, nexthops); + + state->probing_state = PROBING_OFF; + delete_all_probes(state->pg); +} + +static void check_stop_probing(strategy_entry_t *entry, nexthops_t *nexthops) { + strategy_state_t *state = &entry->state.bestpath; + if (state->probing_state == PROBING_OFF) return; + + if (state->probing_state == PROBING_ON) { + Ticks probing_duration = ticks_now() - state->probing_time; + if (probing_duration >= MAX_PROBING_DURATION) { + state->probing_state = PROBING_ENDING; + state->probing_time = ticks_now(); + } + return; + } + + if (state->probing_state == SENT_MAX_PROBES) { + state->probing_state = PROBING_ENDING; + state->probing_time = ticks_now(); + return; + } + + if (state->probing_state == PROBING_ENDING) { + Ticks ending_duration = ticks_now() - state->probing_time; + if (ending_duration >= PROBES_WAINTING_TIME) stop_probing(entry, nexthops); + } +} + +static void send_probes(strategy_entry_t *entry, nexthops_t *nexthops, + const msgbuf_t *msgbuf) { + strategy_state_t *state = &entry->state.bestpath; + + unsigned i; + nexthop_t nexthop; + bool sent_max_probes = false; + nexthops_enumerate(nexthops, i, nexthop, { + if (get_sent_probes(nexthop_state(nexthops, i)) < MAX_PROBES) { + int res = generate_probe(state->pg, msgbuf, entry->forwarder, nexthop); + if (res >= 0) inc_sent_probes(nexthop_state(nexthops, i)); + } else { + sent_max_probes = true; + } + }); + + if (sent_max_probes) { + state->probing_state = SENT_MAX_PROBES; + check_stop_probing(entry, nexthops); + } +} + +static void init_strategy_state(strategy_state_t *state) { + state->best_nexthop = ~0; + state->probing_state = PROBING_OFF; + state->pg = create_probe_generator(); +} + +// strategy functions +static int strategy_bestpath_initialize(strategy_entry_t *entry, + const void *forwarder) { + if (entry->forwarder == NULL) { + srand((unsigned int)time(NULL)); + entry->forwarder = forwarder; + init_strategy_state(&entry->state.bestpath); + } else { + strategy_state_t *state = &entry->state.bestpath; + if (!state->pg) { + // the previous strategy was a different one + init_strategy_state(state); + } else { + // all set, start probing + start_probing(entry); + } + } + return 0; +} + +static int strategy_bestpath_finalize(strategy_entry_t *entry) { + strategy_state_t *state = &entry->state.bestpath; + free_local_prefixes(entry->options.bestpath.local_prefixes); + destroy_probe_generator(state->pg); + return 0; +} + +static int strategy_bestpath_add_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, off_t offset) { + // reset the strategy state + nexthops->state[offset].bestpath = NEXTHOP_STATE_INIT; + return 0; +} + +static int strategy_bestpath_remove_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, + off_t offset) { + /* Nothing to do */ + return 0; +} + +static nexthops_t *strategy_bestpath_lookup_nexthops(strategy_entry_t *entry, + nexthops_t *nexthops, + const msgbuf_t *msgbuf) { + size_t nexthops_len = nexthops_get_curlen(nexthops); + if (nexthops_len == 0) { + // nexthops is empty, return + return nexthops; + } + + strategy_state_t *state = &entry->state.bestpath; + off_t best_nexthop_offset = nexthops_find(nexthops, state->best_nexthop); + + if (nexthops_len == 1) { + nexthop_t nh = nexthops_get_one(nexthops); + if (state->best_nexthop != nh) { + state->best_nexthop = nh; + bestpath_update_remote_node(entry, nexthops); + } + return nexthops; + } + + if (state->best_nexthop == ~0 || best_nexthop_offset == INVALID_NEXTHOP) { + state->best_nexthop = nexthops_get_one(nexthops); + best_nexthop_offset = nexthops_find(nexthops, state->best_nexthop); + bestpath_update_remote_node(entry, nexthops); + // we have probe only in case the number of face is > 1 + start_probing(entry); + // bestpath_update_remote_node sets the nexthops. in case of probing we want + // to send the packets on all faces, so we reset the nexthops here + nexthops_reset(nexthops); + } + + if (state->probing_state == PROBING_ON) { + // send a probe for each interest received + send_probes(entry, nexthops, msgbuf); + + uint32_t suffix = name_GetSuffix(msgbuf_get_name(msgbuf)); + if (suffix >= MIN_PROBE_SUFFIX && suffix <= MAX_PROBE_SUFFIX) { + // this packet is a probe from the transport, so register it + Ticks time = get_probe_send_time(state->pg, suffix); + if (time == 0) { + // a probe with the same seq number is not pending, send the packet + // the stats for this probe will be collected by the transport + register_probe(state->pg, suffix); + } else { + // this probe is already pending. avoid duplicates and drop it + nexthops->flags = ~0; + nexthops->cur_elts = 0; + } + } + } else { + // we are not probing anymore. if in probing ending state (wait for probes + // to come back) keep replicating traffic, otherwise and on best path + if (state->probing_state != PROBING_ENDING) + nexthops_select(nexthops, best_nexthop_offset); + } + + // in case we are still probing send all interest on all paths + // so do not select any next hop. + // XXX in this transition phase should we replicate also at the + // server side? + return nexthops; +} + +static int strategy_bestpath_on_data(strategy_entry_t *entry, + nexthops_t *nexthops, + const nexthops_t *data_nexthops, + const msgbuf_t *msgbuf, + Ticks pitEntryCreation, + Ticks objReception) { + strategy_state_t *state = &entry->state.bestpath; + if (state->probing_state == PROBING_OFF) return 0; + + uint32_t seq = name_GetSuffix(msgbuf_get_name(msgbuf)); + if (seq >= MIN_PROBE_SUFFIX && seq <= MAX_PROBE_SUFFIX) { + if (pitEntryCreation != 0) { + // this is not a probe sent by the forwader. do not use it in the probing + // statisitcs but remove it from the map if it exists + delete_probe(state->pg, seq); + return 0; + } + + unsigned nexthop, i; + Ticks send_time = get_probe_send_time(state->pg, seq); + if (send_time != 0) { + Ticks rtt = ticks_now() - send_time; + delete_probe(state->pg, seq); + nexthops_enumerate(data_nexthops, i, nexthop, { + off_t pos = nexthops_find(nexthops, nexthop); + add_rtt_sample(nexthop_state(nexthops, pos), rtt); + }); + } + } + + check_stop_probing(entry, nexthops); + + return 0; +} + +static int strategy_bestpath_on_timeout(strategy_entry_t *entry, + nexthops_t *nexthops, + const nexthops_t *timeout_nexthops) { + /* Nothing to do */ + return 0; +} + +#undef nexthop_state_t +#undef strategy_state_t + +DECLARE_STRATEGY(bestpath); + +#undef nexthop_state_t +#undef strategy_state_t diff --git a/hicn-light/src/hicn/strategies/best_path.h b/hicn-light/src/hicn/strategies/best_path.h new file mode 100644 index 000000000..206214579 --- /dev/null +++ b/hicn-light/src/hicn/strategies/best_path.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * Forward on a single path. Every time the strategy is reset with a command the + * forwarder starts to probe the available paths matching the probes on the + * original flow. if after the probing phase a better path exists (lower + * latency, less losses) the forwarder switch path, otherwise does nothing + */ + +#ifndef HICNLIGHT_STRATEGY_BESTPATH_H +#define HICNLIGHT_STRATEGY_BESTPATH_H + +#include "probe_generator.h" +#include "local_prefixes.h" + +typedef enum { + PROBING_OFF, + PROBING_ON, + SENT_MAX_PROBES, + PROBING_ENDING, // waiting for probes to come back + UNKWNOWN, +} probing_state_t; + +typedef struct { + // number or probes sent during a probing phase + unsigned int sent_probes; + // number or probes received during a probing phase + unsigned int recv_probes; + // sum of all rtt collected + Ticks rtt_sum; +} strategy_bestpath_nexthop_state_t; + +typedef struct { + unsigned best_nexthop; + Ticks probing_time; + probing_state_t probing_state; + probe_generator_t *pg; +} strategy_bestpath_state_t; + +typedef struct { + local_prefixes_t *local_prefixes; +} strategy_bestpath_options_t; + +#endif /* HICNLIGHT_STRATEGY_BESTPATH_H */ diff --git a/hicn-light/src/hicn/strategies/loadBalancer.c b/hicn-light/src/hicn/strategies/loadBalancer.c deleted file mode 100644 index 82b5a6103..000000000 --- a/hicn-light/src/hicn/strategies/loadBalancer.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_HashMap.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> -#include <parc/algol/parc_Unsigned.h> - -#include <hicn/strategies/loadBalancer.h> -#include <hicn/strategies/nexthopState.h> - -static void _strategyLoadBalancer_ReceiveObject(StrategyImpl *strategy, - const NumberSet *egressId, - const Message *objectMessage, - Ticks pitEntryCreation, - Ticks objReception); -static void _strategyLoadBalancer_OnTimeout(StrategyImpl *strategy, - const NumberSet *egressId); -static NumberSet *_strategyLoadBalancer_LookupNexthop( - StrategyImpl *strategy, -#ifdef WITH_POLICY - NumberSet * nexthops, -#endif /* WITH_POLICY */ - const Message *interestMessage); -#ifndef WITH_POLICY -static NumberSet *_strategyLoadBalancer_ReturnNexthops(StrategyImpl *strategy); -static unsigned _strategyLoadBalancer_CountNexthops(StrategyImpl *strategy); -#endif /* ! WITH_POLICY */ -static void _strategyLoadBalancer_AddNexthop(StrategyImpl *strategy, - unsigned connectionId); -static void _strategyLoadBalancer_RemoveNexthop(StrategyImpl *strategy, - unsigned connectionId); -static void _strategyLoadBalancer_ImplDestroy(StrategyImpl **strategyPtr); -static strategy_type _strategyLoadBalancer_GetStrategy(StrategyImpl *strategy); - -static StrategyImpl _template = { - .context = NULL, - .receiveObject = &_strategyLoadBalancer_ReceiveObject, - .onTimeout = &_strategyLoadBalancer_OnTimeout, - .lookupNexthop = &_strategyLoadBalancer_LookupNexthop, -#ifndef WITH_POLICY - .returnNexthops = &_strategyLoadBalancer_ReturnNexthops, - .countNexthops = &_strategyLoadBalancer_CountNexthops, -#endif /* ! WITH_POLICY */ - .addNexthop = &_strategyLoadBalancer_AddNexthop, - .removeNexthop = &_strategyLoadBalancer_RemoveNexthop, - .destroy = &_strategyLoadBalancer_ImplDestroy, - .getStrategy = &_strategyLoadBalancer_GetStrategy, -}; - -struct strategy_load_balancer; -typedef struct strategy_load_balancer StrategyLoadBalancer; - -struct strategy_load_balancer { -#ifndef WITH_POLICY - double weights_sum; -#endif /* ! WITH_POLICY */ - // hash map from connectionId to StrategyNexthopState - PARCHashMap *strategy_state; -#ifndef WITH_POLICY - NumberSet *nexthops; -#endif /* ! WITH_POLICY */ -}; - -StrategyImpl *strategyLoadBalancer_Create() { - StrategyLoadBalancer *strategy = - parcMemory_AllocateAndClear(sizeof(StrategyLoadBalancer)); - parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(StrategyLoadBalancer)); - -#ifndef WITH_POLICY - strategy->weights_sum = 0.0; -#endif /* ! WITH_POLICY */ - strategy->strategy_state = parcHashMap_Create(); -#ifndef WITH_POLICY - strategy->nexthops = numberSet_Create(); -#endif /* ! WITH_POLICY */ - srand((unsigned int)time(NULL)); - - StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl)); - parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(StrategyImpl)); - memcpy(impl, &_template, sizeof(StrategyImpl)); - impl->context = strategy; - - return impl; -} - -// ======================================================= -// Dispatch API - -strategy_type _strategyLoadBalancer_GetStrategy(StrategyImpl *strategy) { - return SET_STRATEGY_LOADBALANCER; -} - -static void _update_Stats(StrategyLoadBalancer *strategy, - StrategyNexthopState *state, bool inc) { - const double ALPHA = 0.9; -#ifdef WITH_POLICY - strategyNexthopState_UpdateState(state, inc, ALPHA); -#else - double w = strategyNexthopState_GetWeight(state); - strategy->weights_sum -= w; - w = strategyNexthopState_UpdateState(state, inc, ALPHA); - strategy->weights_sum += w; -#endif /* WITH_POLICY */ -} - -#ifndef WITH_POLICY -static unsigned _select_Nexthop(StrategyLoadBalancer *strategy) { - double rnd = (double)rand() / (double)RAND_MAX; - double start_range = 0.0; - - PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state); - - unsigned nexthop = 100000; - while (parcIterator_HasNext(it)) { - PARCUnsigned *cid = parcIterator_Next(it); - const StrategyNexthopState *elem = - parcHashMap_Get(strategy->strategy_state, cid); - - double w = strategyNexthopState_GetWeight(elem); - - double prob = w / strategy->weights_sum; - if ((rnd >= start_range) && (rnd <= (start_range + prob))) { - nexthop = parcUnsigned_GetUnsigned(cid); - break; - } else { - start_range += prob; - } - } - - parcIterator_Release(&it); - - // if no face is selected by the algorithm (for example because of a wrong - // round in the weights) we may always select the last face here. Double check - // this! - return nexthop; -} -#endif /* ! WITH_POLICY */ - -static void _strategyLoadBalancer_ReceiveObject(StrategyImpl *strategy, - const NumberSet *egressId, - const Message *objectMessage, - Ticks pitEntryCreation, - Ticks objReception) { - _strategyLoadBalancer_OnTimeout(strategy, egressId); -} - -static void _strategyLoadBalancer_OnTimeout(StrategyImpl *strategy, - const NumberSet *egressId) { - StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context; - - for (unsigned i = 0; i < numberSet_Length(egressId); i++) { - unsigned outId = numberSet_GetItem(egressId, i); - PARCUnsigned *cid = parcUnsigned_Create(outId); - - const StrategyNexthopState *state = - parcHashMap_Get(lb->strategy_state, cid); - if (state != NULL) { - _update_Stats(lb, (StrategyNexthopState *)state, false); - } else { - // this may happen if we remove a face/route while downloading a file - // we should ignore this timeout - } - parcUnsigned_Release(&cid); - } -} - -static NumberSet *_strategyLoadBalancer_LookupNexthop( - StrategyImpl *strategy, -#ifdef WITH_POLICY - NumberSet * nexthops, -#endif /* WITH_POLICY */ - const Message *interestMessage) { - StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context; - NumberSet *outList = numberSet_Create(); - -#ifdef WITH_POLICY - /* Compute the sum of weights of potential next hops */ - double sum = 0; - for (unsigned i = 0; i < numberSet_Length(nexthops); i++) { - PARCUnsigned *cid = parcUnsigned_Create(numberSet_GetItem(nexthops, i)); - const StrategyNexthopState *elem = - parcHashMap_Get(lb->strategy_state, cid); - parcUnsigned_Release(&cid); - if (!elem) - continue; - sum += strategyNexthopState_GetWeight(elem); - } - - /* Perform weighted random selection */ - double distance = (double)rand() * sum / ((double)RAND_MAX + 1); - - for (unsigned i = 0; i < numberSet_Length(nexthops); i++) { - PARCUnsigned *cid = parcUnsigned_Create(numberSet_GetItem(nexthops, i)); - const StrategyNexthopState *state = - parcHashMap_Get(lb->strategy_state, cid); - if (!state) { - parcUnsigned_Release(&cid); - continue; - } - distance -= strategyNexthopState_GetWeight(state); - if (distance < 0) { - numberSet_Add(outList, parcUnsigned_GetUnsigned(cid)); - _update_Stats(lb, (StrategyNexthopState *)state, true); - parcUnsigned_Release(&cid); - break; - } - parcUnsigned_Release(&cid); - } -#else - unsigned in_connection = message_GetIngressConnectionId(interestMessage); - PARCUnsigned *in = parcUnsigned_Create(in_connection); - - unsigned mapSize = (unsigned)parcHashMap_Size(lb->strategy_state); - - if ((mapSize == 0) || - ((mapSize == 1) && parcHashMap_Contains(lb->strategy_state, in))) { - // there are no output faces or the input face is also the only output face. - // return null to avoid loops - parcUnsigned_Release(&in); - return outList; - } - - unsigned out_connection; - do { - out_connection = _select_Nexthop(lb); - } while (out_connection == in_connection); - - PARCUnsigned *out = parcUnsigned_Create(out_connection); - - const StrategyNexthopState *state = parcHashMap_Get(lb->strategy_state, out); - if (state == NULL) { - // this is an error and should not happen! - parcTrapNotImplemented( - "Try to send an interest on a face that does not exists"); - } - - _update_Stats(lb, (StrategyNexthopState *)state, true); - - parcUnsigned_Release(&in); - parcUnsigned_Release(&out); - - numberSet_Add(outList, out_connection); -#endif /* WITH_POLICY */ - - return outList; -} - -#ifndef WITH_POLICY -static NumberSet *_strategyLoadBalancer_ReturnNexthops(StrategyImpl *strategy) { - StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context; - return lb->nexthops; -} - -unsigned _strategyLoadBalancer_CountNexthops(StrategyImpl *strategy) { - StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context; - return (unsigned)numberSet_Length(lb->nexthops); -} -#endif /* ! WITH_POLICY */ - -static void _strategyLoadBalancer_resetState(StrategyImpl *strategy) { - StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context; -#ifndef WITH_POLICY - lb->weights_sum = 0.0; -#endif/* ! WITH_POLICY */ - PARCIterator *it = parcHashMap_CreateKeyIterator(lb->strategy_state); - - while (parcIterator_HasNext(it)) { - PARCUnsigned *cid = parcIterator_Next(it); - StrategyNexthopState *elem = - (StrategyNexthopState *)parcHashMap_Get(lb->strategy_state, cid); - - strategyNexthopState_Reset(elem); -#ifndef WITH_POLICY - lb->weights_sum += strategyNexthopState_GetWeight(elem); -#endif /* ! WITH_POLICY */ - } - - parcIterator_Release(&it); -} - -static void _strategyLoadBalancer_AddNexthop(StrategyImpl *strategy, - unsigned connectionId) { - - PARCUnsigned *cid = parcUnsigned_Create(connectionId); - - StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context; - - if (!parcHashMap_Contains(lb->strategy_state, cid)) { - StrategyNexthopState *state = strategyNexthopState_Create(); - parcHashMap_Put(lb->strategy_state, cid, state); -#ifndef WITH_POLICY - numberSet_Add(lb->nexthops, connectionId); -#endif /* WITH_POLICY */ - _strategyLoadBalancer_resetState(strategy); - } - parcUnsigned_Release(&cid); -} - -static void _strategyLoadBalancer_RemoveNexthop(StrategyImpl *strategy, - unsigned connectionId) { - StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context; - - PARCUnsigned *cid = parcUnsigned_Create(connectionId); - - if (parcHashMap_Contains(lb->strategy_state, cid)) { - StrategyNexthopState *state = - (StrategyNexthopState *)parcHashMap_Get(lb->strategy_state, cid); - parcObject_Release((void**)&state); - - parcHashMap_Remove(lb->strategy_state, cid); -#ifndef WITH_POLICY - numberSet_Remove(lb->nexthops, connectionId); -#endif /* WITH_POLICY */ - _strategyLoadBalancer_resetState(strategy); - } - - parcUnsigned_Release(&cid); -} - -static void _strategyLoadBalancer_ImplDestroy(StrategyImpl **strategyPtr) { - parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*strategyPtr, - "Parameter must dereference to non-null pointer"); - - StrategyImpl *impl = *strategyPtr; - StrategyLoadBalancer *strategy = (StrategyLoadBalancer *)impl->context; - if (parcHashMap_Size(strategy->strategy_state) > 0) { - PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state); - while (parcIterator_HasNext(it)) { - PARCUnsigned *cid = parcIterator_Next(it); - StrategyNexthopState *state = - (StrategyNexthopState *) parcHashMap_Get(strategy->strategy_state, cid); - parcObject_Release((void **) &state); - } - parcIterator_Release(&it); - } - - parcHashMap_Release(&(strategy->strategy_state)); -#ifndef WITH_POLICY - numberSet_Release(&(strategy->nexthops)); -#endif /* ! WITH_POLICY */ - - parcMemory_Deallocate((void **) &strategy); - parcMemory_Deallocate((void **) &impl); - *strategyPtr = NULL; -} diff --git a/hicn-light/src/hicn/strategies/load_balancer.c b/hicn-light/src/hicn/strategies/load_balancer.c new file mode 100644 index 000000000..709efcf23 --- /dev/null +++ b/hicn-light/src/hicn/strategies/load_balancer.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <hicn/hicn-light/config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <hicn/core/strategy.h> +#include <hicn/core/strategy_vft.h> +#include <hicn/core/nexthops.h> +#include <hicn/core/fib_entry.h> + +#include "load_balancer.h" + +#define AVG_PI_THRESHOLD 1e-3 +#define AVG_PI_MIN 0.1 + +#define ALPHA 0.9 + +/* Shorthand */ +#define nexthop_state_t strategy_load_balancer_nexthop_state_t +#define nexthop_state(nexthops, i) (&nexthops->state[i].load_balancer) + +static const nexthop_state_t NEXTHOP_STATE_INIT = { + .pi = 0, + .avg_pi = 0.0, + .weight = 1, +}; + +static inline void update_state(nexthop_state_t *state) { + state->avg_pi = (state->avg_pi * ALPHA) + (state->pi * 1 - ALPHA); + if (state->avg_pi < AVG_PI_THRESHOLD) state->avg_pi = AVG_PI_MIN; + state->weight = 1 / state->avg_pi; +} + +static inline void update_state_inc(nexthop_state_t *state) { + state->pi++; + update_state(state); +} + +static inline void update_state_dec(nexthop_state_t *state) { + if (state->pi > 0) state->pi--; + update_state(state); +} + +static inline void reset_all(nexthops_t *nexthops) { + unsigned i; + nexthop_t nexthop; + nexthops_enumerate(nexthops, i, nexthop, { + (void)nexthop; + nexthops->state[i].load_balancer = NEXTHOP_STATE_INIT; + }); +} + +static int strategy_load_balancer_initialize(strategy_entry_t *entry, + const void *forwarder) { + /* No reset, this will be done when a nexthop is added */ + entry->forwarder = forwarder; + return 0; +} + +static int strategy_load_balancer_finalize(strategy_entry_t *entry) { + /* Nothing to do */ + return 0; +} + +static int strategy_load_balancer_add_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, + off_t offset) { + /* We reset the state of all nexthops */ + reset_all(nexthops); + return 0; +} + +static int strategy_load_balancer_remove_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, + off_t offset) { + reset_all(nexthops); + return 0; +} + +static nexthops_t *strategy_load_balancer_lookup_nexthops( + strategy_entry_t *entry, nexthops_t *nexthops, const msgbuf_t *msgbuf) { + /* Compute the sum of weights of potential next hops */ + double sum = 0; + unsigned i, nexthop; + nexthops_enumerate(nexthops, i, nexthop, { + (void)nexthop; + sum += nexthops_state(nexthops, i).load_balancer.weight; + }); + + /* Perform weighted random selection */ + double distance = (double)rand() * sum / ((double)RAND_MAX + 1); + + nexthops_enumerate(nexthops, i, nexthop, { + distance -= nexthop_state(nexthops, i)->weight; + if (distance < 0) { + nexthops_select(nexthops, i); + update_state_inc(nexthop_state(nexthops, i)); + break; + } + }); + return nexthops; +} + +static int strategy_load_balancer_on_timeout( + strategy_entry_t *entry, nexthops_t *nexthops, + const nexthops_t *timeout_nexthops) { + /* + * As we have few nexthops in FIB entry, and even fewer selected ones in + * nexthops, we can allow for linear search that will be very efficient + * CPU-wise. + */ + nexthop_t timeout_nexthop; + nexthops_foreach(timeout_nexthops, timeout_nexthop, { + nexthop_t nexthop; + unsigned i; + nexthops_enumerate(nexthops, i, nexthop, { + if (nexthop == timeout_nexthop) + update_state_dec(nexthop_state(nexthops, i)); + }); + }); + return 0; +} + +static int strategy_load_balancer_on_data(strategy_entry_t *entry, + nexthops_t *nexthops, + const nexthops_t *data_nexthops, + const msgbuf_t *msgbuf, + Ticks pitEntryCreation, + Ticks objReception) { + return strategy_load_balancer_on_timeout(entry, nexthops, data_nexthops); +} + +#undef nexthop_state_t + +DECLARE_STRATEGY(load_balancer); + +#undef nexthop_state_t diff --git a/hicn-light/src/hicn/config/controlUpdate.h b/hicn-light/src/hicn/strategies/load_balancer.h index 0007ab653..f7447d928 100644 --- a/hicn-light/src/hicn/config/controlUpdate.h +++ b/hicn-light/src/hicn/strategies/load_balancer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -14,22 +14,24 @@ */ /** - * @file control_Update.h - * @brief Root node for the "update" commands - * - * Implements the "update" node of the CLI tree. - * + * Forward on the less loaded path */ -#ifndef controlUpdate_h -#define controlUpdate_h +#ifndef HICNLIGHT_STRATEGY_LOAD_BALANCER_H +#define HICNLIGHT_STRATEGY_LOAD_BALANCER_H -#ifdef WITH_POLICY +typedef struct { + unsigned int pi; + double avg_pi; + double weight; +} strategy_load_balancer_nexthop_state_t; -#include <hicn/config/controlState.h> -CommandOps *controlUpdate_Create(ControlState *state); -CommandOps *controlUpdate_HelpCreate(ControlState *state); +typedef struct { + void *_; +} strategy_load_balancer_state_t; -#endif /* WITH_POLICY */ +typedef struct { + void *_; +} strategy_load_balancer_options_t; -#endif // controlUpdate_h +#endif /* HICNLIGHT_STRATEGY_LOAD_BALANCER_H */ diff --git a/hicn-light/src/hicn/strategies/local_prefixes.c b/hicn-light/src/hicn/strategies/local_prefixes.c new file mode 100644 index 000000000..23d72ae80 --- /dev/null +++ b/hicn-light/src/hicn/strategies/local_prefixes.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 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. + */ + +#include "local_prefixes.h" +#include <hicn/core/forwarder.h> +#include <hicn/core/nexthops.h> +#include <hicn/core/name.h> +#include <hicn/core/mapme.h> + +#define MAX_PREFIXES 10 + +struct local_prefixes_s { + Name local_prefixes[MAX_PREFIXES]; + unsigned len; +}; + +local_prefixes_t *create_local_prefixes() { + local_prefixes_t *lp = calloc(1, sizeof(local_prefixes_t)); + if (!lp) return NULL; + return lp; +} + +void free_local_prefixes(local_prefixes_t *lp) { free(lp); } + +unsigned local_prefixes_get_len(local_prefixes_t *prefixes) { + return prefixes->len; +} + +bool contain_prefix(local_prefixes_t *prefixes, Name *name) { + for (unsigned i = 0; i < prefixes->len; i++) { + if (name_Equals(&(prefixes->local_prefixes[i]), name)) return true; + } + return false; +} + +void local_prefixes_add_prefixes(local_prefixes_t *prefixes, + local_prefixes_t *new_prefixes) { + // if there is not enough space for the new prefixes they are not added + unsigned i = 0; + while ((i < new_prefixes->len) && (prefixes->len < MAX_PREFIXES)) { + if (!contain_prefix(prefixes, &(new_prefixes->local_prefixes[i]))) { + name_Copy(&new_prefixes->local_prefixes[i], + &prefixes->local_prefixes[prefixes->len]); + prefixes->len++; + } + i++; + } +} + +void local_prefixes_add_prefix(local_prefixes_t *prefixes, const void *prefix) { + if (prefixes->len >= MAX_PREFIXES) return; + Name *n = (Name *)prefix; + if (!contain_prefix(prefixes, n)) { + name_Copy(n, &(prefixes->local_prefixes[prefixes->len])); + prefixes->len++; + } +} + +void update_remote_node_paths(const void *nexthops, const void *forwarder, + local_prefixes_t *prefixes) { + if (!prefixes) return; + struct mapme_s *mapme = forwarder_get_mapme((forwarder_t *)forwarder); + fib_t *fib = forwarder_get_fib((forwarder_t *)forwarder); + for (unsigned i = 0; i < prefixes->len; i++) { + fib_entry_t *entry = fib_match_name(fib, &prefixes->local_prefixes[i]); + if (!entry) continue; + mapme_set_adjacencies(mapme, entry, (nexthops_t *)nexthops, false); + } +} diff --git a/hicn-light/src/hicn/strategies/local_prefixes.h b/hicn-light/src/hicn/strategies/local_prefixes.h new file mode 100644 index 000000000..833a48057 --- /dev/null +++ b/hicn-light/src/hicn/strategies/local_prefixes.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * struct used to store prefixes that are served locally. + * these prefixes are used in mapme messages to tell to the server which + * path to use to retrive the content produced locally. + * using this strategy the path selection done by the client can be + * replicated at the server + */ + +#ifndef HICNLIGHT_LOCAL_PREFIXES_H +#define HICNLIGHT_LOCAL_PREFIXES_H + +typedef struct local_prefixes_s local_prefixes_t; + +local_prefixes_t* create_local_prefixes(); + +void free_local_prefixes(local_prefixes_t* lp); + +unsigned local_prefixes_get_len(local_prefixes_t* prefixes); + +void local_prefixes_add_prefixes(local_prefixes_t* prefixes, + local_prefixes_t* new_prefixes); + +void local_prefixes_add_prefix(local_prefixes_t* prefixes, const void* prefix); + +void update_remote_node_paths(const void* nexthops, const void* forwarder, + local_prefixes_t* prefixes); + +#endif /* HICNLIGHT_LOCAL_PREFIXES */ diff --git a/hicn-light/src/hicn/strategies/lowLatency.c b/hicn-light/src/hicn/strategies/lowLatency.c deleted file mode 100644 index 61bffe243..000000000 --- a/hicn-light/src/hicn/strategies/lowLatency.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <math.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_HashMap.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> -#include <parc/algol/parc_Unsigned.h> - -#include <hicn/core/messageHandler.h> - -#include <hicn/strategies/lowLatency.h> -#include <hicn/strategies/nexthopStateLowLatency.h> - -const unsigned STABILITY_FACTOR = 15; -const unsigned MAX_SWITCH_TRY = 10; -const unsigned MAX_LATENCY_DIFF = 10; -const unsigned MAX_TOLLERATED_LATENCY_DIFF = 15; -const unsigned MAX_ROUNDS_MP_WITHOUT_CHECK = 2; -const unsigned MAX_ROUNDS_AVOIDING_MULTIPATH = 40; //about 20 sec -const unsigned MAX_ROUNDS_WITH_ERROR = 4; -const unsigned PROBE_LIFETIME = 500; //ms - -static void _strategyLowLatency_ReceiveObject(StrategyImpl *strategy, - const NumberSet *egressId, - const Message *objectMessage, - Ticks pitEntryCreation, - Ticks objReception); -static void _strategyLowLatency_OnTimeout(StrategyImpl *strategy, - const NumberSet *egressId); -static NumberSet *_strategyLowLatency_LookupNexthop( - StrategyImpl *strategy, -#ifdef WITH_POLICY - NumberSet * nexthops, -#endif /* WITH_POLICY */ - const Message *interestMessage); -#ifndef WITH_POLICY -static NumberSet *_strategyLowLatency_ReturnNexthops(StrategyImpl *strategy); -static unsigned _strategyLowLatency_CountNexthops(StrategyImpl *strategy); -#endif /* ! WITH_POLICY */ -static void _strategyLowLatency_AddNexthop(StrategyImpl *strategy, - unsigned connectionId); -static void _strategyLowLatency_RemoveNexthop(StrategyImpl *strategy, - unsigned connectionId); -static void _strategyLowLatency_ImplDestroy(StrategyImpl **strategyPtr); -static strategy_type _strategyLowLatency_GetStrategy(StrategyImpl *strategy); - -static StrategyImpl _template = { - .context = NULL, - .receiveObject = &_strategyLowLatency_ReceiveObject, - .onTimeout = &_strategyLowLatency_OnTimeout, - .lookupNexthop = &_strategyLowLatency_LookupNexthop, -#ifndef WITH_POLICY - .returnNexthops = &_strategyLowLatency_ReturnNexthops, - .countNexthops = &_strategyLowLatency_CountNexthops, -#endif /* ! WITH_POLICY */ - .addNexthop = &_strategyLowLatency_AddNexthop, - .removeNexthop = &_strategyLowLatency_RemoveNexthop, - .destroy = &_strategyLowLatency_ImplDestroy, - .getStrategy = &_strategyLowLatency_GetStrategy, -}; - -struct strategy_low_latency; -typedef struct strategy_low_latency StrategyLowLatency; - -struct strategy_low_latency { - // hash map from connectionId to StrategyNexthopStateLL - PARCHashMap *strategy_state; - //hash map from sequence number to ticks (sent time) - PARCHashMap *pending_probes_ticks; - //hash map from sequence number to face id - PARCHashMap *pending_probes_faces; - const Forwarder * forwarder; - PARCEventTimer *sendProbes; - PARCEventTimer *computeBestFace; - uint8_t * probe; - hicn_name_t * name; - StrategyNexthopStateLL * bestFaces[2]; - unsigned round; - unsigned rounds_in_multipath; - unsigned rounds_with_error; - unsigned rounds_avoiding_multipath; - bool use2paths; - bool avoid_multipath; - unsigned related_prefixes_len; - Name **related_prefixes; -#ifndef WITH_POLICY - NumberSet *nexthops; -#endif /* ! WITH_POLICY */ -}; - -static void strategyLowLatency_SendProbesCB(int fd, PARCEventType which_event, - void *data){ - parcAssertTrue(which_event & PARCEventType_Timeout, - "Event incorrect, expecting %X set, got %X", - PARCEventType_Timeout, which_event); - - StrategyLowLatency *ll = (StrategyLowLatency *) data; - - //delete old pending probes - if(parcHashMap_Size(ll->pending_probes_ticks) != 0){ - Ticks now = forwarder_GetTicks(ll->forwarder); - PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->pending_probes_ticks); - NumberSet *to_remove = numberSet_Create(); - while(parcIterator_HasNext(iterator)) { - PARCUnsigned *parc_seq = (PARCUnsigned *) parcIterator_Next(iterator); - PARCUnsigned *parc_time = (PARCUnsigned *) parcHashMap_Get(ll->pending_probes_ticks, parc_seq); - Ticks sent_time = parcUnsigned_GetUnsigned(parc_time); - if((now - sent_time) > PROBE_LIFETIME){ - //probes to delete - numberSet_Add(to_remove, parcUnsigned_GetUnsigned(parc_seq)); - } - } - parcIterator_Release(&iterator); - - for(int i = 0; i < numberSet_Length(to_remove); i++){ - PARCUnsigned *prob_seq = parcUnsigned_Create(numberSet_GetItem(to_remove,i)); - PARCUnsigned *cid = (PARCUnsigned *) parcHashMap_Get(ll->pending_probes_faces, prob_seq); - StrategyNexthopStateLL *state = - (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); - strategyNexthopStateLL_LostProbe(state); - parcHashMap_Remove(ll->pending_probes_ticks, prob_seq); - parcHashMap_Remove(ll->pending_probes_faces, prob_seq); - parcUnsigned_Release(&prob_seq); - } - numberSet_Release(&to_remove); - } - - ConnectionTable * ct = forwarder_GetConnectionTable(ll->forwarder); - - PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); - while(parcIterator_HasNext(iterator)){ - PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); - Connection *conn = - (Connection *)connectionTable_FindById(ct, - parcUnsigned_GetUnsigned(cid)); - if(!conn) - continue; - - StrategyNexthopStateLL *state = - (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); - - //probe only usable paths - if(!strategyNexthopStateLL_IsAllowed(state)) - continue; - - uint32_t seq = rand(); - messageHandler_SetProbeName(ll->probe, HF_INET6_TCP, - ll->name, seq); - connection_Probe(conn, ll->probe); - - PARCUnsigned *parc_seq = parcUnsigned_Create(seq); - Ticks now = forwarder_GetTicks(ll->forwarder); - PARCUnsigned *parc_time = parcUnsigned_Create((unsigned int)now); - parcHashMap_Put(ll->pending_probes_ticks, parc_seq, parc_time); - parcHashMap_Put(ll->pending_probes_faces, parc_seq, cid); - strategyNexthopStateLL_SentProbe(state); - parcUnsigned_Release(&parc_seq); - parcUnsigned_Release(&parc_time); - } - parcIterator_Release(&iterator); - - struct timeval timeout = {0,50000}; - parcEventTimer_Start(ll->sendProbes, &timeout); -} - -static void strategyLowLatency_SendMapmeUpdate(StrategyLowLatency *ll, - const NumberSet * nexthops){ - MapMe * mapme = forwarder_getMapmeInstance(ll->forwarder); - FIB * fib = forwarder_getFib((Forwarder*) ll->forwarder); - if(fib != NULL){ - for(unsigned i = 0; i < ll->related_prefixes_len; i++){ - FibEntry *fibEntry = fib_MatchName(fib, ll->related_prefixes[i]); - if(fibEntry != NULL){ - mapme_maybe_send_updates(mapme, fibEntry, nexthops); - } - } - } -} - -static void strategyLowLatency_SelectBestFaces(StrategyLowLatency *ll, - bool new_round){ - - StrategyNexthopStateLL * old_faces[2]; - old_faces[0] = ll->bestFaces[0]; - old_faces[1] = ll->bestFaces[1]; - - if(new_round){ - ll->round++; - } - - if(parcHashMap_Size(ll->strategy_state) == 0){ - ll->bestFaces[0] = NULL; - ll->bestFaces[1] = NULL; - ll->use2paths = false; - goto NEW_ROUND; - } - - if(ll->use2paths && ll->bestFaces[0] != NULL && ll->bestFaces[1] != NULL){ - //multipath case - - if(!strategyNexthopStateLL_IsLossy(ll->bestFaces[0]) - && !strategyNexthopStateLL_IsLossy(ll->bestFaces[1]) - && strategyNexthopStateLL_IsAllowed(ll->bestFaces[0]) - && strategyNexthopStateLL_IsAllowed(ll->bestFaces[1])){ - - if(ll->rounds_in_multipath < MAX_ROUNDS_MP_WITHOUT_CHECK){ - //we are at the first rounds of the multipath let's wait a bit - //(MAX_ROUNDS_MP_WITHOUT_CHECK) to make the queuing converge - ll->rounds_in_multipath++; - goto NEW_ROUND; - } - - //we need to decide if we want ot keep using two paths or not - ll->rounds_in_multipath++; - double rtt0 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]); - double rtt1 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]); - double diff = fabs(rtt0 - rtt1); - - if(diff < MAX_LATENCY_DIFF){ - //everything is working, keep using the two paths - ll->rounds_with_error = 0; - goto NEW_ROUND; - } - - //check for how many rounds we had problems - if(ll->rounds_with_error < MAX_ROUNDS_WITH_ERROR && - diff < MAX_TOLLERATED_LATENCY_DIFF){ - //we can tollerate few round with errors - ll->rounds_with_error++; - goto NEW_ROUND; - } - - //prevent the usage of multiple paths - ll->rounds_with_error = 0; - ll->avoid_multipath = true; - ll->rounds_avoiding_multipath = 0; - } //else - //at least one of the two path is lossy - //or it is not allowed by the policies. - //search for a better possibility - } - - ll->bestFaces[0] = NULL; - ll->bestFaces[1] = NULL; - - //check if there is at least one non lossy connection - PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); - bool check_losses = true; - bool found_good_face = false; - while(parcIterator_HasNext(iterator) && !found_good_face){ - PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); - const StrategyNexthopStateLL *state = parcHashMap_Get(ll->strategy_state, cid); - if(!strategyNexthopStateLL_IsLossy(state) && - strategyNexthopStateLL_IsAllowed(state)){ - found_good_face = true; - } - } - parcIterator_Release(&iterator); - if(!found_good_face){ - // all the available faces are lossy, so we take into account only - // the latency computed with the probes - check_losses = false; - } - - if(ll->bestFaces[0] == NULL){ - //try to take a random face - PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); - bool face_found = false; - while(parcIterator_HasNext(iterator) && !face_found) { - PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); - StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) - parcHashMap_Get(ll->strategy_state, cid); - - if((check_losses && strategyNexthopStateLL_IsLossy(state)) || - !strategyNexthopStateLL_IsAllowed(state)){ - //skip the face - continue; - } - - ll->bestFaces[0] = state; - face_found = true; - } - parcIterator_Release(&iterator); - } - - if(ll->bestFaces[0] == NULL){ - //no usable face exists - ll->bestFaces[0] = NULL; - ll->bestFaces[1] = NULL; - ll->use2paths = false; - goto NEW_ROUND; - } - - double bestRtt = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]); - - if(ll->avoid_multipath) - ll->rounds_avoiding_multipath++; - - if(ll->rounds_avoiding_multipath > MAX_ROUNDS_AVOIDING_MULTIPATH){ - ll->avoid_multipath = false; - ll->rounds_avoiding_multipath = 0; - } - - iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); - while (parcIterator_HasNext(iterator)) { - - PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); - StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) - parcHashMap_Get(ll->strategy_state, cid); - double rtt = strategyNexthopStateLL_GetRTTLive(state); - - if((check_losses && strategyNexthopStateLL_IsLossy(state)) || - !strategyNexthopStateLL_IsAllowed(state)){ - //skip the face - continue; - } - - if(rtt + STABILITY_FACTOR < bestRtt){ - //maybe we found a better face - double rttInUse = strategyNexthopStateLL_GetRTTInUse(state); - unsigned try = strategyNexthopStateLL_GetTryToSwitch(state); - - //we check the rtt in use to check if the new face that we found - //gets congested when we use it to send the traffic - if(rttInUse < bestRtt || try > MAX_SWITCH_TRY){ - //we have a new best face! - strategyNexthopStateLL_ResetTryToSwitch((StrategyNexthopStateLL*) state); - bestRtt = rtt; - if(ll->bestFaces[0] != NULL) - strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[0]); - ll->bestFaces[0] = (StrategyNexthopStateLL*) state; - }else{ - //in this case we should switch but we wait MAX_SWITCH_TRY - //before switch to avoid ossillations between different paths - strategyNexthopStateLL_IncreaseTryToSwitch( - (StrategyNexthopStateLL*) state, ll->round); - } - } - } - - parcIterator_Release(&iterator); - - if(ll->bestFaces[0] == NULL){ - //we found no face so return - ll->bestFaces[0] = NULL; - ll->bestFaces[1] = NULL; - ll->use2paths = false; - goto NEW_ROUND; - } - - if(parcHashMap_Size(ll->strategy_state) == 1 || ll->avoid_multipath){ - //in this case (one face available or avoid multipath) we stop the - //search here. Just reset face 1 if needed - if(ll->bestFaces[1] != NULL){ - strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); - ll->bestFaces[1] = NULL; - } - ll->use2paths = false; - goto NEW_ROUND; - } - - //if we are here we have more than 1 interface, so we search for a second one - //to use in case of multipath - iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); - while (parcIterator_HasNext(iterator)) { - PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); - if(parcUnsigned_GetUnsigned(cid) != - strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])){ - - StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) - parcHashMap_Get(ll->strategy_state, cid); - - if((check_losses && strategyNexthopStateLL_IsLossy(state)) || - !strategyNexthopStateLL_IsAllowed(state)){ - //skip the face - continue; - } - - if(ll->bestFaces[1] == NULL){ - //in case of 2 faces we should pass always here - ll->bestFaces[1] = state; - }else{ - //TODO this must be tested with more then 2 faces - double rtt1 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]); - double rttNewFace = strategyNexthopStateLL_GetRTTLive(state); - if(rttNewFace + STABILITY_FACTOR < rtt1){ - strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); - ll->bestFaces[1] = state; - } - } - } - } - parcIterator_Release(&iterator); - - if(ll->bestFaces[1] != NULL){ - //we are not using the second face yet so we use the normal rtt for comparison - double rtt0 = strategyNexthopStateLL_GetRTTProbe(ll->bestFaces[0]); - double rtt1 = strategyNexthopStateLL_GetRTTProbe(ll->bestFaces[1]); - double diff = fabs(rtt0 - rtt1); - if(diff < MAX_LATENCY_DIFF) { - //let's start to use 2 paths - ll->rounds_with_error = 0; - ll->use2paths = true; - ll->rounds_in_multipath = 0; - }else{ - //we use only one path - strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); - ll->bestFaces[1] = NULL; - ll->use2paths = false; - } - }else{ - ll->use2paths = false; - } - - NEW_ROUND: - { - Logger * log = forwarder_GetLogger(ll->forwarder); - if(log != NULL && - logger_IsLoggable(log, LoggerFacility_Strategy, PARCLogLevel_Info)){ - if(ll->use2paths){ - logger_Log(log, LoggerFacility_Strategy, PARCLogLevel_Info, - __func__, "use 2 paths. rtt face %d = %f queue = %f is_lossy = %d," - "rtt face %d = %f queue = %f is_lossy = %d\n", - strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]), - strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]), - strategyNexthopStateLL_GetQueuing(ll->bestFaces[0]), - strategyNexthopStateLL_IsLossy(ll->bestFaces[0]), - strategyNexthopStateLL_GetFaceId(ll->bestFaces[1]), - strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]), - strategyNexthopStateLL_GetQueuing(ll->bestFaces[1]), - strategyNexthopStateLL_IsLossy(ll->bestFaces[1])); - }else{ - if(ll->bestFaces[0] != NULL){ - logger_Log(log, LoggerFacility_Strategy, - PARCLogLevel_Info, __func__, - "use 1 path. rtt face %d = %f is_lossy = %d, " - "(avoid multipath = %d)\n", - strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]), - strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]), - strategyNexthopStateLL_IsLossy(ll->bestFaces[0]), - ll->avoid_multipath); - }else{ - logger_Log(log, LoggerFacility_Strategy, PARCLogLevel_Info, - __func__, "no face to use!\n"); - } - } - } - } - - //update the round only at the end for all the faces - if(new_round){ - PARCIterator * iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); - while (parcIterator_HasNext(iterator)) { - PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); - strategyNexthopStateLL_StartNewRound((StrategyNexthopStateLL *) - parcHashMap_Get(ll->strategy_state, cid)); - } - parcIterator_Release(&iterator); - } - - //mapme updates - //if ll->bestFaces[0] == NULL we don't have any output faces - //so don't need to send any updates since we are disconnected - if(ll->related_prefixes_len != 0){ - if(ll->bestFaces[0] != NULL){ - NumberSet *out = numberSet_Create(); - if(old_faces[0] == NULL || - (strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]) != - strategyNexthopStateLL_GetFaceId(old_faces[0]))){ - //there is a new face 0 so we need a map me update - //if ll->bestFaces[1] != NULL we need to send the update - //even if it is the same as before - numberSet_Add(out, - strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); - if(ll->bestFaces[1] != NULL){ - numberSet_Add(out, - strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); - } - strategyLowLatency_SendMapmeUpdate(ll,out); - }else{ - if(ll->bestFaces[1] != NULL){ - if(old_faces[1] == NULL || - (strategyNexthopStateLL_GetFaceId(ll->bestFaces[1]) != - strategyNexthopStateLL_GetFaceId(old_faces[1]))){ - //send a mapme both with face 0 and face 1 - numberSet_Add(out, - strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); - numberSet_Add(out, - strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); - strategyLowLatency_SendMapmeUpdate(ll,out); - } - }else{ - if(old_faces[1] != NULL){ - //in the previuos round we were using two faces, now only one - //send update with only face 0 - numberSet_Add(out, - strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); - strategyLowLatency_SendMapmeUpdate(ll,out); - } - } - } - numberSet_Release(&out); - } - } -} - -static void strategyLowLatency_BestFaceCB(int fd, PARCEventType which_event, - void *data){ - parcAssertTrue(which_event & PARCEventType_Timeout, - "Event incorrect, expecting %X set, got %X", - PARCEventType_Timeout, which_event); - - StrategyLowLatency * ll = (StrategyLowLatency *) data; - strategyLowLatency_SelectBestFaces(ll, true); - - struct timeval timeout = {0, 500000}; - parcEventTimer_Start(ll->computeBestFace, &timeout); -} - -StrategyImpl *strategyLowLatency_Create() { - StrategyLowLatency *strategy = - parcMemory_AllocateAndClear(sizeof(StrategyLowLatency)); - parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(StrategyLowLatency)); - - strategy->strategy_state = parcHashMap_Create(); - strategy->pending_probes_ticks = parcHashMap_Create(); - strategy->pending_probes_faces = parcHashMap_Create(); -#ifndef WITH_POLICY - strategy->nexthops = numberSet_Create(); -#endif /* ! WITH_POLICY */ - srand((unsigned int)time(NULL)); - - StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl)); - parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(StrategyImpl)); - memcpy(impl, &_template, sizeof(StrategyImpl)); - impl->context = strategy; - - return impl; -} - -void strategyLowLatency_SetStrategy(StrategyImpl *strategy, - const Forwarder * forwarder, - const FibEntry * fibEntry, - unsigned related_prefixes_len, - Name **related_prefixes) { - StrategyLowLatency *ll = - (StrategyLowLatency *)strategy->context; - ll->forwarder = forwarder; - - //create probe packet - ll->probe = messageHandler_CreateProbePacket(HF_INET6_TCP, PROBE_LIFETIME); - ip_prefix_t address; - nameBitvector_ToIPAddress(name_GetContentName( - fibEntry_GetPrefix(fibEntry)), &address); - ll->name = messageHandler_CreateProbeName(&address); - - - Dispatcher *dispatcher = forwarder_GetDispatcher((Forwarder *)ll->forwarder); - ll->sendProbes = dispatcher_CreateTimer(dispatcher, false, - strategyLowLatency_SendProbesCB, ll); - - ll->round = 0; - ll->rounds_in_multipath = 0; - ll->rounds_with_error = 0; - ll->rounds_avoiding_multipath = 0; - ll->use2paths = false; - ll->avoid_multipath = false; - - ll->related_prefixes_len = related_prefixes_len; - ll->related_prefixes = malloc(sizeof(Name *) * ll->related_prefixes_len); - for(unsigned i = 0; i < ll->related_prefixes_len; i++){ - ll->related_prefixes[i] = name_Copy(related_prefixes[i]); - } - - ll->computeBestFace = dispatcher_CreateTimer(dispatcher, false, - strategyLowLatency_BestFaceCB, ll); -} - -void _startTimers(StrategyImpl *strategy){ - StrategyLowLatency *ll = - (StrategyLowLatency *)strategy->context; - - struct timeval timeoutProbes = {0,10000}; - parcEventTimer_Start(ll->sendProbes, &timeoutProbes); - struct timeval timeoutBF = {1,0}; - parcEventTimer_Start(ll->computeBestFace, &timeoutBF); -} - -void _stopTimers(StrategyImpl *strategy){ - StrategyLowLatency *ll = - (StrategyLowLatency *)strategy->context; - - parcEventTimer_Stop(ll->sendProbes); - parcEventTimer_Stop(ll->computeBestFace); -} - -// ======================================================= -// Dispatch API - -strategy_type _strategyLowLatency_GetStrategy(StrategyImpl *strategy) { - return SET_STRATEGY_LOW_LATENCY; -} - -static void _strategyLowLatency_ReceiveObject(StrategyImpl *strategy, - const NumberSet *egressId, - const Message *objectMessage, - Ticks pitEntryCreation, - Ticks objReception) { - StrategyLowLatency *ll = (StrategyLowLatency *)strategy->context; - - if(!messageHandler_IsAProbe(message_FixedHeader(objectMessage))) - return; - - uint32_t seq = messageHandler_GetSegment(message_FixedHeader(objectMessage)); - PARCUnsigned *parc_seq = parcUnsigned_Create(seq); - if (!parcHashMap_Contains(ll->pending_probes_ticks, parc_seq)){ - parcUnsigned_Release(&parc_seq); - return; - } - - //here numberSet_Length(egressId) should be 1 - for (unsigned i = 0; i < numberSet_Length(egressId); i++) { - unsigned outId = numberSet_GetItem(egressId, i); - PARCUnsigned *cid = parcUnsigned_Create(outId); - - const StrategyNexthopStateLL *state = - parcHashMap_Get(ll->strategy_state, cid); - if (state != NULL) { - Ticks time = parcUnsigned_GetUnsigned( - parcHashMap_Get(ll->pending_probes_ticks, parc_seq)); - Ticks now = forwarder_GetTicks(ll->forwarder); - Ticks RTT = now - time; - if(RTT <= 0) - RTT = 1; - strategyNexthopStateLL_AddRttSample( - (StrategyNexthopStateLL *) state, (unsigned int)RTT); - parcHashMap_Remove(ll->pending_probes_ticks, parc_seq); - } else { - // this may happen if we remove a face/route while downloading a file - // we should ignore this timeout - } - parcUnsigned_Release(&cid); - } - parcUnsigned_Release(&parc_seq); -} - -static void _strategyLowLatency_OnTimeout(StrategyImpl *strategy, - const NumberSet *egressId) {} - -static NumberSet *_strategyLowLatency_LookupNexthop(StrategyImpl *strategy, -#ifdef WITH_POLICY - NumberSet * nexthops, -#endif /* WITH_POLICY */ - const Message *interestMessage) { - //unsigned out_connection; - NumberSet *out = numberSet_Create(); - - StrategyLowLatency *ll = (StrategyLowLatency *)strategy->context; - - //update is_allowed flag of all the next hops - PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); - while(parcIterator_HasNext(iterator)){ - PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); - StrategyNexthopStateLL *state = - (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); - if(numberSet_Contains(nexthops, parcUnsigned_GetUnsigned(cid))){ - strategyNexthopStateLL_SetIsAllowed(state,true); - }else{ - strategyNexthopStateLL_SetIsAllowed(state,false); - } - } - parcIterator_Release(&iterator); - - if(ll->bestFaces[0] != NULL && - !strategyNexthopStateLL_IsAllowed(ll->bestFaces[0])){ - //if ll->bestFaces[0] is not allowed we need to find a new face - strategyLowLatency_SelectBestFaces(ll, false); - } - - //at this point ll->bestFaces[0] must be allowed - //single path case - if(ll->bestFaces[0] != NULL && (ll->bestFaces[1] == NULL || !ll->use2paths)){ - strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); - numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); - - //multipath case - }else if(ll->bestFaces[0] != NULL && ll->bestFaces[1] != NULL && ll->use2paths){ - //it may happen that ll->bestFaces[1] is not allowed, in that case we send on - //ll->bestFaces[0] until the next best face selection - if(!strategyNexthopStateLL_IsAllowed(ll->bestFaces[1])){ - strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); - numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); - }else{ - double queue0 = strategyNexthopStateLL_GetQueuing(ll->bestFaces[0]); - double queue1 = strategyNexthopStateLL_GetQueuing(ll->bestFaces[1]); - double prob0 = 0.5; - if(queue0 > 1 || queue1 > 1){ - prob0 = 1.0 - (queue0 / (queue0 + queue1)); - } - double coin = ((double) rand() / (RAND_MAX)); - if(coin < prob0){ - strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); - numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); - }else{ - strategyNexthopStateLL_SendPacket(ll->bestFaces[1]); - numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); - } - } - } - return out; -} - - -#ifndef WITH_POLICY -static NumberSet *_strategyLowLatency_ReturnNexthops(StrategyImpl *strategy) { - StrategyLoadBalancerLL *ll = (StrategyLoadBalancerLL *)strategy->context; - return ll->nexthops; -} - -unsigned _strategyLowLatency_CountNexthops(StrategyImpl *strategy) { - StrategyLoadBalancerLL *ll = (StrategyLoadBalancerLL *)strategy->context; - return (unsigned)numberSet_Length(ll->nexthops); -} -#endif /* ! WITH_POLICY */ - -static void _strategyLowLatency_AddNexthop(StrategyImpl *strategy, - unsigned connectionId) { - PARCUnsigned *cid = parcUnsigned_Create(connectionId); - - StrategyLowLatency *ll = (StrategyLowLatency *)strategy->context; - - if (!parcHashMap_Contains(ll->strategy_state, cid)) { - StrategyNexthopStateLL *state = strategyNexthopStateLL_Create(connectionId); - parcHashMap_Put(ll->strategy_state, cid, state); - if(ll->bestFaces[0] == NULL){ - ll->bestFaces[0] = state; - } -#ifndef WITH_POLICY - numberSet_Add(ll->nexthops, connectionId); -#endif /* WITH_POLICY */ - } - - if(parcHashMap_Size(ll->strategy_state) >= 2){ - _startTimers(strategy); - } - - parcUnsigned_Release(&cid); -} - -static void _strategyLowLatency_RemoveNexthop(StrategyImpl *strategy, - unsigned connectionId) { - StrategyLowLatency *ll = (StrategyLowLatency *)strategy->context; - - bool reset_bestFaces = false; - - if((ll->bestFaces[0] != NULL && - strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]) == connectionId) || - (ll->bestFaces[1] != NULL && - strategyNexthopStateLL_GetFaceId(ll->bestFaces[1]) == connectionId)){ - reset_bestFaces = true; - } - - PARCUnsigned *cid = parcUnsigned_Create(connectionId); - - if (parcHashMap_Contains(ll->strategy_state, cid)) { - parcHashMap_Remove(ll->strategy_state, cid); -#ifndef WITH_POLICY - numberSet_Remove(lb->nexthops, connectionId); -#endif /* WITH_POLICY */ - } - - if(reset_bestFaces){ - ll->bestFaces[0] = NULL; - ll->bestFaces[1] = NULL; - strategyLowLatency_SelectBestFaces(ll, false); - } - - if(parcHashMap_Size(ll->strategy_state) < 2){ - _stopTimers(strategy); - } - - parcUnsigned_Release(&cid); -} - -static void _strategyLowLatency_ImplDestroy(StrategyImpl **strategyPtr) { - parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*strategyPtr, - "Parameter must dereference to non-null pointer"); - - StrategyImpl *impl = *strategyPtr; - StrategyLowLatency *strategy = (StrategyLowLatency *)impl->context; - - _stopTimers(impl); - - parcEventTimer_Destroy(&(strategy->sendProbes)); - parcEventTimer_Destroy(&(strategy->computeBestFace)); - - if (parcHashMap_Size(strategy->strategy_state) > 0) { - PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state); - while (parcIterator_HasNext(it)) { - PARCUnsigned *cid = parcIterator_Next(it); - StrategyNexthopStateLL *state = - (StrategyNexthopStateLL *)parcHashMap_Get(strategy->strategy_state, cid); - parcObject_Release((void**)&state); - } - parcIterator_Release(&it); - } - - parcHashMap_Release(&(strategy->strategy_state)); - parcHashMap_Release(&(strategy->pending_probes_ticks)); - parcHashMap_Release(&(strategy->pending_probes_faces)); - - parcMemory_Deallocate(&(strategy->probe)); - parcMemory_Deallocate(&(strategy->name)); - - for(unsigned i = 0; i < strategy->related_prefixes_len; i++){ - name_Release(&(strategy->related_prefixes[i])); - } - free(strategy->related_prefixes); - -#ifndef WITH_POLICY - numberSet_Release(&(strategy->nexthops)); -#endif /* ! WITH_POLICY */ - - parcMemory_Deallocate((void **)&strategy); - parcMemory_Deallocate((void **)&impl); - *strategyPtr = NULL; -} diff --git a/hicn-light/src/hicn/strategies/lowLatency.h b/hicn-light/src/hicn/strategies/lowLatency.h deleted file mode 100644 index 736c8783d..000000000 --- a/hicn-light/src/hicn/strategies/lowLatency.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * Forward on the path with lowest latency - */ - -#ifndef lowLatency_h -#define lowLatency_h - -#include <hicn/strategies/strategyImpl.h> -#include <hicn/core/forwarder.h> - -StrategyImpl *strategyLowLatency_Create(); - -void strategyLowLatency_SetStrategy(StrategyImpl *strategy, - const Forwarder * forwarder, - const FibEntry * fibEntry, - unsigned related_prefixes_len, - Name **related_prefixes); -#endif // lowLatency_h diff --git a/hicn-light/src/hicn/strategies/low_latency.c b/hicn-light/src/hicn/strategies/low_latency.c new file mode 100644 index 000000000..1e5a74c1a --- /dev/null +++ b/hicn-light/src/hicn/strategies/low_latency.c @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2021 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. + */ + +#if 0 + +#include <hicn/hicn-light/config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> + +#include <hicn/base/khash.h> + +#include <parc/assert/parc_Assert.h> +#include <parc/algol/parc_HashMap.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_Object.h> +#include <parc/algol/parc_Unsigned.h> + +#include <hicn/core/messageHandler.h> + +#include "low_latency.h" + +#define STABILITY_FACTOR 15 +#define MAX_SWITCH_TRY 10 +#define MAX_LATENCY_DIFF 10 +#define MAX_TOLLERATED_LATENCY_DIFF 15 +#define MAX_ROUNDS_MP_WITHOUT_CHECK 2 +#define MAX_ROUNDS_AVOIDING_MULTIPATH 40 /* about 20 sec */ +#define MAX_ROUNDS_WITH_ERROR 4 +#define PROBE_LIFETIME 500 /* ms */ + +#define MAX_ROUNS_WITHOUT_PROBES 4 + +/* + * If we do not receives probes for 4 rounds it means that we had no responce + * from any producer for 2 sec we can say that this interface is daed + */ +#define MIN_NON_LOSSY_ROUNDS 10 + +/* + * Number of rounds in non lossy mode before switch to no lossy state + * Defaults to 10 % + */ +#define MAX_LOSS_RATE 0.10 + +/* Shorthands */ +#define nexthop_state_t strategy_low_latency_nexthop_state_t +#define state_t strategy_low_latency_state_t + +#define NEXTHOP_STATE_INIT \ + { \ + .in_use = false, .is_allowed = true, .sent_packets = 0, \ + .last_try_to_switch_round = 0, .try_to_switch_counter = 0, \ + .recevied_probes = 0, .rounds_without_probes = 0, .sent_probes = 0, \ + .lost_probes = 0, .non_lossy_rounds = MIN_NON_LOSSY_ROUNDS, \ + .avg_rtt = -1.0, .avg_rtt_in_use = -1.0, .avg_queue = 0.0001, \ + .avg_loss_rate = 0.0, \ + } + +// XXX ???? +#define STATE_INIT \ + {} + +static + void +strategy_low_latency_SendProbesCB(int fd, PARCEventType which_event, void *data) +{ + parcAssertTrue(which_event & PARCEventType_Timeout, + "Event incorrect, expecting %X set, got %X", + PARCEventType_Timeout, which_event); + + StrategyLowLatency *ll = (StrategyLowLatency *) data; + + //delete old pending probes + if(parcHashMap_Size(ll->pending_probes_ticks) != 0){ + Ticks now = forwarder_GetTicks(ll->forwarder); + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->pending_probes_ticks); + NumberSet *to_remove = numberSet_Create(); + while(parcIterator_HasNext(iterator)) { + PARCUnsigned *parc_seq = (PARCUnsigned *) parcIterator_Next(iterator); + PARCUnsigned *parc_time = (PARCUnsigned *) parcHashMap_Get(ll->pending_probes_ticks, parc_seq); + Ticks sent_time = parcUnsigned_GetUnsigned(parc_time); + if((now - sent_time) > PROBE_LIFETIME){ + //probes to delete + numberSet_Add(to_remove, parcUnsigned_GetUnsigned(parc_seq)); + } + } + parcIterator_Release(&iterator); + + for(int i = 0; i < numberSet_Length(to_remove); i++){ + PARCUnsigned *prob_seq = parcUnsigned_Create(numberSet_GetItem(to_remove,i)); + PARCUnsigned *cid = (PARCUnsigned *) parcHashMap_Get(ll->pending_probes_faces, prob_seq); + StrategyNexthopStateLL *state = + (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); + strategyNexthopStateLL_LostProbe(state); + parcHashMap_Remove(ll->pending_probes_ticks, prob_seq); + parcHashMap_Remove(ll->pending_probes_faces, prob_seq); + parcUnsigned_Release(&prob_seq); + } + numberSet_Release(&to_remove); + } + + ConnectionTable * ct = forwarder_GetConnectionTable(ll->forwarder); + + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while(parcIterator_HasNext(iterator)){ + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + Connection *conn = + (Connection *)connectionTable_FindById(ct, + parcUnsigned_GetUnsigned(cid)); + if(!conn) + continue; + + StrategyNexthopStateLL *state = + (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); + + //probe only usable paths + if(!strategyNexthopStateLL_IsAllowed(state)) + continue; + + uint32_t seq = rand(); + messageHandler_SetProbeName(ll->probe, HF_INET6_TCP, + ll->name, seq); + connection_Probe(conn, ll->probe); + + PARCUnsigned *parc_seq = parcUnsigned_Create(seq); + Ticks now = forwarder_GetTicks(ll->forwarder); + PARCUnsigned *parc_time = parcUnsigned_Create((unsigned int)now); + parcHashMap_Put(ll->pending_probes_ticks, parc_seq, parc_time); + parcHashMap_Put(ll->pending_probes_faces, parc_seq, cid); + strategyNexthopStateLL_SentProbe(state); + parcUnsigned_Release(&parc_seq); + parcUnsigned_Release(&parc_time); + } + parcIterator_Release(&iterator); + + struct timeval timeout = {0,50000}; + parcEventTimer_Start(ll->sendProbes, &timeout); +} + +static +void +strategy_low_latency_SendMapmeUpdate(StrategyLowLatency *ll, + const NumberSet * nexthops){ + MapMe * mapme = forwarder_getMapmeInstance(ll->forwarder); + FIB * fib = forwarder_getFib((Forwarder*) ll->forwarder); + for(unsigned i = 0; i < ll->related_prefixes_len; i++){ + FibEntry *fibEntry = fib_MatchName(fib, ll->related_prefixes[i]); + if (!fibEntry) + continue; + mapme_maybe_send_to_nexthops(mapme, fibEntry, nexthops); + } +} + +static +void +strategy_low_latency_SelectBestFaces(StrategyLowLatency *ll, bool new_round) +{ + + StrategyNexthopStateLL * old_faces[2]; + old_faces[0] = ll->bestFaces[0]; + old_faces[1] = ll->bestFaces[1]; + + if(new_round){ + ll->round++; + } + + if(parcHashMap_Size(ll->strategy_state) == 0){ + ll->bestFaces[0] = NULL; + ll->bestFaces[1] = NULL; + ll->use2paths = false; + goto NEW_ROUND; + } + + if(ll->use2paths && ll->bestFaces[0] != NULL && ll->bestFaces[1] != NULL){ + //multipath case + + if(!strategyNexthopStateLL_IsLossy(ll->bestFaces[0]) + && !strategyNexthopStateLL_IsLossy(ll->bestFaces[1]) + && strategyNexthopStateLL_IsAllowed(ll->bestFaces[0]) + && strategyNexthopStateLL_IsAllowed(ll->bestFaces[1])){ + + if(ll->rounds_in_multipath < MAX_ROUNDS_MP_WITHOUT_CHECK){ + //we are at the first rounds of the multipath let's wait a bit + //(MAX_ROUNDS_MP_WITHOUT_CHECK) to make the queuing converge + ll->rounds_in_multipath++; + goto NEW_ROUND; + } + + //we need to decide if we want ot keep using two paths or not + ll->rounds_in_multipath++; + double rtt0 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]); + double rtt1 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]); + double diff = fabs(rtt0 - rtt1); + + if(diff < MAX_LATENCY_DIFF){ + //everything is working, keep using the two paths + ll->rounds_with_error = 0; + goto NEW_ROUND; + } + + //check for how many rounds we had problems + if(ll->rounds_with_error < MAX_ROUNDS_WITH_ERROR && + diff < MAX_TOLLERATED_LATENCY_DIFF){ + //we can tollerate few round with errors + ll->rounds_with_error++; + goto NEW_ROUND; + } + + //prevent the usage of multiple paths + ll->rounds_with_error = 0; + ll->avoid_multipath = true; + ll->rounds_avoiding_multipath = 0; + } //else + //at least one of the two path is lossy + //or it is not allowed by the policies. + //search for a better possibility + } + + ll->bestFaces[0] = NULL; + ll->bestFaces[1] = NULL; + + //check if there is at least one non lossy connection + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + bool check_losses = true; + bool found_good_face = false; + while(parcIterator_HasNext(iterator) && !found_good_face){ + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + const StrategyNexthopStateLL *state = parcHashMap_Get(ll->strategy_state, cid); + if(!strategyNexthopStateLL_IsLossy(state) && + strategyNexthopStateLL_IsAllowed(state)){ + found_good_face = true; + } + } + parcIterator_Release(&iterator); + if(!found_good_face){ + // all the available faces are lossy, so we take into account only + // the latency computed with the probes + check_losses = false; + } + + if(ll->bestFaces[0] == NULL){ + //try to take a random face + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + bool face_found = false; + while(parcIterator_HasNext(iterator) && !face_found) { + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) + parcHashMap_Get(ll->strategy_state, cid); + + if((check_losses && strategyNexthopStateLL_IsLossy(state)) || + !strategyNexthopStateLL_IsAllowed(state)){ + //skip the face + continue; + } + + ll->bestFaces[0] = state; + face_found = true; + } + parcIterator_Release(&iterator); + } + + if(ll->bestFaces[0] == NULL){ + //no usable face exists + ll->bestFaces[0] = NULL; + ll->bestFaces[1] = NULL; + ll->use2paths = false; + goto NEW_ROUND; + } + + double bestRtt = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]); + + if(ll->avoid_multipath) + ll->rounds_avoiding_multipath++; + + if(ll->rounds_avoiding_multipath > MAX_ROUNDS_AVOIDING_MULTIPATH){ + ll->avoid_multipath = false; + ll->rounds_avoiding_multipath = 0; + } + + iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while (parcIterator_HasNext(iterator)) { + + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) + parcHashMap_Get(ll->strategy_state, cid); + double rtt = strategyNexthopStateLL_GetRTTLive(state); + + if((check_losses && strategyNexthopStateLL_IsLossy(state)) || + !strategyNexthopStateLL_IsAllowed(state)){ + //skip the face + continue; + } + + if(rtt + STABILITY_FACTOR < bestRtt){ + //maybe we found a better face + double rttInUse = strategyNexthopStateLL_GetRTTInUse(state); + unsigned try = strategyNexthopStateLL_GetTryToSwitch(state); + + //we check the rtt in use to check if the new face that we found + //gets congested when we use it to send the traffic + if(rttInUse < bestRtt || try > MAX_SWITCH_TRY){ + //we have a new best face! + strategyNexthopStateLL_ResetTryToSwitch((StrategyNexthopStateLL*) state); + bestRtt = rtt; + if(ll->bestFaces[0] != NULL) + strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[0]); + ll->bestFaces[0] = (StrategyNexthopStateLL*) state; + }else{ + //in this case we should switch but we wait MAX_SWITCH_TRY + //before switch to avoid ossillations between different paths + strategyNexthopStateLL_IncreaseTryToSwitch( + (StrategyNexthopStateLL*) state, ll->round); + } + } + } + + parcIterator_Release(&iterator); + + if(ll->bestFaces[0] == NULL){ + //we found no face so return + ll->bestFaces[0] = NULL; + ll->bestFaces[1] = NULL; + ll->use2paths = false; + goto NEW_ROUND; + } + + if(parcHashMap_Size(ll->strategy_state) == 1 || ll->avoid_multipath){ + //in this case (one face available or avoid multipath) we stop the + //search here. Just reset face 1 if needed + if(ll->bestFaces[1] != NULL){ + strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); + ll->bestFaces[1] = NULL; + } + ll->use2paths = false; + goto NEW_ROUND; + } + + //if we are here we have more than 1 interface, so we search for a second one + //to use in case of multipath + iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while (parcIterator_HasNext(iterator)) { + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + if(parcUnsigned_GetUnsigned(cid) != + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])){ + + StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) + parcHashMap_Get(ll->strategy_state, cid); + + if((check_losses && strategyNexthopStateLL_IsLossy(state)) || + !strategyNexthopStateLL_IsAllowed(state)){ + //skip the face + continue; + } + + if(ll->bestFaces[1] == NULL){ + //in case of 2 faces we should pass always here + ll->bestFaces[1] = state; + }else{ + //TODO this must be tested with more then 2 faces + double rtt1 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]); + double rttNewFace = strategyNexthopStateLL_GetRTTLive(state); + if(rttNewFace + STABILITY_FACTOR < rtt1){ + strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); + ll->bestFaces[1] = state; + } + } + } + } + parcIterator_Release(&iterator); + + if(ll->bestFaces[1] != NULL){ + //we are not using the second face yet so we use the normal rtt for comparison + double rtt0 = strategyNexthopStateLL_GetRTTProbe(ll->bestFaces[0]); + double rtt1 = strategyNexthopStateLL_GetRTTProbe(ll->bestFaces[1]); + double diff = fabs(rtt0 - rtt1); + if(diff < MAX_LATENCY_DIFF) { + //let's start to use 2 paths + ll->rounds_with_error = 0; + ll->use2paths = true; + ll->rounds_in_multipath = 0; + }else{ + //we use only one path + strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); + ll->bestFaces[1] = NULL; + ll->use2paths = false; + } + }else{ + ll->use2paths = false; + } + +NEW_ROUND: + { + Logger * log = forwarder_GetLogger(ll->forwarder); + if(log != NULL && + logger_IsLoggable(log, LoggerFacility_Strategy, PARCLogLevel_Info)){ + if(ll->use2paths){ + logger_Log(log, LoggerFacility_Strategy, PARCLogLevel_Info, + __func__, "use 2 paths. rtt face %d = %f queue = %f is_lossy = %d," + "rtt face %d = %f queue = %f is_lossy = %d\n", + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]), + strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]), + strategyNexthopStateLL_GetQueuing(ll->bestFaces[0]), + strategyNexthopStateLL_IsLossy(ll->bestFaces[0]), + strategyNexthopStateLL_GetFaceId(ll->bestFaces[1]), + strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]), + strategyNexthopStateLL_GetQueuing(ll->bestFaces[1]), + strategyNexthopStateLL_IsLossy(ll->bestFaces[1])); + }else{ + if(ll->bestFaces[0] != NULL){ + logger_Log(log, LoggerFacility_Strategy, + PARCLogLevel_Info, __func__, + "use 1 path. rtt face %d = %f is_lossy = %d, " + "(avoid multipath = %d)\n", + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]), + strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]), + strategyNexthopStateLL_IsLossy(ll->bestFaces[0]), + ll->avoid_multipath); + }else{ + logger_Log(log, LoggerFacility_Strategy, PARCLogLevel_Info, + __func__, "no face to use!\n"); + } + } + } + } + + //update the round only at the end for all the faces + if(new_round){ + PARCIterator * iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while (parcIterator_HasNext(iterator)) { + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + strategyNexthopStateLL_StartNewRound((StrategyNexthopStateLL *) + parcHashMap_Get(ll->strategy_state, cid)); + } + parcIterator_Release(&iterator); + } + + //mapme updates + //if ll->bestFaces[0] == NULL we don't have any output faces + //so don't need to send any updates since we are disconnected + if(ll->related_prefixes_len != 0){ + if(ll->bestFaces[0] != NULL){ + NumberSet *out = numberSet_Create(); + if(old_faces[0] == NULL || + (strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]) != + strategyNexthopStateLL_GetFaceId(old_faces[0]))){ + //there is a new face 0 so we need a map me update + //if ll->bestFaces[1] != NULL we need to send the update + //even if it is the same as before + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + if(ll->bestFaces[1] != NULL){ + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); + } + strategy_low_latency_SendMapmeUpdate(ll,out); + }else{ + if(ll->bestFaces[1] != NULL){ + if(old_faces[1] == NULL || + (strategyNexthopStateLL_GetFaceId(ll->bestFaces[1]) != + strategyNexthopStateLL_GetFaceId(old_faces[1]))){ + //send a mapme both with face 0 and face 1 + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); + strategy_low_latency_SendMapmeUpdate(ll,out); + } + }else{ + if(old_faces[1] != NULL){ + //in the previuos round we were using two faces, now only one + //send update with only face 0 + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + strategy_low_latency_SendMapmeUpdate(ll,out); + } + } + } + numberSet_Release(&out); + } + } +} + +static +void +strategy_low_latency_BestFaceCB(int fd, PARCEventType which_event, void *data) +{ + parcAssertTrue(which_event & PARCEventType_Timeout, + "Event incorrect, expecting %X set, got %X", + PARCEventType_Timeout, which_event); + + StrategyLowLatency * ll = (StrategyLowLatency *) data; + strategy_low_latency_SelectBestFaces(ll, true); + + struct timeval timeout = {0, 500000}; + parcEventTimer_Start(ll->computeBestFace, &timeout); +} + +static +void +_startTimers(strategy_entry_t * entry) +{ + struct timeval timeoutProbes = {0, 10000}; + struct timeval timeoutBF = {1, 0}; + + parcEventTimer_Start(entry->state.sendProbes, &timeoutProbes); + parcEventTimer_Start(entry->state.computeBestFace, &timeoutBF); +} + +static +void +_stopTimers(strategy_entry_t * entry) +{ + parcEventTimer_Stop(entry->state.sendProbes); + parcEventTimer_Stop(entry->state.computeBestFace); +} + +static +void +strategy_low_latency_initialize(strategy_entry_t * entry) +{ + srand((unsigned int)time(NULL)); + + /* XXX TODO Three hashmaps to initialize */ + strategy->strategy_state = parcHashMap_Create(); + strategy->pending_probes_ticks = parcHashMap_Create(); + strategy->pending_probes_faces = parcHashMap_Create(); + + Dispatcher *dispatcher = forwarder_GetDispatcher((Forwarder *)ll->forwarder); + ip_prefix_t address; + nameBitvector_ToIPAddress(name_GetContentName( + fibEntry_GetPrefix(fibEntry)), &address); + + entry->state = { + .probe = messageHandler_CreateProbePacket(HF_INET6_TCP, PROBE_LIFETIME), + .name = messageHandler_CreateProbeName(&address); + .sendProbes = dispatcher_CreateTimer(dispatcher, false, + strategy_low_latency_SendProbesCB, ll); + .round = 0; + .rounds_in_multipath = 0; + .rounds_with_error = 0; + .rounds_avoiding_multipath = 0; + .use2paths = false; + .avoid_multipath = false; + .computeBestFace = dispatcher_CreateTimer(dispatcher, false, + strategy_low_latency_BestFaceCB, ll); + .related_prefixes_len = related_prefixes_len; + // XXX TODO + .related_prefixes = malloc(sizeof(Name *) * related_prefixes_len); + }; + + for(unsigned i = 0; i < entry->state.related_prefixes_len; i++){ + entry->state.related_prefixes[i] = name_Copy(related_prefixes[i]); + } +} + +static +void +strategy_low_latency_finalize(strategy_entry_t * entry) +{ + _stopTimers(entry); + + parcEventTimer_Destroy(&(strategy->sendProbes)); + parcEventTimer_Destroy(&(strategy->computeBestFace)); + + if (parcHashMap_Size(strategy->strategy_state) > 0) { + PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state); + while (parcIterator_HasNext(it)) { + PARCUnsigned *cid = parcIterator_Next(it); + StrategyNexthopStateLL *state = + (StrategyNexthopStateLL *)parcHashMap_Get(strategy->strategy_state, cid); + parcObject_Release((void**)&state); + } + parcIterator_Release(&it); + } + + parcHashMap_Release(&(strategy->strategy_state)); + parcHashMap_Release(&(strategy->pending_probes_ticks)); + parcHashMap_Release(&(strategy->pending_probes_faces)); + + parcMemory_Deallocate(&(strategy->probe)); + parcMemory_Deallocate(&(strategy->name)); + + for(unsigned i = 0; i < strategy->related_prefixes_len; i++){ + name_Release(&(strategy->related_prefixes[i])); + } + free(strategy->related_prefixes); + + parcMemory_Deallocate((void **)&strategy); + parcMemory_Deallocate((void **)&impl); + *strategyPtr = NULL; +} + +static +void +strategy_low_latency_add_nexthop(strategy_entry_t * entry, unsigned nexthop, nexthop_state_t * state) +{ + PARCUnsigned *cid = parcUnsigned_Create(connectionId); + + StrategyLowLatency *ll = (StrategyLowLatency *)strategy->context; + + if (!parcHashMap_Contains(ll->strategy_state, cid)) { + StrategyNexthopStateLL *state = strategyNexthopStateLL_Create(connectionId); + parcHashMap_Put(ll->strategy_state, cid, state); + if(ll->bestFaces[0] == NULL){ + ll->bestFaces[0] = state; + } + } + + if(parcHashMap_Size(ll->strategy_state) >= 2){ + _startTimers(strategy); + } + + parcUnsigned_Release(&cid); +} + +static +void +strategy_low_latency_remove_nexthop(strategy_entry_t * entry, unsigned nexthop, nexthop_state_t * state) +{ + bool reset_bestFaces = false; + + if((entry->state.bestFaces[0] != NULL && + strategyNexthopStateLL_GetFaceId(entry->state.bestFaces[0]) == connectionId) || + (entry->state.bestFaces[1] != NULL && + strategyNexthopStateLL_GetFaceId(entry->state.bestFaces[1]) == connectionId)){ + reset_bestFaces = true; + } + + PARCUnsigned *cid = parcUnsigned_Create(connectionId); + + if (parcHashMap_Contains(entry->state.strategy_state, cid)) { + parcHashMap_Remove(entry->state.strategy_state, cid); + } + + if(reset_bestFaces){ + entry->state.bestFaces[0] = NULL; + entry->state.bestFaces[1] = NULL; + strategy_low_latency_SelectBestFaces(ll, false); + } + + if(parcHashMap_Size(entry->state.strategy_state) < 2){ + _stopTimers(strategy); + } + + parcUnsigned_Release(&cid); +} + +static +nexthops_t * +strategy_low_latency_lookup_nexthops(strategy_entry_t * entry, + const msgbuf_t * msgbuf) +{ + //unsigned out_connection; + NumberSet *out = numberSet_Create(); + + StrategyLowLatency *ll = (StrategyLowLatency *)strategy->context; + + //update is_allowed flag of all the next hops + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while(parcIterator_HasNext(iterator)){ + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + StrategyNexthopStateLL *state = + (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); + if(numberSet_Contains(nexthops, parcUnsigned_GetUnsigned(cid))){ + strategyNexthopStateLL_SetIsAllowed(state,true); + }else{ + strategyNexthopStateLL_SetIsAllowed(state,false); + } + } + parcIterator_Release(&iterator); + + if(ll->bestFaces[0] != NULL && + !strategyNexthopStateLL_IsAllowed(ll->bestFaces[0])){ + //if ll->bestFaces[0] is not allowed we need to find a new face + strategy_low_latency_SelectBestFaces(ll, false); + } + + //at this point ll->bestFaces[0] must be allowed + //single path case + if(ll->bestFaces[0] != NULL && (ll->bestFaces[1] == NULL || !ll->use2paths)){ + strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); + numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + + //multipath case + }else if(ll->bestFaces[0] != NULL && ll->bestFaces[1] != NULL && ll->use2paths){ + //it may happen that ll->bestFaces[1] is not allowed, in that case we send on + //ll->bestFaces[0] until the next best face selection + if(!strategyNexthopStateLL_IsAllowed(ll->bestFaces[1])){ + strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); + numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + }else{ + double queue0 = strategyNexthopStateLL_GetQueuing(ll->bestFaces[0]); + double queue1 = strategyNexthopStateLL_GetQueuing(ll->bestFaces[1]); + double prob0 = 0.5; + if(queue0 > 1 || queue1 > 1){ + prob0 = 1.0 - (queue0 / (queue0 + queue1)); + } + double coin = ((double) rand() / (RAND_MAX)); + if(coin < prob0){ + strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); + numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + }else{ + strategyNexthopStateLL_SendPacket(ll->bestFaces[1]); + numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); + } + } + } + return out; +} + + + +static +void +strategy_low_latency_on_data(strategy_entry_t * entry, + const nexthops_t * nexthops, const msgbuf_t * msgbuf, + Ticks pitEntryCreation, Ticks objReception) +{ + if (!msgbuf_is_probe(msgbuf)) + return; + + uint32_t seq = messageHandler_GetSegment(message_FixedHeader(objectMessage)); + if (!parcHashMap_Contains(ll->pending_probes_ticks, seq)) + return; // unexpected + + /* A single nexthop is expected */ + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + const StrategyNexthopStateLL *state = + parcHashMap_Get(ll->strategy_state, nexthop); + if (!state) + // this may happen if we remove a face/route while downloading a file + // we should ignore this timeout + continue; + + Ticks time = parcUnsigned_GetUnsigned( + parcHashMap_Get(ll->pending_probes_ticks, seq)); + Ticks now = forwarder_GetTicks(ll->forwarder); + Ticks RTT = now - time; + if(RTT <= 0) + RTT = 1; + strategyNexthopStateLL_AddRttSample( + (StrategyNexthopStateLL *) state, (unsigned int)RTT); + parcHashMap_Remove(ll->pending_probes_ticks, seq); + } + }; +} + +static +void +strategy_low_latency_on_timeout(strategy_entry_t * entry, const nexthops_t * nexthops) +{ + /* Nothing to do */ +} + +DECLARE_STRATEGY(low_latency); + +#undef nexthop_state_t +#undef state_t + +#endif diff --git a/hicn-light/src/hicn/strategies/low_latency.h b/hicn-light/src/hicn/strategies/low_latency.h new file mode 100644 index 000000000..6b3001637 --- /dev/null +++ b/hicn-light/src/hicn/strategies/low_latency.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * Forward on the path with lowest latency + */ + +#ifndef HICNLIGHT_STRATEGY_LOW_LATENCY_H +#define HICNLIGHT_STRATEGY_LOW_LATENCY_H + +struct name_s; + +#include <hicn/strategy.h> + +typedef struct { + void *_; +} strategy_low_latency_nexthop_state_t; + +typedef struct { + void *_; +} strategy_low_latency_state_t; + +typedef struct { + // Name ** related_prefixes; + struct name_s *related_prefixes[MAX_FWD_STRATEGY_RELATED_PREFIXES]; + unsigned related_prefixes_len; +} strategy_low_latency_options_t; + +#if 0 + +/* + * We have global state in addition to state associated for each next hop : + */ +typedef struct { + bool in_use; + bool is_allowed; // XXX TODO the policy may not allow the use of this face +// unsigned face_id; + unsigned sent_packets; + /* switch metrics */ + unsigned last_try_to_switch_round; + unsigned try_to_switch_counter; + /* probes counters */ + unsigned recevied_probes; + unsigned rounds_without_probes; + unsigned sent_probes; + unsigned lost_probes; + unsigned non_lossy_rounds; + /* Averages */ + double avg_rtt; + double avg_rtt_in_use; + double avg_queue; + double avg_loss_rate; +} strategy_low_latency_nexthop_state_t; + +typedef struct { + // hash map from connectionId to StrategyNexthopStateLL + //PARCHashMap *strategy_state; + // XXX This is now store in each nexthop state + + /* + * Hhash map from sequence number to ticks (sent time) + * + * TODO improvement: the tick and face id could be stored in the probe and + * repeated in the reply to avoid state to be maintained. + * + * Also, in case we have few probes, linear scan might be more effective + */ + PARCHashMap *pending_probes_ticks; + + /* hash map from sequence number to face id */ + PARCHashMap *pending_probes_faces; + + const Forwarder * forwarder; + PARCEventTimer *sendProbes; + PARCEventTimer *computeBestFace; + uint8_t * probe; + hicn_name_t * name; + StrategyNexthopStateLL * bestFaces[2]; + unsigned round; + unsigned rounds_in_multipath; + unsigned rounds_with_error; + unsigned rounds_avoiding_multipath; + bool use2paths; + bool avoid_multipath; +} strategy_low_latency_state_t; + +#endif + +#endif /* HICNLIGHT_STRATEGY_LOW_LATENCY_H */ diff --git a/hicn-light/src/hicn/strategies/nexthopState.c b/hicn-light/src/hicn/strategies/nexthopState.c deleted file mode 100644 index 40af14832..000000000 --- a/hicn-light/src/hicn/strategies/nexthopState.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_DisplayIndented.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/strategies/nexthopState.h> - -#define AVG_PI_THRESHOLD 1e-3 - -struct strategy_nexthop_state { - unsigned int pi; - double avg_pi; - double weight; -}; - -static bool _strategyNexthopState_Destructor( - StrategyNexthopState **instancePtr) { - return true; -} - -parcObject_ImplementAcquire(strategyNexthopState, StrategyNexthopState); - -parcObject_ImplementRelease(strategyNexthopState, StrategyNexthopState); - -parcObject_Override( - StrategyNexthopState, PARCObject, - .destructor = (PARCObjectDestructor *)_strategyNexthopState_Destructor, - .copy = (PARCObjectCopy *)strategyNexthopState_Copy, - .display = (PARCObjectDisplay *)strategyNexthopState_Display, - .toString = (PARCObjectToString *)strategyNexthopState_ToString, - .equals = (PARCObjectEquals *)strategyNexthopState_Equals, - .compare = (PARCObjectCompare *)strategyNexthopState_Compare, - .hashCode = (PARCObjectHashCode *)strategyNexthopState_HashCode, - .display = (PARCObjectDisplay *)strategyNexthopState_Display); - -void strategyNexthopState_AssertValid(const StrategyNexthopState *instance) { - parcAssertTrue(strategyNexthopState_IsValid(instance), - "StrategyNexthopState is not valid."); -} - -StrategyNexthopState *strategyNexthopState_Create() { - StrategyNexthopState *result = - parcObject_CreateInstance(StrategyNexthopState); - if (result != NULL) { - result->pi = 0; - result->avg_pi = 0.0; - result->weight = 1; - } - return result; -} - -void strategyNexthopState_Reset(StrategyNexthopState *x) { - x->pi = 0; - x->avg_pi = 0.0; - x->weight = 1; -} - -int strategyNexthopState_Compare(const StrategyNexthopState *val, - const StrategyNexthopState *other) { - if (val == NULL) { - if (other != NULL) { - return -1; - } - } else if (other == NULL) { - return 1; - } else { - strategyNexthopState_OptionalAssertValid(val); - strategyNexthopState_OptionalAssertValid(other); - - if (val->pi < other->pi) { - return -1; - } else if (val->pi > other->pi) { - return 1; - } - - if (val->avg_pi < other->avg_pi) { - return -1; - } else if (val->avg_pi > other->avg_pi) { - return 1; - } - - if (val->weight < other->weight) { - return -1; - } else if (val->weight > other->weight) { - return 1; - } - } - - return 0; -} - -StrategyNexthopState *strategyNexthopState_Copy( - const StrategyNexthopState *original) { - StrategyNexthopState *result = strategyNexthopState_Create(); - result->pi = original->pi; - result->avg_pi = original->avg_pi; - result->weight = original->weight; - - return result; -} - -void strategyNexthopState_Display(const StrategyNexthopState *instance, - int indentation) { - parcDisplayIndented_PrintLine(indentation, "StrategyNexthopState@%p {", - instance); - parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->pi); - parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_pi); - parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->weight); - parcDisplayIndented_PrintLine(indentation, "}"); -} - -bool strategyNexthopState_Equals(const StrategyNexthopState *x, - const StrategyNexthopState *y) { - bool result = false; - - if (x == y) { - result = true; - } else if (x == NULL || y == NULL) { - result = false; - } else { - strategyNexthopState_OptionalAssertValid(x); - strategyNexthopState_OptionalAssertValid(y); - - if (strategyNexthopState_Compare(x, y) == 0) { - result = true; - } - } - - return result; -} - -PARCHashCode strategyNexthopState_HashCode(const StrategyNexthopState *x) { - PARCHashCode result = 0; - char str[128]; - sprintf(str, "PI:%d: AVG_PI:%f: W:%f", x->pi, x->avg_pi, x->weight); - result = parcHashCode_Hash((uint8_t *)&str, strlen(str)); - return result; -} - -bool strategyNexthopState_IsValid(const StrategyNexthopState *x) { - bool result = false; - - if (x != NULL) { - result = true; - } - - return result; -} - -char *strategyNexthopState_ToString(const StrategyNexthopState *x) { - // this is not implemented - parcTrapNotImplemented("strategyNexthopState_ToString is not implemented"); - return NULL; -} - -unsigned strategyNexthopState_GetPI(const StrategyNexthopState *x) { - strategyNexthopState_OptionalAssertValid(x); - - return x->pi; -} - -double strategyNexthopState_GetAvgPI(const StrategyNexthopState *x) { - strategyNexthopState_OptionalAssertValid(x); - - return x->avg_pi; -} - -double strategyNexthopState_GetWeight(const StrategyNexthopState *x) { - strategyNexthopState_OptionalAssertValid(x); - - return x->weight; -} - -double strategyNexthopState_UpdateState(StrategyNexthopState *x, bool inc, - double alpha) { - if (inc) { - x->pi++; - } else { - if (x->pi > 0) { - x->pi--; - } - } - x->avg_pi = (x->avg_pi * alpha) + (x->pi * (1 - alpha)); -#ifdef WITH_POLICY - if (x->avg_pi < AVG_PI_THRESHOLD) { -#else - if (x->avg_pi == 0.0) { -#endif /* WITH_POLICY */ - x->avg_pi = 0.1; - } - x->weight = 1 / x->avg_pi; - - return x->weight; -} diff --git a/hicn-light/src/hicn/strategies/nexthopState.h b/hicn-light/src/hicn/strategies/nexthopState.h deleted file mode 100644 index 35a9f497b..000000000 --- a/hicn-light/src/hicn/strategies/nexthopState.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 nexthopstate_h -#define nexthopstate_h - -#include <parc/algol/parc_HashCode.h> -#include <parc/algol/parc_Object.h> - -struct strategy_nexthop_state; -typedef struct strategy_nexthop_state StrategyNexthopState; -extern parcObjectDescriptor_Declaration(StrategyNexthopState); - -/** - */ -StrategyNexthopState *strategyNexthopState_Acquire( - const StrategyNexthopState *instance); - -#ifdef PARCLibrary_DISABLE_VALIDATION -#define strategyNexthopState_OptionalAssertValid(_instance_) -#else -#define strategyNexthopState_OptionalAssertValid(_instance_) \ - strategyNexthopState_AssertValid(_instance_) -#endif - -/** - */ -void strategyNexthopState_AssertValid(const StrategyNexthopState *instance); - -/** - */ -StrategyNexthopState *strategyNexthopState_Create(); - -void strategyNexthopState_Reset(StrategyNexthopState *x); -/** - */ -int strategyNexthopState_Compare(const StrategyNexthopState *instance, - const StrategyNexthopState *other); - -/** - */ -StrategyNexthopState *strategyNexthopState_Copy( - const StrategyNexthopState *original); - -/** - */ -void strategyNexthopState_Display(const StrategyNexthopState *instance, - int indentation); - -/** - */ -bool strategyNexthopState_Equals(const StrategyNexthopState *x, - const StrategyNexthopState *y); - -/** - */ -PARCHashCode strategyNexthopState_HashCode( - const StrategyNexthopState *instance); - -/** - */ -bool strategyNexthopState_IsValid(const StrategyNexthopState *instance); - -/** - */ -void strategyNexthopState_Release(StrategyNexthopState **instancePtr); - -/** - */ -char *strategyNexthopState_ToString(const StrategyNexthopState *instance); - -/** - */ -unsigned strategyNexthopState_GetPI(const StrategyNexthopState *x); - -double strategyNexthopState_GetAvgPI(const StrategyNexthopState *x); - -double strategyNexthopState_GetWeight(const StrategyNexthopState *x); - -double strategyNexthopState_UpdateState(StrategyNexthopState *x, bool inc, - double alpha); -#endif diff --git a/hicn-light/src/hicn/strategies/nexthopStateLowLatency.c b/hicn-light/src/hicn/strategies/nexthopStateLowLatency.c index a3953987f..3caed8130 100644 --- a/hicn-light/src/hicn/strategies/nexthopStateLowLatency.c +++ b/hicn-light/src/hicn/strategies/nexthopStateLowLatency.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -24,303 +24,17 @@ #include <parc/assert/parc_Assert.h> #include <hicn/strategies/nexthopStateLowLatency.h> -const unsigned MAX_ROUNS_WITHOUT_PROBES = 4; - //if we do not receives probes for 4 rounds it means - //that we had no responce from any producer for 2 sec - //we can say that this interface is daed -const unsigned MIN_NON_LOSSY_ROUNDS = 10; - //number of rounds in non lossy mode before switch to - //no lossy state -const double MAX_LOSS_RATE = 0.10; //10% - -struct strategy_nexthop_state_ll { - bool in_use; - bool is_allowed; // the policy may not allow the use of this face - unsigned face_id; - unsigned sent_packets; - //switch metrics - unsigned last_try_to_switch_round; - unsigned try_to_switch_counter; - //probes counters - unsigned recevied_probes; - unsigned rounds_without_probes; - unsigned sent_probes; - unsigned lost_probes; - unsigned non_lossy_rounds; - //avgs - double avg_rtt; - double avg_rtt_in_use; - double avg_queue; - double avg_loss_rate; - -}; - -static bool _strategyNexthopStateLL_Destructor( - StrategyNexthopStateLL **instancePtr) { - return true; -} - -parcObject_ImplementAcquire(strategyNexthopStateLL, StrategyNexthopStateLL); - -parcObject_ImplementRelease(strategyNexthopStateLL, StrategyNexthopStateLL); - -parcObject_Override( - StrategyNexthopStateLL, PARCObject, - .destructor = (PARCObjectDestructor *)_strategyNexthopStateLL_Destructor, - .copy = (PARCObjectCopy *)strategyNexthopStateLL_Copy, - .display = (PARCObjectDisplay *)strategyNexthopStateLL_Display, - .toString = (PARCObjectToString *)strategyNexthopStateLL_ToString, - .equals = (PARCObjectEquals *)strategyNexthopStateLL_Equals, - .compare = (PARCObjectCompare *)strategyNexthopStateLL_Compare, - .hashCode = (PARCObjectHashCode *)strategyNexthopStateLL_HashCode, - .display = (PARCObjectDisplay *)strategyNexthopStateLL_Display); - -void strategyNexthopStateLL_AssertValid(const StrategyNexthopStateLL *instance) { - parcAssertTrue(strategyNexthopStateLL_IsValid(instance), - "StrategyNexthopState is not valid."); -} - -StrategyNexthopStateLL *strategyNexthopStateLL_Create(unsigned face_id) { - StrategyNexthopStateLL *result = - parcObject_CreateInstance(StrategyNexthopStateLL); - if (result != NULL) { - result->in_use = false; - result->is_allowed = true; - result->face_id = face_id; - result->sent_packets = 0; - result->last_try_to_switch_round = 0; - result->try_to_switch_counter = 0; - result->recevied_probes = 0; - result->rounds_without_probes = 0; - result->sent_probes = 0; - result->lost_probes = 0; - result->non_lossy_rounds = MIN_NON_LOSSY_ROUNDS; - result->avg_rtt = -1.0; - result->avg_rtt_in_use = -1.0; - result->avg_queue = 0.0001; - result->avg_loss_rate = 0.0; - } - return result; -} - -void strategyNexthopStateLL_Reset(StrategyNexthopStateLL *x) { - x->in_use = false; - x->is_allowed = true; - x->sent_packets = 0; - x->last_try_to_switch_round = 0; - x->try_to_switch_counter = 0; - x->recevied_probes = 0; - x->rounds_without_probes = 0; - x->sent_probes = 0; - x->lost_probes = 0; - x->non_lossy_rounds = MIN_NON_LOSSY_ROUNDS; - x->avg_rtt = -1.0; - x->avg_rtt_in_use = -1.0; - x->avg_queue = 0.0001; - x->avg_loss_rate = 0.0; -} - - -int strategyNexthopStateLL_Compare(const StrategyNexthopStateLL *val, - const StrategyNexthopStateLL *other) { - if (val == NULL) { - if (other != NULL) { - return -1; - } - } else if (other == NULL) { - return 1; - } else { - strategyNexthopStateLL_OptionalAssertValid(val); - strategyNexthopStateLL_OptionalAssertValid(other); - - if (val->in_use < other->in_use){ - return -1; - }else if (val->in_use > other->in_use){ - return 1; - } - - if (val->is_allowed < other->is_allowed){ - return -1; - }else if (val->is_allowed> other->is_allowed){ - return 1; - } - - if (val->face_id < other->face_id) { - return -1; - } else if (val->face_id > other->face_id) { - return 1; - } - - if (val->sent_packets < other->sent_packets){ - return -1; - } else if (val->sent_packets > other->sent_packets){ - return 1; - } - - if (val->last_try_to_switch_round < - other->last_try_to_switch_round) { - return -1; - } else if (val->last_try_to_switch_round > - other->last_try_to_switch_round) { - return 1; - } - - if (val->try_to_switch_counter < - other->try_to_switch_counter) { - return -1; - } else if (val->try_to_switch_counter > - other->try_to_switch_counter) { - return 1; - } - - if (val->recevied_probes < other->recevied_probes) { - return -1; - } else if (val->recevied_probes > other->recevied_probes) { - return 1; - } - - if (val->rounds_without_probes < other->rounds_without_probes) { - return -1; - } else if (val->rounds_without_probes > other->rounds_without_probes) { - return 1; - } - - if (val->sent_probes < other->sent_probes) { - return -1; - } else if (val->sent_probes > other->sent_probes) { - return 1; - } - - if (val->lost_probes < other->lost_probes) { - return -1; - } else if (val->lost_probes > other->lost_probes) { - return 1; - } - - if (val->non_lossy_rounds < other->non_lossy_rounds) { - return -1; - } else if (val->non_lossy_rounds > other->non_lossy_rounds) { - return 1; - } - - if (val->avg_rtt < other->avg_rtt) { - return -1; - } else if (val->avg_rtt > other->avg_rtt) { - return 1; - } - - if (val->avg_rtt_in_use < other->avg_rtt_in_use) { - return -1; - } else if (val->avg_rtt_in_use > other->avg_rtt_in_use) { - return 1; - } - - if (val->avg_queue < other->avg_queue) { - return -1; - } else if (val->avg_queue > other->avg_queue) { - return 1; - } - - if (val->avg_loss_rate < other->avg_loss_rate) { - return -1; - } else if (val->avg_loss_rate > other->avg_loss_rate) { - return 1; - } - } - - return 0; -} - -StrategyNexthopStateLL *strategyNexthopStateLL_Copy( - const StrategyNexthopStateLL *original) { - StrategyNexthopStateLL *result = strategyNexthopStateLL_Create(original->face_id); - result->in_use = original->in_use; - result->is_allowed = original->is_allowed; - result->sent_packets = original->sent_packets; - result->last_try_to_switch_round = original->last_try_to_switch_round; - result->try_to_switch_counter = original->try_to_switch_counter; - result->recevied_probes = original->recevied_probes; - result->rounds_without_probes = original->rounds_without_probes; - result->sent_probes = original->sent_probes; - result->lost_probes = original->lost_probes; - result->non_lossy_rounds = original->non_lossy_rounds; - result->avg_rtt = original->avg_rtt; - result->avg_rtt_in_use = original->avg_rtt_in_use; - result->avg_queue = original->avg_queue; - result->avg_loss_rate = original->avg_loss_rate; - return result; -} - -void strategyNexthopStateLL_Display(const StrategyNexthopStateLL *instance, - int indentation) { - parcDisplayIndented_PrintLine(indentation, "StrategyNexthopStateLL@%p {", - instance); - parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->face_id); - parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_rtt); - parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_rtt_in_use); - parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_queue); - parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_loss_rate); - parcDisplayIndented_PrintLine(indentation, "}"); -} - - -bool strategyNexthopStateLL_Equals(const StrategyNexthopStateLL *x, - const StrategyNexthopStateLL *y) { - bool result = false; - - if (x == y) { - result = true; - } else if (x == NULL || y == NULL) { - result = false; - } else { - strategyNexthopStateLL_OptionalAssertValid(x); - strategyNexthopStateLL_OptionalAssertValid(y); - - if (strategyNexthopStateLL_Compare(x, y) == 0) { - result = true; - } - } - - return result; -} - -PARCHashCode strategyNexthopStateLL_HashCode(const StrategyNexthopStateLL *x) { - PARCHashCode result = 0; - char str[128]; - sprintf(str, "ID:%d: RTT:%f: RTTUSE:%f: Q:%f L:%f", x->face_id, x->avg_rtt, - x->avg_rtt_in_use, x->avg_queue, x->avg_loss_rate); - result = parcHashCode_Hash((uint8_t *)&str, strlen(str)); - return result; -} - -bool strategyNexthopStateLL_IsValid(const StrategyNexthopStateLL *x) { - bool result = false; - - if (x != NULL) { - result = true; - } - - return result; -} - -char *strategyNexthopStateLL_ToString(const StrategyNexthopStateLL *x) { - // this is not implemented - parcTrapNotImplemented("strategyNexthopStateLL_ToString is not implemented"); - return NULL; -} - double strategyNexthopStateLL_GetRTTProbe(StrategyNexthopStateLL *x) { strategyNexthopStateLL_OptionalAssertValid(x); - if(x->rounds_without_probes > MAX_ROUNS_WITHOUT_PROBES) - return DBL_MAX; + if (x->rounds_without_probes > MAX_ROUNS_WITHOUT_PROBES) return DBL_MAX; - if(x->avg_rtt == -1.0){ - if(x->avg_rtt_in_use == -1.0){ + if (x->avg_rtt == -1.0) { + if (x->avg_rtt_in_use == -1.0) { return 0.0; - }else{ - //this happens if the face recevied probes only in in_use mode - //we set the avf_rtt with rtt_in_use + } else { + // this happens if the face recevied probes only in in_use mode + // we set the avf_rtt with rtt_in_use x->avg_rtt = x->avg_rtt_in_use; } } @@ -331,11 +45,9 @@ double strategyNexthopStateLL_GetRTTProbe(StrategyNexthopStateLL *x) { double strategyNexthopStateLL_GetRTTInUse(StrategyNexthopStateLL *x) { strategyNexthopStateLL_OptionalAssertValid(x); - if(x->rounds_without_probes > MAX_ROUNS_WITHOUT_PROBES) - return DBL_MAX; + if (x->rounds_without_probes > MAX_ROUNS_WITHOUT_PROBES) return DBL_MAX; - if(x->avg_rtt_in_use == -1.0) - return strategyNexthopStateLL_GetRTTProbe(x); + if (x->avg_rtt_in_use == -1.0) return strategyNexthopStateLL_GetRTTProbe(x); return x->avg_rtt_in_use; } @@ -343,9 +55,9 @@ double strategyNexthopStateLL_GetRTTInUse(StrategyNexthopStateLL *x) { double strategyNexthopStateLL_GetRTTLive(StrategyNexthopStateLL *x) { strategyNexthopStateLL_OptionalAssertValid(x); - if(x->in_use){ + if (x->in_use) { return strategyNexthopStateLL_GetRTTInUse(x); - }else{ + } else { return strategyNexthopStateLL_GetRTTProbe(x); } } @@ -353,46 +65,45 @@ double strategyNexthopStateLL_GetRTTLive(StrategyNexthopStateLL *x) { double strategyNexthopStateLL_GetQueuing(const StrategyNexthopStateLL *x) { strategyNexthopStateLL_OptionalAssertValid(x); - if(x->rounds_without_probes > MAX_ROUNS_WITHOUT_PROBES) - return 0.0; + if (x->rounds_without_probes > MAX_ROUNS_WITHOUT_PROBES) return 0.0; return x->avg_queue; } void strategyNexthopStateLL_AddRttSample(StrategyNexthopStateLL *x, - unsigned int rtt){ + unsigned int rtt) { strategyNexthopStateLL_OptionalAssertValid(x); x->recevied_probes++; - //form uint to double + // form uint to double double drtt = rtt; - if(x->in_use){ - if(x->avg_rtt_in_use == -1.0){ + if (x->in_use) { + if (x->avg_rtt_in_use == -1.0) { x->avg_rtt_in_use = drtt; - }else{ + } else { x->avg_rtt_in_use = (x->avg_rtt_in_use * 0.9) + (drtt * 0.1); } - }else{ - if(x->avg_rtt == -1.0){ - x->avg_rtt = drtt; - }else{ + } else { + if (x->avg_rtt == -1.0) { + x->avg_rtt = drtt; + } else { x->avg_rtt = (x->avg_rtt * 0.9) + (drtt * 0.1); } } - if(x->avg_rtt_in_use == -1.0 || x->avg_rtt == -1.0){ + if (x->avg_rtt_in_use == -1.0 || x->avg_rtt == -1.0) { x->avg_queue = 0.0001; - }else{ + } else { double queue = x->avg_rtt_in_use - x->avg_rtt; - if(queue < 0){ + if (queue < 0) { queue = 0.0001; } x->avg_queue = (x->avg_queue * 0.95) + (0.05 * queue); } } -void strategyNexthopStateLL_SetUnusedFace(StrategyNexthopStateLL *x){ +void strategyNexthopStateLL_SetUnusedFace(StrategyNexthopStateLL *x) { strategyNexthopStateLL_OptionalAssertValid(x); x->in_use = false; } @@ -403,75 +114,76 @@ unsigned strategyNexthopStateLL_GetFaceId(StrategyNexthopStateLL *x) { } void strategyNexthopStateLL_IncreaseTryToSwitch(StrategyNexthopStateLL *x, - unsigned round){ - if(x->try_to_switch_counter == 0 || - round == (x->last_try_to_switch_round + 1)){ + unsigned round) { + if (x->try_to_switch_counter == 0 || + round == (x->last_try_to_switch_round + 1)) { x->last_try_to_switch_round = round; x->try_to_switch_counter++; - }else{ + } else { x->try_to_switch_counter = 0; } } -unsigned strategyNexthopStateLL_GetTryToSwitch(const StrategyNexthopStateLL *x){ +unsigned strategyNexthopStateLL_GetTryToSwitch( + const StrategyNexthopStateLL *x) { return x->try_to_switch_counter; } -void strategyNexthopStateLL_ResetTryToSwitch(StrategyNexthopStateLL *x){ +void strategyNexthopStateLL_ResetTryToSwitch(StrategyNexthopStateLL *x) { x->try_to_switch_counter = 0; } -void strategyNexthopStateLL_SendPacket(StrategyNexthopStateLL *x){ +void strategyNexthopStateLL_SendPacket(StrategyNexthopStateLL *x) { x->in_use = true; x->sent_packets++; } -void strategyNexthopStateLL_SentProbe(StrategyNexthopStateLL *x){ +void strategyNexthopStateLL_SentProbe(StrategyNexthopStateLL *x) { x->sent_probes++; } -void strategyNexthopStateLL_LostProbe(StrategyNexthopStateLL *x){ +void strategyNexthopStateLL_LostProbe(StrategyNexthopStateLL *x) { x->lost_probes++; } -bool strategyNexthopStateLL_IsLossy(const StrategyNexthopStateLL *x){ - if(x->non_lossy_rounds < 10 || - x->avg_loss_rate > MAX_LOSS_RATE){ +bool strategyNexthopStateLL_IsLossy(const StrategyNexthopStateLL *x) { + if (x->non_lossy_rounds < 10 || x->avg_loss_rate > MAX_LOSS_RATE) { return true; } return false; } -void strategyNexthopStateLL_SetIsAllowed(StrategyNexthopStateLL *x, bool allowed){ +void strategyNexthopStateLL_SetIsAllowed(StrategyNexthopStateLL *x, + bool allowed) { x->is_allowed = allowed; } -bool strategyNexthopStateLL_IsAllowed(const StrategyNexthopStateLL *x){ +bool strategyNexthopStateLL_IsAllowed(const StrategyNexthopStateLL *x) { return x->is_allowed; } -void strategyNexthopStateLL_StartNewRound(StrategyNexthopStateLL *x){ +void strategyNexthopStateLL_StartNewRound(StrategyNexthopStateLL *x) { strategyNexthopStateLL_OptionalAssertValid(x); - if(x->sent_packets == 0) //the face was not used in the last round + if (x->sent_packets == 0) // the face was not used in the last round x->in_use = false; x->sent_packets = 0; - if(x->recevied_probes == 0){ + if (x->recevied_probes == 0) { x->rounds_without_probes++; - }else{ + } else { x->rounds_without_probes = 0; } x->recevied_probes = 0; - //compute losses in this round - if(x->sent_probes != 0){ - double loss_rate = (double) x->lost_probes / (double) x->sent_probes; + // compute losses in this round + if (x->sent_probes != 0) { + double loss_rate = (double)x->lost_probes / (double)x->sent_probes; x->avg_loss_rate = x->avg_loss_rate * 0.7 + loss_rate * 0.3; - if(x->avg_loss_rate > MAX_LOSS_RATE){ + if (x->avg_loss_rate > MAX_LOSS_RATE) { x->non_lossy_rounds = 0; - }else{ + } else { x->non_lossy_rounds++; } } diff --git a/hicn-light/src/hicn/strategies/nexthopStateLowLatency.h b/hicn-light/src/hicn/strategies/nexthopStateLowLatency.h index 34dbb8262..7f4181d44 100644 --- a/hicn-light/src/hicn/strategies/nexthopStateLowLatency.h +++ b/hicn-light/src/hicn/strategies/nexthopStateLowLatency.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -47,7 +47,7 @@ void strategyNexthopStateLL_Reset(StrategyNexthopStateLL *x); /** */ int strategyNexthopStateLL_Compare(const StrategyNexthopStateLL *instance, - const StrategyNexthopStateLL *other); + const StrategyNexthopStateLL *other); /** */ @@ -57,12 +57,12 @@ StrategyNexthopStateLL *strategyNexthopStateLL_Copy( /** */ void strategyNexthopStateLL_Display(const StrategyNexthopStateLL *instance, - int indentation); + int indentation); /** */ bool strategyNexthopStateLL_Equals(const StrategyNexthopStateLL *x, - const StrategyNexthopStateLL *y); + const StrategyNexthopStateLL *y); /** */ @@ -88,11 +88,10 @@ double strategyNexthopStateLL_GetRTTInUse(StrategyNexthopStateLL *x); double strategyNexthopStateLL_GetRTTLive(StrategyNexthopStateLL *x); double strategyNexthopStateLL_GetQueuing(const StrategyNexthopStateLL *x); void strategyNexthopStateLL_AddRttSample(StrategyNexthopStateLL *x, - unsigned int rtt); - + unsigned int rtt); void strategyNexthopStateLL_IncreaseTryToSwitch(StrategyNexthopStateLL *x, - unsigned round); + unsigned round); unsigned strategyNexthopStateLL_GetTryToSwitch(const StrategyNexthopStateLL *x); void strategyNexthopStateLL_ResetTryToSwitch(StrategyNexthopStateLL *x); @@ -108,7 +107,8 @@ void strategyNexthopStateLL_LostProbe(StrategyNexthopStateLL *x); bool strategyNexthopStateLL_IsLossy(const StrategyNexthopStateLL *x); -void strategyNexthopStateLL_SetIsAllowed(StrategyNexthopStateLL *x, bool allowed); +void strategyNexthopStateLL_SetIsAllowed(StrategyNexthopStateLL *x, + bool allowed); bool strategyNexthopStateLL_IsAllowed(const StrategyNexthopStateLL *x); diff --git a/hicn-light/src/hicn/strategies/probe_generator.c b/hicn-light/src/hicn/strategies/probe_generator.c new file mode 100644 index 000000000..439de0a12 --- /dev/null +++ b/hicn-light/src/hicn/strategies/probe_generator.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021 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. + */ + +#include "probe_generator.h" + +#include <hicn/core/forwarder.h> +#include <hicn/core/nexthops.h> + +// map functions +static void add_to_map(probe_generator_t *pg, unsigned seq, Ticks now) { + khiter_t k; + int ret; + k = kh_put_bp_map(pg->ticks_by_seq, seq, &ret); + kh_value(pg->ticks_by_seq, k) = now; +} + +static Ticks get_from_map(probe_generator_t *pg, unsigned seq) { + khiter_t k; + k = kh_get_bp_map(pg->ticks_by_seq, seq); + if (k == kh_end(pg->ticks_by_seq)) return 0; + Ticks t = kh_value(pg->ticks_by_seq, k); + return t; +} + +static void remove_from_map(probe_generator_t *pg, unsigned seq) { + khiter_t k; + k = kh_get_bp_map(pg->ticks_by_seq, seq); + if (k != kh_end(pg->ticks_by_seq)) kh_del_bp_map(pg->ticks_by_seq, k); +} + +static void clear_map(probe_generator_t *pg) { + kh_clear(bp_map, pg->ticks_by_seq); +} + +// seq number generator + +static uint32_t get_seq_number(probe_generator_t *pg) { + uint32_t seq = 0; + uint32_t try = 0; + while (try < 3) { // try up to 3 times + seq = + (rand() % (MAX_PROBE_SUFFIX - MIN_PROBE_SUFFIX + 1)) + MIN_PROBE_SUFFIX; + Ticks time = get_from_map(pg, seq); + if (time == 0) return seq; // seq does not exists + try++; + } + return 0; +} + +// probing functions + +probe_generator_t *create_probe_generator() { + probe_generator_t *pg = calloc(1, sizeof(probe_generator_t)); + if (!pg) return NULL; + + pg->ticks_by_seq = kh_init_bp_map(); + return pg; +} + +void destroy_probe_generator(probe_generator_t *pg) { + kh_destroy_bp_map(pg->ticks_by_seq); + free(pg); +} + +int generate_probe(probe_generator_t *pg, const msgbuf_t *msgbuf, + const forwarder_t *forwarder, nexthop_t nexthop) { + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + connection_table_t *table = forwarder_get_connection_table(forwarder); + const connection_t *conn = connection_table_get_by_id(table, nexthop); + if (!conn) return -1; + + msgbuf_t *probe; + off_t msg_id = msgbuf_pool_get_id(msgbuf_pool, (msgbuf_t *)msgbuf); + off_t probe_offset = msgbuf_pool_clone(msgbuf_pool, &probe, msg_id); + + uint32_t seq = get_seq_number(pg); + if (seq == 0) return -1; + + messageHandler_ModifySuffix(msgbuf_get_packet(probe), seq); + connection_send(conn, probe_offset, true); + connection_flush(conn); + add_to_map(pg, seq, ticks_now()); + msgbuf_pool_put(msgbuf_pool, probe); + + return 0; +} + +Ticks register_probe(probe_generator_t *pg, unsigned seq) { + Ticks now = ticks_now(); + add_to_map(pg, seq, now); + return now; +} + +Ticks get_probe_send_time(probe_generator_t *pg, unsigned seq) { + return get_from_map(pg, seq); +} + +void delete_probe(probe_generator_t *pg, unsigned seq) { + remove_from_map(pg, seq); +} + +void delete_all_probes(probe_generator_t *pg) { clear_map(pg); } diff --git a/hicn-light/src/hicn/strategies/probe_generator.h b/hicn-light/src/hicn/strategies/probe_generator.h new file mode 100644 index 000000000..26d6a3a22 --- /dev/null +++ b/hicn-light/src/hicn/strategies/probe_generator.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 HICNLIGHT_PROBE_GENERATOR +#define HICNLIGHT_PROBE_GENERATOR + +#include "../base/khash.h" +#include <hicn/core/ticks.h> +#include <hicn/core/msgbuf.h> + +KHASH_MAP_INIT_INT64(bp_map, Ticks); + +struct forwarder_s; + +typedef struct probe_generator { + kh_bp_map_t *ticks_by_seq; +} probe_generator_t; + +probe_generator_t *create_probe_generator(); + +void destroy_probe_generator(probe_generator_t *pg); + +int generate_probe(probe_generator_t *pg, const msgbuf_t *msgbuf, + const struct forwarder_s *forwarder, unsigned nexthop); + +Ticks register_probe(probe_generator_t *pg, unsigned seq); + +Ticks get_probe_send_time(probe_generator_t *pg, unsigned seq); + +void delete_probe(probe_generator_t *pg, unsigned seq); + +void delete_all_probes(probe_generator_t *pg); + +#endif /* HICNLIGHT_PROBE_GENERATOR */ diff --git a/hicn-light/src/hicn/strategies/random.c b/hicn-light/src/hicn/strategies/random.c new file mode 100644 index 000000000..5b076df7c --- /dev/null +++ b/hicn-light/src/hicn/strategies/random.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <hicn/hicn-light/config.h> + +#include <hicn/core/nexthops.h> +#include <hicn/core/strategy.h> +#include <hicn/core/strategy_vft.h> + +#include "random.h" + +static int strategy_random_initialize(strategy_entry_t *entry, + const void *forwarder) { + srand((unsigned int)time(NULL)); + entry->forwarder = forwarder; + return 0; +} + +static int strategy_random_finalize(strategy_entry_t *entry) { + /* Nothing to do */ + return 0; +} + +static int strategy_random_add_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, off_t offset) { + /* Nothing to do */ + return 0; +} + +static int strategy_random_remove_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, off_t offset) { + /* Nothing to do */ + return 0; +} + +static nexthops_t *strategy_random_lookup_nexthops(strategy_entry_t *entry, + nexthops_t *nexthops, + const msgbuf_t *msgbuf) { + nexthops_select(nexthops, rand() % nexthops_get_len(nexthops)); + return nexthops; +} + +static int strategy_random_on_data(strategy_entry_t *entry, + nexthops_t *nexthops, + const nexthops_t *data_nexthops, + const msgbuf_t *msgbuf, + Ticks pitEntryCreation, Ticks objReception) { + /* Nothing to do */ + return 0; +} + +static int strategy_random_on_timeout(strategy_entry_t *entry, + nexthops_t *nexthops, + const nexthops_t *timeout_nexthops) { + /* Nothing to do */ + return 0; +} + +DECLARE_STRATEGY(random); diff --git a/hicn-light/src/hicn/config/controlRemovePunting.h b/hicn-light/src/hicn/strategies/random.h index 858d6f969..bdea5e4dd 100644 --- a/hicn-light/src/hicn/config/controlRemovePunting.h +++ b/hicn-light/src/hicn/strategies/random.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -14,14 +14,22 @@ */ /** - * @file control_RemovePunting.h - * + * Forward randomly */ -#ifndef Control_RemovePunting_h -#define Control_RemovePunting_h +#ifndef HICNLIGHT_STRATEGY_RANDOM_H +#define HICNLIGHT_STRATEGY_RANDOM_H + +typedef struct { + void *_; +} strategy_random_nexthop_state_t; + +typedef struct { + void *_; +} strategy_random_state_t; + +typedef struct { + void *_; +} strategy_random_options_t; -#include <hicn/config/controlState.h> -CommandOps *controlRemovePunting_Create(ControlState *state); -CommandOps *controlRemovePunting_HelpCreate(ControlState *state); -#endif // Control_RemovePunting_h +#endif /* HICNLIGHT_STRATEGY_RANDOM_H */ diff --git a/hicn-light/src/hicn/strategies/replication.c b/hicn-light/src/hicn/strategies/replication.c new file mode 100644 index 000000000..86a3e3431 --- /dev/null +++ b/hicn-light/src/hicn/strategies/replication.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <hicn/hicn-light/config.h> + +#include <hicn/core/nexthops.h> +#include <hicn/core/strategy.h> +#include <hicn/core/strategy_vft.h> + +#include "replication.h" + +/* Shorthand */ +#define strategy_state_t strategy_replication_state_t + +static int strategy_replication_initialize(strategy_entry_t *entry, + const void *forwarder) { + entry->forwarder = forwarder; + strategy_state_t *state = &entry->state.replication; + state->prev_nexthops = malloc(sizeof(nexthops_t)); + *((nexthops_t *)state->prev_nexthops) = NEXTHOPS_EMPTY; + return 0; +} + +static int strategy_replication_finalize(strategy_entry_t *entry) { + /* Nothing to do */ + strategy_state_t *state = &entry->state.replication; + free(state->prev_nexthops); + return 0; +} + +static int strategy_replication_add_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, + off_t offset) { + /* Nothing to do */ + return 0; +} + +static int strategy_replication_remove_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, + off_t offset) { + /* Nothing to do */ + return 0; +} + +static nexthops_t *strategy_replication_lookup_nexthops( + strategy_entry_t *entry, nexthops_t *nexthops, const msgbuf_t *msgbuf) { + // if nexthops is different from prev_nexthops send updates + strategy_state_t *state = &entry->state.replication; + + if (!nexthops_equal((nexthops_t *)state->prev_nexthops, nexthops)) { + // send updates + strategy_replication_options_t *options = &entry->options.replication; + update_remote_node_paths(nexthops, entry->forwarder, + options->local_prefixes); + + // update next hops + nexthops_copy(nexthops, (nexthops_t *)state->prev_nexthops); + } + + // Return all next hops + return nexthops; +} + +static int strategy_replication_on_data(strategy_entry_t *entry, + nexthops_t *nexthops, + const nexthops_t *data_nexthops, + const msgbuf_t *msgbuf, + Ticks pitEntryCreation, + Ticks objReception) { + /* Nothing to do */ + return 0; +} + +static int strategy_replication_on_timeout(strategy_entry_t *entry, + nexthops_t *nexthops, + const nexthops_t *timeout_nexthops) { + /* Nothing to do */ + return 0; +} + +DECLARE_STRATEGY(replication); diff --git a/hicn-light/src/hicn/strategies/replication.h b/hicn-light/src/hicn/strategies/replication.h new file mode 100644 index 000000000..753ae4744 --- /dev/null +++ b/hicn-light/src/hicn/strategies/replication.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * Forward replication of the interest on all the paths + */ + +#ifndef HICNLIGHT_STRATEGY_REPLICATION_H +#define HICNLIGHT_STRATEGY_REPLICATION_H + +#include "local_prefixes.h" + +typedef struct { + void *_; +} strategy_replication_nexthop_state_t; + +typedef struct { + void *prev_nexthops; +} strategy_replication_state_t; + +typedef struct { + local_prefixes_t *local_prefixes; +} strategy_replication_options_t; + +#endif /* HICNLIGHT_STRATEGY_REPLICATION_H */ diff --git a/hicn-light/src/hicn/strategies/rnd.c b/hicn-light/src/hicn/strategies/rnd.c deleted file mode 100644 index 064f3965b..000000000 --- a/hicn-light/src/hicn/strategies/rnd.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_HashMap.h> -#include <parc/algol/parc_Memory.h> - -#include <hicn/strategies/rnd.h> - -static void _strategyRnd_ReceiveObject(StrategyImpl *strategy, - const NumberSet *egressId, - const Message *objectMessage, - Ticks pitEntryCreation, - Ticks objReception); -static void _strategyRnd_OnTimeout(StrategyImpl *strategy, - const NumberSet *egressId); - -static NumberSet *_strategyRnd_LookupNexthop(StrategyImpl *strategy, -#ifdef WITH_POLICY - NumberSet * nexthops, -#endif /* WITH_POLICY */ - const Message *interestMessage); -#ifndef WITH_POLICY -static NumberSet *_strategyRnd_ReturnNexthops(StrategyImpl *strategy); -static unsigned _strategyRnd_CountNexthops(StrategyImpl *strategy); -#endif /* ! WITH_POLICY */ -static void _strategyRnd_AddNexthop(StrategyImpl *strategy, - unsigned connectionId); -static void _strategyRnd_RemoveNexthop(StrategyImpl *strategy, - unsigned connectionId); -static void _strategyRnd_ImplDestroy(StrategyImpl **strategyPtr); -static strategy_type _strategyRnd_GetStrategy(StrategyImpl *strategy); - -static StrategyImpl _template = { - .context = NULL, - .receiveObject = &_strategyRnd_ReceiveObject, - .onTimeout = &_strategyRnd_OnTimeout, - .lookupNexthop = &_strategyRnd_LookupNexthop, -#ifndef WITH_POLICY - .returnNexthops = &_strategyRnd_ReturnNexthops, - .countNexthops = &_strategyRnd_CountNexthops, -#endif /* ! WITH_POLICY */ - .addNexthop = &_strategyRnd_AddNexthop, - .removeNexthop = &_strategyRnd_RemoveNexthop, - .destroy = &_strategyRnd_ImplDestroy, - .getStrategy = &_strategyRnd_GetStrategy, -}; - -#ifndef WITH_POLICY -struct strategy_rnd; -typedef struct strategy_rnd StrategyRnd; - -struct strategy_rnd { - NumberSet *nexthops; -}; -#endif /* ! WITH_POLICY */ - -StrategyImpl *strategyRnd_Create() { -#ifndef WITH_POLICY - StrategyRnd *strategy = parcMemory_AllocateAndClear(sizeof(StrategyRnd)); - parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(StrategyRnd)); - - strategy->nexthops = numberSet_Create(); -#endif /* ! WITH_POLICY */ - srand((unsigned int)time(NULL)); - - StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl)); - parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(StrategyImpl)); - memcpy(impl, &_template, sizeof(StrategyImpl)); -#ifndef WITH_POLICY - impl->context = strategy; -#endif /* ! WITH_POLICY */ - return impl; -} - -// ======================================================= -// Dispatch API - -strategy_type _strategyRnd_GetStrategy(StrategyImpl *strategy) { - return SET_STRATEGY_RANDOM; -} - -#ifndef WITH_POLICY -static int _select_Nexthop(StrategyRnd *strategy) { - unsigned len = (unsigned)numberSet_Length(strategy->nexthops); - if (len == 0) { - return -1; - } - - int rnd = (rand() % len); - return numberSet_GetItem(strategy->nexthops, rnd); -} -#endif /* ! WITH_POLICY */ - -static void _strategyRnd_ReceiveObject(StrategyImpl *strategy, - const NumberSet *egressId, - const Message *objectMessage, - Ticks pitEntryCreation, - Ticks objReception) {} - -static void _strategyRnd_OnTimeout(StrategyImpl *strategy, - const NumberSet *egressId) {} - -static NumberSet *_strategyRnd_LookupNexthop(StrategyImpl *strategy, -#ifdef WITH_POLICY - NumberSet * nexthops, -#endif /* WITH_POLICY */ - const Message *interestMessage) { - unsigned out_connection; - NumberSet *out = numberSet_Create(); - -#ifdef WITH_POLICY - // We return one next hop at random - out_connection = numberSet_GetItem(nexthops, rand() % numberSet_Length(nexthops)); - -#else - StrategyRnd *srnd = (StrategyRnd *)strategy->context; - unsigned in_connection = message_GetIngressConnectionId(interestMessage); - unsigned nexthopSize = (unsigned)numberSet_Length(srnd->nexthops); - - if ((nexthopSize == 0) || - ((nexthopSize == 1) && - numberSet_Contains(srnd->nexthops, in_connection))) { - // there are no output faces or the input face is also the only output face. - // return null to avoid loops - return out; - } - - do { - out_connection = _select_Nexthop(srnd); - } while (out_connection == in_connection); - - if (out_connection == -1) { - return out; - } -#endif /* WITH_POLICY */ - - numberSet_Add(out, out_connection); - return out; -} - -#ifndef WITH_POLICY -static NumberSet *_strategyRnd_ReturnNexthops(StrategyImpl *strategy) { - StrategyRnd *srnd = (StrategyRnd *)strategy->context; - return srnd->nexthops; -} - -unsigned _strategyRnd_CountNexthops(StrategyImpl *strategy) { - StrategyRnd *srnd = (StrategyRnd *)strategy->context; - return (unsigned)numberSet_Length(srnd->nexthops); -} -#endif /* ! WITH_POLICY */ - -static void _strategyRnd_AddNexthop(StrategyImpl *strategy, - unsigned connectionId) { -#ifndef WITH_POLICY - StrategyRnd *srnd = (StrategyRnd *)strategy->context; - if (!numberSet_Contains(srnd->nexthops, connectionId)) { - numberSet_Add(srnd->nexthops, connectionId); - } -#endif /* ! WITH_POLICY */ -} - -static void _strategyRnd_RemoveNexthop(StrategyImpl *strategy, - unsigned connectionId) { -#ifndef WITH_POLICY - StrategyRnd *srnd = (StrategyRnd *)strategy->context; - - if (numberSet_Contains(srnd->nexthops, connectionId)) { - numberSet_Remove(srnd->nexthops, connectionId); - } -#endif /* ! WITH_POLICY */ -} - -static void _strategyRnd_ImplDestroy(StrategyImpl **strategyPtr) { - parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*strategyPtr, - "Parameter must dereference to non-null pointer"); - - StrategyImpl *impl = *strategyPtr; - -#ifndef WITH_POLICY - StrategyRnd *strategy = (StrategyRnd *)impl->context; - numberSet_Release(&(strategy->nexthops)); - parcMemory_Deallocate((void **)&strategy); -#endif /* ! WITH_POLICY */ - - parcMemory_Deallocate((void **)&impl); - *strategyPtr = NULL; -} diff --git a/hicn-light/src/hicn/strategies/strategyImpl.h b/hicn-light/src/hicn/strategies/strategyImpl.h deleted file mode 100644 index 140da5bf8..000000000 --- a/hicn-light/src/hicn/strategies/strategyImpl.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @file strategyImpl.h - * @brief Defines the function structure for a Strategy implementation - * - * <#Detailed Description#> - * - */ - -/** - * A dispatch structure for a concrete implementation of a forwarding strategy. - */ - -#ifndef strategyImpl_h -#define strategyImpl_h - -#include <hicn/core/message.h> -#include <hicn/core/numberSet.h> - -struct strategy_impl; -typedef struct strategy_impl StrategyImpl; - -/** - * @typedef StrategyImpl - * @abstract Forwarding strategy implementation - * @constant receiveObject is called when we receive an object and have a - * measured round trip time. This allows a strategy to update its performance - * data. - * @constant lookupNexthop Find the set of nexthops to use for the Interest. - * May be empty, should not be NULL. Must be destroyed. - * @constant addNexthop Add a nexthop to the list of available nexthops with a - * routing protocol-specific cost. - * @constant destroy cleans up the strategy, freeing all memory and state. A - * strategy is reference counted, so the final destruction only happens after - * the last reference is released. - * @discussion <#Discussion#> - */ -struct strategy_impl { - void *context; - void (*receiveObject)(StrategyImpl *strategy, const NumberSet *egressId, - const Message *objectMessage, Ticks pitEntryCreation, - Ticks objReception); - void (*onTimeout)(StrategyImpl *strategy, const NumberSet *egressId); - NumberSet *(*lookupNexthop)(StrategyImpl *strategy, -#ifdef WITH_POLICY - NumberSet * nexthops, -#endif /* WITH_POLICY */ - const Message *interestMessage); -#ifndef WITH_POLICY - NumberSet *(*returnNexthops)(StrategyImpl *strategy); - unsigned (*countNexthops)(StrategyImpl *strategy); -#endif /* ! WITH_POLICY */ - void (*addNexthop)(StrategyImpl *strategy, unsigned connectionId); - void (*removeNexthop)(StrategyImpl *strategy, unsigned connectionId); - void (*destroy)(StrategyImpl **strategyPtr); - strategy_type (*getStrategy)(StrategyImpl *strategy); -}; - -#endif // strategyImpl_h diff --git a/hicn-light/src/hicn/test/CMakeLists.txt b/hicn-light/src/hicn/test/CMakeLists.txt new file mode 100644 index 000000000..0ded4253d --- /dev/null +++ b/hicn-light/src/hicn/test/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (c) 2021 Cisco and/or its affiliates. + +include(BuildMacros) + +list(APPEND TESTS_SRC + test-bitmap.cc + test-configuration.cc + test-hash.cc + test-khash.cc + test-loop.cc + test-pool.cc + test-parser.cc + test-ctrl.cc + test-ring.cc + test-vector.cc + test-msgbuf_pool.cc + test-nexthops.cc + test-connection_table.cc + test-listener_table.cc + test-packet_cache.cc + test-strategy-load-balancing.cc + test-strategy-random.cc + test-strategy-replication.cc + test-strategy-best-path.cc + test-subscription.cc + test-local_prefixes.cc + test-probe_generator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../config/command_listener.c + ${CMAKE_CURRENT_SOURCE_DIR}/../config/command_route.c + main.cc +) + +build_executable(hicn_light_tests + NO_INSTALL + SOURCES ${TESTS_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_STATIC} ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + INCLUDE_DIRS ${HICN_LIGHT_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} + DEPENDS gtest ${LIBHICNCTRL_STATIC} ${LIBHICN_LIGHT_SHARED} + COMPONENT ${HICN_LIGHT} + DEFINITIONS "${COMPILER_DEFINITIONS}" +) + +add_test_internal(hicn_light_tests) diff --git a/hicn-light/src/hicn/strategies/loadBalancer.h b/hicn-light/src/hicn/test/main.cc index 74920768d..49cc28f66 100644 --- a/hicn-light/src/hicn/strategies/loadBalancer.h +++ b/hicn-light/src/hicn/test/main.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,15 +13,9 @@ * limitations under the License. */ -/** - * Forward on the less loaded path - */ - -#ifndef loadBalancer_h -#define loadBalancer_h - -#include <hicn/strategies/strategyImpl.h> - -StrategyImpl *strategyLoadBalancer_Create(); +#include <gtest/gtest.h> -#endif // loadBalancer_h +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/hicn-light/src/hicn/test/test-bitmap.cc b/hicn-light/src/hicn/test/test-bitmap.cc new file mode 100644 index 000000000..f1bf1ae5a --- /dev/null +++ b/hicn-light/src/hicn/test/test-bitmap.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/bitmap.h> +} + +#define DEFAULT_SIZE 10 + +class BitmapTest : public ::testing::Test { + protected: + BitmapTest() {} + + virtual ~BitmapTest() {} + + bitmap_t* bitmap; +}; + +/* + * TEST: bitmap allocation + */ +TEST_F(BitmapTest, BitmapAllocation) { + int rc; + + /* + * We take a value < 32 on purpose to avoid confusion on the choice of a 32 + * or 64 bit integer for storage + */ + size_t size_not_pow2 = DEFAULT_SIZE; + bitmap_init(bitmap, size_not_pow2, 0); + + /* + * Bitmap should have been allocated with a size rounded to the next power + * of 2 + */ + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + /* By default, no element should be set */ + EXPECT_FALSE(bitmap_is_set(bitmap, 0)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 0)); + + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + EXPECT_FALSE(bitmap_is_set(bitmap, size_not_pow2 - 1)); + EXPECT_TRUE(bitmap_is_unset(bitmap, size_not_pow2 - 1)); + + /* Bitmap should not have been reallocated */ + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + /* After setting a bit after the end, bitmap should have been reallocated */ + bitmap_set(bitmap, sizeof(bitmap[0]) * 8 - 1); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + /* After setting a bit after the end, bitmap should have been reallocated */ + rc = bitmap_set(bitmap, sizeof(bitmap[0]) * 8); + EXPECT_GE(rc, 0); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 2UL); + + rc = bitmap_set(bitmap, sizeof(bitmap[0]) * 8 + 1); + EXPECT_GE(rc, 0); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 2UL); + + bitmap_free(bitmap); + + size_t size_pow2 = 16; + + /* Limiting test for allocation size */ + bitmap_init(bitmap, size_pow2, 0); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + bitmap_free(bitmap); +} + +TEST_F(BitmapTest, BitmapSet) { + bitmap_init(bitmap, DEFAULT_SIZE, 0); + + bitmap_set(bitmap, 20); + EXPECT_TRUE(bitmap_is_set(bitmap, 20)); + EXPECT_FALSE(bitmap_is_unset(bitmap, 20)); + EXPECT_FALSE(bitmap_is_set(bitmap, 19)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 19)); + + bitmap_free(bitmap); +} + +TEST_F(BitmapTest, BitmapUnSet) { + bitmap_init(bitmap, DEFAULT_SIZE, 0); + + bitmap_set(bitmap, 20); + bitmap_set(bitmap, 19); + bitmap_unset(bitmap, 20); + EXPECT_FALSE(bitmap_is_set(bitmap, 20)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 20)); + EXPECT_TRUE(bitmap_is_set(bitmap, 19)); + EXPECT_FALSE(bitmap_is_unset(bitmap, 19)); + + bitmap_free(bitmap); +} + +TEST_F(BitmapTest, BitmapSetTo) { + bitmap_init(bitmap, DEFAULT_SIZE, 0); + + bitmap_set_to(bitmap, 40); + EXPECT_TRUE(bitmap_is_set(bitmap, 20)); + EXPECT_TRUE(bitmap_is_set(bitmap, 21)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 41)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 42)); + + bitmap_free(bitmap); +} diff --git a/hicn-light/src/hicn/test/test-configuration.cc b/hicn-light/src/hicn/test/test-configuration.cc new file mode 100644 index 000000000..b631bb20b --- /dev/null +++ b/hicn-light/src/hicn/test/test-configuration.cc @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + */ + +#include <gtest/gtest.h> + +extern "C" { +#include <hicn/config/configuration.h> +} + +static inline size_t CS_SIZE = 10; +static inline char CONFIG_FILE[] = "setup.conf"; +static inline int LOG_LEVEL = LOG_DEBUG; +static inline char LOG_FILE[] = "/dev/null"; +static inline uint16_t PORT = 1234; +static inline uint16_t CONF_PORT = 5678; +static inline bool IS_DAEMON_MODE = true; +static inline char PREFIX[] = "b001::/16"; +static inline char PREFIX_2[] = "c001::/16"; +static inline strategy_type_t STRATEGY_TYPE = STRATEGY_TYPE_BESTPATH; + +class ConfigurationTest : public ::testing::Test { + protected: + ConfigurationTest() { + config = configuration_create(); + log_conf.log_level = LOG_FATAL; + log_conf.log_file = NULL; + } + virtual ~ConfigurationTest() { configuration_free(config); } + + configuration_t *config; +}; + +TEST_F(ConfigurationTest, CreateConfiguration) { + // Check configuration creation + ASSERT_NE(config, nullptr); +} + +TEST_F(ConfigurationTest, SetGeneralParameters) { + configuration_set_cs_size(config, CS_SIZE); + size_t cs_size = configuration_get_cs_size(config); + EXPECT_EQ(cs_size, CS_SIZE); + + configuration_set_fn_config(config, CONFIG_FILE); + const char *config_file = configuration_get_fn_config(config); + EXPECT_EQ(config_file, CONFIG_FILE); + + configuration_set_port(config, PORT); + uint16_t port = configuration_get_port(config); + EXPECT_EQ(port, PORT); + + configuration_set_configuration_port(config, CONF_PORT); + uint16_t conf_port = configuration_get_configuration_port(config); + EXPECT_EQ(conf_port, CONF_PORT); + + configuration_set_daemon(config, IS_DAEMON_MODE); + bool is_daemon_mode = configuration_get_daemon(config); + EXPECT_EQ(is_daemon_mode, IS_DAEMON_MODE); +} + +TEST_F(ConfigurationTest, SetLogParameters) { + configuration_set_loglevel(config, LOG_LEVEL); + int log_level = configuration_get_loglevel(config); + EXPECT_EQ(log_level, LOG_LEVEL); + EXPECT_EQ(log_conf.log_level, LOG_LEVEL); + + configuration_set_logfile(config, LOG_FILE); + const char *log_file = configuration_get_logfile(config); + EXPECT_EQ(log_file, LOG_FILE); + int write_fd = configuration_get_logfile_fd(config); + EXPECT_NE(write_fd, -1); +} + +TEST_F(ConfigurationTest, SetStrategyParameter) { + configuration_set_strategy(config, PREFIX, STRATEGY_TYPE); + strategy_type_t strategy_type = configuration_get_strategy(config, PREFIX); + EXPECT_EQ(strategy_type, STRATEGY_TYPE); + + // Check strategy for non-registered prefix + strategy_type = configuration_get_strategy(config, PREFIX_2); + EXPECT_EQ(strategy_type, STRATEGY_TYPE_UNDEFINED); +} diff --git a/hicn-light/src/hicn/test/test-connection_table.cc b/hicn-light/src/hicn/test/test-connection_table.cc new file mode 100644 index 000000000..6bbf478e2 --- /dev/null +++ b/hicn-light/src/hicn/test/test-connection_table.cc @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/connection_table.h> +} + +#define CONNECTION_NAME "connection_name_test" +#define CONNECTION_NAME_2 "connection_name_test_2" + +class ConnectionTableTest : public ::testing::Test { + protected: + ConnectionTableTest() { + log_conf.log_level = LOG_INFO; + + conn_table_ = connection_table_create(); + pair_ = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + } + virtual ~ConnectionTableTest() { connection_table_free(conn_table_); } + + connection_table_t *conn_table_; + connection_t *connection_; + address_pair_t pair_; +}; + +TEST_F(ConnectionTableTest, CreateTable) { + /* Check connection_table allocation */ + EXPECT_NE(conn_table_, nullptr); + + /* Check connection_table size */ + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)0); +} + +TEST_F(ConnectionTableTest, AddConnection) { + // Add connection to connection table + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)1); + EXPECT_NE(connection_, nullptr); + + // Get connection by name and by pair + khiter_t k_name = kh_get_ct_name(conn_table_->id_by_name, CONNECTION_NAME); + EXPECT_NE(k_name, kh_end(conn_table_->id_by_name)); + khiter_t k_pair = kh_get_ct_pair(conn_table_->id_by_pair, &pair_); + EXPECT_NE(k_pair, kh_end(conn_table_->id_by_pair)); +} + +TEST_F(ConnectionTableTest, GetConnection) { + // Add connection to connection table + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)1); + EXPECT_NE(connection_, nullptr); + + // Get connection by name + connection_t *connection_retrieved = + connection_table_get_by_name(conn_table_, CONNECTION_NAME); + ASSERT_NE(connection_retrieved, nullptr); + EXPECT_EQ(connection_retrieved, connection_); + + // Get connection by pair + connection_retrieved = connection_table_get_by_pair(conn_table_, &pair_); + ASSERT_NE(connection_retrieved, nullptr); + EXPECT_EQ(connection_retrieved, connection_); +} + +TEST_F(ConnectionTableTest, GetConnectionWithIdOutOfRange) { + connection_t *connection = _connection_table_get_by_id(conn_table_, ~0); + EXPECT_EQ(connection, nullptr); +} + +TEST_F(ConnectionTableTest, GetConnectionWithInvalidId) { + // First connection inserted has always id equal to 0 + int non_valid_id = 5; + + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + connection_t *connection_not_found = + connection_table_get_by_id(conn_table_, non_valid_id); + ASSERT_EQ(connection_not_found, nullptr); +} + +TEST_F(ConnectionTableTest, GetConnectionWithValidId) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + int id = connection_table_get_connection_id(conn_table_, connection_); + connection_t *connection_found = connection_table_get_by_id(conn_table_, id); + ASSERT_EQ(connection_found, connection_); +} + +TEST_F(ConnectionTableTest, GetConnectionIdFromValidName) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + int id = connection_table_get_id_by_name(conn_table_, CONNECTION_NAME); + ASSERT_TRUE(listener_id_is_valid(id)); +} + +TEST_F(ConnectionTableTest, GetConnectionIdFromInvalidName) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + int id = connection_table_get_id_by_name(conn_table_, CONNECTION_NAME_2); + ASSERT_FALSE(listener_id_is_valid(id)); +} + +TEST_F(ConnectionTableTest, RemoveConnection) { + // Add connection (connection name and pair must be set) + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + connection_->name = (char *)CONNECTION_NAME; + connection_->pair = pair_; + + // Remove connection + int id = connection_table_get_connection_id(conn_table_, connection_); + connection_table_remove_by_id(conn_table_, id); + + // Check connection table size + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)0); + + // Check that previous connection is not valid anymore + connection_t *connection_not_found = + connection_table_get_by_id(conn_table_, id); + EXPECT_EQ(connection_not_found, nullptr); + connection_not_found = + connection_table_get_by_name(conn_table_, CONNECTION_NAME); + EXPECT_EQ(connection_not_found, nullptr); + connection_not_found = connection_table_get_by_pair(conn_table_, &pair_); + EXPECT_EQ(connection_not_found, nullptr); +} + +TEST_F(ConnectionTableTest, PrintTable) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + // Insert an additional connection + address_pair_t pair_2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(4)); + connection_t *connection_2 = + connection_table_allocate(conn_table_, &pair_2, CONNECTION_NAME_2); + connection_2->type = FACE_TYPE_TCP; + + testing::internal::CaptureStdout(); + connection_table_print_by_pair(conn_table_); + std::string std_out = testing::internal::GetCapturedStdout(); + + ASSERT_NE(std_out, ""); + + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:1")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:3")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:4")); +} + +TEST_F(ConnectionTableTest, AddMultipleConnections) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + // Insert an additional connection + address_pair_t pair_2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(4)); + connection_t *connection_2 = + connection_table_allocate(conn_table_, &pair_2, CONNECTION_NAME_2); + connection_2->type = FACE_TYPE_TCP; + + // Check connection table size + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)2); + + connection_t *c1 = connection_table_get_by_name(conn_table_, CONNECTION_NAME); + ASSERT_NE(c1, nullptr); + connection_t *c2 = + connection_table_get_by_name(conn_table_, CONNECTION_NAME_2); + ASSERT_NE(c2, nullptr); + EXPECT_NE(c1, c2); +} + +TEST_F(ConnectionTableTest, Iterate) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + connection_->pair = pair_; + + // Insert an additional connection + address_pair_t pair_2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(4)); + connection_t *connection_2 = + connection_table_allocate(conn_table_, &pair_2, CONNECTION_NAME_2); + connection_2->type = FACE_TYPE_TCP; + connection_2->pair = pair_2; + + // Iterate over the connection table and count the connections + connection_t *c; + int count = 0; + connection_table_foreach(conn_table_, c, { count++; }); + EXPECT_EQ(count, 2); + + // Iterate over the connection table and check the connections + char local_addr_str[NI_MAXHOST], remote_addr_str[NI_MAXHOST]; + int local_port, remote_port; + testing::internal::CaptureStdout(); + connection_table_foreach(conn_table_, c, { + const address_pair_t *pair = connection_get_pair(c); + address_to_string(&pair->local, local_addr_str, &local_port); + address_to_string(&pair->remote, remote_addr_str, &remote_port); + + printf("%s:%d\t%s:%d\n", local_addr_str, local_port, remote_addr_str, + remote_port); + }); + + std::string std_out = testing::internal::GetCapturedStdout(); + ASSERT_NE(std_out, ""); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:1")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:3")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:4")); +} diff --git a/hicn-light/src/hicn/test/test-ctrl.cc b/hicn-light/src/hicn/test/test-ctrl.cc new file mode 100644 index 000000000..77b16a8af --- /dev/null +++ b/hicn-light/src/hicn/test/test-ctrl.cc @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +extern "C" { +#include <hicn/util/log.h> +#include <hicn/ctrl.h> +#include <hicn/config/parse.h> +#include <hicn/ctrl/route.h> +#include <hicn/util/sstrncpy.h> +} + +class CtrlTest : public ::testing::Test { + protected: + CtrlTest() { + log_conf.log_level = LOG_INFO; + s_ = hc_sock_create_forwarder(HICNLIGHT_NG); + } + virtual ~CtrlTest() { hc_sock_free(s_); } + + hc_sock_t *s_ = nullptr; + hc_command_t command_ = {}; +}; + +/** + * The parse() function is used to easily create the command. + * Here we test the serialization of the commands i.e. from command + * to message sent to the forwarder. + */ + +TEST_F(CtrlTest, AddValidListener) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_TRUE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidProtocol) { + // Set invalid protocol (icmp) + std::string cmd = "add listener icmp udp0 10.0.0.1 9696 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidLocalPort) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid port + command_.object.listener.local_port = 0; + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidLocalAddress) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid family + command_.object.listener.family = -1; + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerEmptyLocalAddress) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid address + command_.object.listener.local_addr = IP_ADDRESS_EMPTY; + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidSymbolicName) { + std::string cmd = "add listener udp 0udp 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidSymbolicName2) { + std::string cmd = "add listener udp udp! 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidInterfaceName) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth/0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddValidRoute) { + std::string cmd = "add route conn0 c001::/64 1"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_route_create_conf(s_, &command_.object.route); + bool success = hc_result_get_success(s_, result); + EXPECT_TRUE(success); +} + +TEST_F(CtrlTest, AddRouteInvalidLength) { + std::string cmd = "add route conn0 c001::/64 1"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid prfix len + command_.object.route.len = MAX_IPV6_PREFIX_LEN + 1; + + hc_result_t *result = hc_route_create_conf(s_, &command_.object.route); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddRouteInvalidCost) { + std::string cmd = "add route conn0 c001::/64 1"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid cost + command_.object.route.cost = MAX_ROUTE_COST + 1; + + hc_result_t *result = hc_route_create_conf(s_, &command_.object.route); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); + + // Override with invalid cost + command_.object.route.cost = MIN_ROUTE_COST - 1; + + result = hc_route_create_conf(s_, &command_.object.route); + success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-hash.cc b/hicn-light/src/hicn/test/test-hash.cc new file mode 100644 index 000000000..2b72e194a --- /dev/null +++ b/hicn-light/src/hicn/test/test-hash.cc @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +// #include <hicn/transport/utils/hash.h> + +extern "C" { +#include <hicn/base/hash.h> +#include <hicn/core/address_pair.h> +#include <hicn/core/listener.h> +} + +TEST(HashTest, MultipleHashesForSameAddrPair) { + address_pair_t pair = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + + unsigned h1 = hash_struct(&pair); + unsigned h2 = hash_struct(&pair); + EXPECT_EQ(h1, h2); +} + +TEST(HashTest, SameAddrPairs) { + address_pair_t pair1 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + address_pair_t pair2 = pair1; + + unsigned h1 = hash_struct(&pair1); + unsigned h2 = hash_struct(&pair2); + EXPECT_EQ(h1, h2); +} + +TEST(HashTest, DifferentAddrPairs) { + address_pair_t pair1 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + + address_pair_t pair2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(4)); + + unsigned h1 = hash_struct(&pair1); + unsigned h2 = hash_struct(&pair2); + EXPECT_NE(h1, h2); +} + +TEST(HashTest, SameLocalDifferentRemote) { + address_pair_t pair1 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + + address_pair_t pair2 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(4)); + + unsigned h1 = hash_struct(&pair1); + unsigned h2 = hash_struct(&pair2); + EXPECT_NE(h1, h2); +} + +TEST(HashTest, SameRemoteDifferentLocal) { + address_pair_t pair1 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + + address_pair_t pair2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(2)); + + unsigned h1 = hash_struct(&pair1); + unsigned h2 = hash_struct(&pair2); + EXPECT_NE(h1, h2); +} + +TEST(HashTest, SameAddresses) { + address_t addr1 = _ADDRESS4_LOCALHOST(1); + address_t addr2 = _ADDRESS4_LOCALHOST(1); + + unsigned h1 = hash_struct(&addr1); + unsigned h2 = hash_struct(&addr2); + + EXPECT_EQ(h1, h2); +} + +TEST(HashTest, SameListenerKeys) { + listener_key_t key1 = + listener_key_factory(_ADDRESS4_LOCALHOST(1), FACE_TYPE_UDP_LISTENER); + listener_key_t key2 = + listener_key_factory(_ADDRESS4_LOCALHOST(1), FACE_TYPE_UDP_LISTENER); + + unsigned h1 = hash_struct(&key1); + unsigned h2 = hash_struct(&key2); + + EXPECT_EQ(h1, h2); +} + +TEST(HashTest, Collisions) { + uint32_t init_val = 2166136261UL; + (void)init_val; + + std::map<u32, uint32_t> hashes; + for (int i = 0; i < 50000; i++) { + uint32_t seg = i; + // u32 h = utils::hash::fnv32_buf (&seg, sizeof (seg)); + // u32 h = cumulative_hash32 (&seg, sizeof (seg), init_val); + u32 h = hash(&seg, sizeof(seg)); + EXPECT_FALSE(hashes.find(h) != hashes.end()) << seg << " - " << hashes[h]; + hashes[h] = seg; + } +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-khash.cc b/hicn-light/src/hicn/test/test-khash.cc new file mode 100644 index 000000000..4fcb48c31 --- /dev/null +++ b/hicn-light/src/hicn/test/test-khash.cc @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#include <hicn/base/khash.h> +} + +KHASH_MAP_INIT_INT(int, unsigned char) + +typedef struct { + unsigned key; + unsigned char val; +} int_unpack_t; + +typedef struct { + unsigned key; + unsigned char val; +} __attribute__((__packed__)) int_packed_t; + +#define hash_eq(a, b) ((a).key == (b).key) +#define hash_func(a) ((a).key) + +KHASH_INIT(iun, int_unpack_t, char, 0, hash_func, hash_eq) +KHASH_INIT(ipk, int_packed_t, char, 0, hash_func, hash_eq) + +class KHashTest : public ::testing::Test { + protected: + KHashTest() {} + + virtual ~KHashTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { khash = kh_init(int); } + + virtual void TearDown() { kh_destroy(int, khash); } + khash_t(int) * khash; +}; + +TEST_F(KHashTest, KhashIntSize) { + int ret; + int k; + int size = kh_size(khash); + + EXPECT_EQ(size, 0); + k = kh_put(int, khash, 10, &ret); + if (ret == 1) { + kh_val(khash, k) = 10; + } + size = kh_size(khash); + EXPECT_EQ(size, 1); +} + +TEST_F(KHashTest, KhashIntPut) { + int ret; + int k; + k = kh_put(int, khash, 10, &ret); + if (ret == 1) { + kh_val(khash, k) = 10; + } + int size = kh_size(khash); + EXPECT_EQ(size, 1); + k = kh_put(int, khash, 20, &ret); + if (ret == 1) { + kh_val(khash, k) = 20; + } + size = kh_size(khash); + EXPECT_EQ(size, 2); +} + +TEST_F(KHashTest, KhashCheckValue) { + int ret; + int k; + k = kh_put(int, khash, 10, &ret); + if (ret == 1) { + kh_val(khash, k) = 100; + } + k = kh_put(int, khash, 20, &ret); + if (ret == 1) { + kh_val(khash, k) = 200; + } + + k = kh_put(int, khash, 10, &ret); + int val = -1; + if (!ret) val = kh_val(khash, k); + EXPECT_EQ(val, 100); + + k = kh_put(int, khash, 20, &ret); + val = -1; + if (!ret) val = kh_val(khash, k); + EXPECT_EQ(val, 200); +} + +// Check that there are no collisions in case of same key hash +typedef struct { + int x; +} Key; +#define hash_key(key) 1 // Hash is always 1 to simulate collisions +#define key_hash_eq(a, b) (a->x == b->x) // Function used in case of collisions +KHASH_INIT(test_map, const Key *, unsigned, 1, hash_key, key_hash_eq); + +TEST_F(KHashTest, Collisions) { + int ret; + khiter_t k; + + kh_test_map_t *map = kh_init(test_map); + Key key1 = {.x = 10}; + Key key2 = {.x = 11}; + + k = kh_put_test_map(map, &key1, &ret); + EXPECT_EQ(ret, 1); + kh_val(map, k) = 15; + + k = kh_put_test_map(map, &key2, &ret); + EXPECT_EQ(ret, 1); + kh_val(map, k) = 27; + + k = kh_get_test_map(map, &key1); + ASSERT_NE(k, kh_end(map)); + unsigned val = kh_val(map, k); + EXPECT_EQ(val, 15u); + + k = kh_get_test_map(map, &key2); + ASSERT_NE(k, kh_end(map)); + val = kh_val(map, k); + EXPECT_EQ(val, 27u); + + kh_destroy_test_map(map); +} diff --git a/hicn-light/src/hicn/test/test-listener_table.cc b/hicn-light/src/hicn/test/test-listener_table.cc new file mode 100644 index 000000000..b2ed0c276 --- /dev/null +++ b/hicn-light/src/hicn/test/test-listener_table.cc @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/listener_table.h> +} + +#define LISTENER_NAME "listener_name_test" +#define LISTENER_NAME_2 "listener_name_test_2" + +class ListenerTableTest : public ::testing::Test { + protected: + ListenerTableTest() { + log_conf.log_level = LOG_INFO; + + listener_table_ = listener_table_create(); + key_ = listener_key_factory(_ADDRESS4_LOCALHOST(1), FACE_TYPE_UDP_LISTENER); + } + virtual ~ListenerTableTest() { listener_table_free(listener_table_); } + + listener_table_t *listener_table_; + listener_t *listener_; + listener_key_t key_; +}; + +TEST_F(ListenerTableTest, CreateTable) { + // Check listener_table allocation + EXPECT_NE(listener_table_, nullptr); + + // Check listener_table size + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)0); +} + +TEST_F(ListenerTableTest, AddListener) { + // Add listener to listener table + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)1); + EXPECT_NE(listener_, nullptr); + + // Get listener by name and by key + khiter_t k_name = kh_get_lt_name(listener_table_->id_by_name, LISTENER_NAME); + EXPECT_NE(k_name, kh_end(listener_table_->id_by_name)); + khiter_t k_key = kh_get_lt_key(listener_table_->id_by_key, &key_); + EXPECT_NE(k_key, kh_end(listener_table_->id_by_key)); +} + +TEST_F(ListenerTableTest, GetListener) { + // Add listener to listener table + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)1); + ASSERT_NE(listener_, nullptr); + + // Get listener by name + listener_t *listener_retrieved = + listener_table_get_by_name(listener_table_, LISTENER_NAME); + ASSERT_NE(listener_retrieved, nullptr); + EXPECT_EQ(listener_retrieved, listener_); + + // Get listener by key + listener_retrieved = listener_table_get_by_key(listener_table_, &key_); + ASSERT_NE(listener_retrieved, nullptr); + EXPECT_EQ(listener_retrieved, listener_); +} + +TEST_F(ListenerTableTest, GetListenerWithIdOutOfRange) { + listener_t *listener = _listener_table_get_by_id(listener_table_, ~0); + EXPECT_EQ(listener, nullptr); +} + +TEST_F(ListenerTableTest, GetListenerWithInvalidId) { + // First listener inserted has always id equal to 0 + int non_valid_id = 5; + + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + listener_t *listener_not_found = + listener_table_get_by_id(listener_table_, non_valid_id); + ASSERT_EQ(listener_not_found, nullptr); +} + +TEST_F(ListenerTableTest, GetListenerWithValidId) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + int id = listener_table_get_listener_id(listener_table_, listener_); + listener_t *listener_found = listener_table_get_by_id(listener_table_, id); + ASSERT_EQ(listener_found, listener_); +} + +TEST_F(ListenerTableTest, GetListenerIdFromValidName) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + int id = listener_table_get_id_by_name(listener_table_, LISTENER_NAME); + ASSERT_TRUE(listener_id_is_valid(id)); +} + +TEST_F(ListenerTableTest, GetListenerIdFromInvalidName) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + int id = listener_table_get_id_by_name(listener_table_, LISTENER_NAME_2); + ASSERT_FALSE(listener_id_is_valid(id)); +} + +TEST_F(ListenerTableTest, RemoveListener) { + // Add listener (listerner name and key must be set) + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + listener_->name = (char *)LISTENER_NAME; + listener_->key = key_; + + // Remove listener + int id = listener_table_get_listener_id(listener_table_, listener_); + listener_table_remove_by_id(listener_table_, id); + + // Check listener table size + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)0); + + // Check that previous listener is not valid anymore + listener_t *listener_not_found = + listener_table_get_by_id(listener_table_, id); + EXPECT_EQ(listener_not_found, nullptr); + listener_not_found = + listener_table_get_by_name(listener_table_, LISTENER_NAME); + EXPECT_EQ(listener_not_found, nullptr); + listener_not_found = listener_table_get_by_key(listener_table_, &key_); + EXPECT_EQ(listener_not_found, nullptr); +} + +TEST_F(ListenerTableTest, PrintTable) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + // Insert an additional listener + listener_key_t key_2 = + listener_key_factory(_ADDRESS4_LOCALHOST(2), FACE_TYPE_TCP_LISTENER); + listener_t *listener_2 = + listener_table_allocate(listener_table_, &key_2, LISTENER_NAME_2); + listener_2->type = FACE_TYPE_UDP_LISTENER; + + testing::internal::CaptureStdout(); + listener_table_print_by_key(listener_table_); + std::string std_out = testing::internal::GetCapturedStdout(); + + ASSERT_NE(std_out, ""); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:1")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); +} + +TEST_F(ListenerTableTest, AddMultipleListeners) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + // Insert an additional listener + listener_key_t key_2 = + listener_key_factory(_ADDRESS4_LOCALHOST(2), FACE_TYPE_TCP_LISTENER); + listener_t *listener_2 = + listener_table_allocate(listener_table_, &key_2, LISTENER_NAME_2); + listener_2->type = FACE_TYPE_UDP_LISTENER; + + // Check listener table size + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)2); + + listener_t *l1 = listener_table_get_by_name(listener_table_, LISTENER_NAME); + ASSERT_NE(l1, nullptr); + listener_t *l2 = listener_table_get_by_name(listener_table_, LISTENER_NAME_2); + ASSERT_NE(l2, nullptr); + EXPECT_NE(l1, l2); +} + +TEST_F(ListenerTableTest, Iterate) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + listener_->key = key_; + + // Insert an additional listener + listener_key_t key_2 = + listener_key_factory(_ADDRESS4_LOCALHOST(2), FACE_TYPE_TCP_LISTENER); + listener_t *listener_2 = + listener_table_allocate(listener_table_, &key_2, LISTENER_NAME_2); + listener_2->type = FACE_TYPE_UDP_LISTENER; + listener_2->key = key_2; + + // Iterate over the listener table and count the listeners + listener_t *l; + int count = 0; + listener_table_foreach(listener_table_, l, { count++; }); + EXPECT_EQ(count, 2); + + // Iterate over the listener table and check the listeners + char addr_str[NI_MAXHOST]; + int port; + testing::internal::CaptureStdout(); + listener_table_foreach(listener_table_, l, { + address_to_string(&l->address, addr_str, &port); + printf("%s\t%s:%d\n", face_type_str(l->type), addr_str, port); + }); + + std::string std_out = testing::internal::GetCapturedStdout(); + ASSERT_NE(std_out, ""); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:1")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); + EXPECT_THAT(std_out, testing::HasSubstr("UDP")); + EXPECT_THAT(std_out, testing::HasSubstr("TCP")); +} diff --git a/hicn-light/src/hicn/test/test-local_prefixes.cc b/hicn-light/src/hicn/test/test-local_prefixes.cc new file mode 100644 index 000000000..80eb46501 --- /dev/null +++ b/hicn-light/src/hicn/test/test-local_prefixes.cc @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <arpa/inet.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/strategies/local_prefixes.h> +#include <hicn/core/strategy.h> +#include <hicn/core/name.h> +} + +const char *name_str1 = "b001::0"; +const char *name_str2 = "b002::0"; +const char *name_str3 = "b003::0"; +const char *name_str4 = "b004::0"; +const char *name_str5 = "b005::0"; +const char *name_str6 = "b006::0"; +const char *name_str7 = "b007::0"; +const char *name_str8 = "b008::0"; +const char *name_str9 = "b009::0"; +const char *name_str10 = "b010::0"; +const char *name_str11 = "b011::0"; + +class LocalPrefixesTest : public ::testing::Test { + protected: + LocalPrefixesTest() {} + + virtual ~LocalPrefixesTest() {} +}; + +TEST_F(LocalPrefixesTest, LocalPrefixesAddName) { + local_prefixes_t *lp = create_local_prefixes(); + EXPECT_FALSE(lp == nullptr); + + ip_address_t result; + inet_pton(AF_INET6, name_str1, (struct in6_addr *)&result); + Name name1; + name_CreateFromAddress(&name1, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str2, (struct in6_addr *)&result); + Name name2; + name_CreateFromAddress(&name2, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str3, (struct in6_addr *)&result); + Name name3; + name_CreateFromAddress(&name3, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str4, (struct in6_addr *)&result); + Name name4; + name_CreateFromAddress(&name4, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str5, (struct in6_addr *)&result); + Name name5; + name_CreateFromAddress(&name5, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str6, (struct in6_addr *)&result); + Name name6; + name_CreateFromAddress(&name6, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str7, (struct in6_addr *)&result); + Name name7; + name_CreateFromAddress(&name7, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str8, (struct in6_addr *)&result); + Name name8; + name_CreateFromAddress(&name8, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str9, (struct in6_addr *)&result); + Name name9; + name_CreateFromAddress(&name9, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str10, (struct in6_addr *)&result); + Name name10; + name_CreateFromAddress(&name10, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str11, (struct in6_addr *)&result); + Name name11; + name_CreateFromAddress(&name11, AF_INET6, result, 128); + + local_prefixes_add_prefix(lp, &name1); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)1); + + local_prefixes_add_prefix(lp, &name1); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)1); + + local_prefixes_add_prefix(lp, &name2); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)2); + + local_prefixes_add_prefix(lp, &name2); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)2); + + local_prefixes_add_prefix(lp, &name3); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)3); + + local_prefixes_add_prefix(lp, &name4); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)4); + + local_prefixes_add_prefix(lp, &name5); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)5); + + local_prefixes_add_prefix(lp, &name6); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)6); + + local_prefixes_add_prefix(lp, &name7); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)7); + + local_prefixes_add_prefix(lp, &name8); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)8); + + local_prefixes_add_prefix(lp, &name9); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)9); + + local_prefixes_add_prefix(lp, &name10); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)10); + + local_prefixes_add_prefix(lp, &name11); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)10); + + free_local_prefixes(lp); +} + +TEST_F(LocalPrefixesTest, LocalPrefixesAddPrefixes) { + local_prefixes_t *lp = create_local_prefixes(); + EXPECT_FALSE(lp == nullptr); + + ip_address_t result; + + local_prefixes_t *lp1 = create_local_prefixes(); + EXPECT_FALSE(lp1 == nullptr); + + inet_pton(AF_INET6, name_str1, (struct in6_addr *)&result); + Name name1; + name_CreateFromAddress(&name1, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str2, (struct in6_addr *)&result); + Name name2; + name_CreateFromAddress(&name2, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str3, (struct in6_addr *)&result); + Name name3; + name_CreateFromAddress(&name3, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str4, (struct in6_addr *)&result); + Name name4; + name_CreateFromAddress(&name4, AF_INET6, result, 128); + + local_prefixes_add_prefix(lp1, &name1); + local_prefixes_add_prefix(lp1, &name2); + local_prefixes_add_prefix(lp1, &name3); + local_prefixes_add_prefix(lp1, &name4); + + EXPECT_EQ(local_prefixes_get_len(lp1), (unsigned)4); + + local_prefixes_add_prefixes(lp, lp1); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)4); + + local_prefixes_add_prefixes(lp, lp1); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)4); + + local_prefixes_t *lp2 = create_local_prefixes(); + EXPECT_FALSE(lp2 == nullptr); + + inet_pton(AF_INET6, name_str5, (struct in6_addr *)&result); + Name name5; + name_CreateFromAddress(&name5, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str6, (struct in6_addr *)&result); + Name name6; + name_CreateFromAddress(&name6, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str7, (struct in6_addr *)&result); + Name name7; + name_CreateFromAddress(&name7, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str8, (struct in6_addr *)&result); + Name name8; + name_CreateFromAddress(&name8, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str9, (struct in6_addr *)&result); + Name name9; + name_CreateFromAddress(&name9, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str10, (struct in6_addr *)&result); + Name name10; + name_CreateFromAddress(&name10, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str11, (struct in6_addr *)&result); + Name name11; + name_CreateFromAddress(&name11, AF_INET6, result, 128); + + local_prefixes_add_prefix(lp2, &name5); + local_prefixes_add_prefix(lp2, &name6); + local_prefixes_add_prefix(lp2, &name7); + local_prefixes_add_prefix(lp2, &name8); + local_prefixes_add_prefix(lp2, &name9); + local_prefixes_add_prefix(lp2, &name10); + local_prefixes_add_prefix(lp2, &name11); + + EXPECT_EQ(local_prefixes_get_len(lp2), (unsigned)7); + + local_prefixes_add_prefixes(lp, lp2); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)10); + + free_local_prefixes(lp); + free_local_prefixes(lp1); + free_local_prefixes(lp2); +} diff --git a/hicn-light/src/hicn/test/test-loop.cc b/hicn-light/src/hicn/test/test-loop.cc new file mode 100644 index 000000000..f783b0ada --- /dev/null +++ b/hicn-light/src/hicn/test/test-loop.cc @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> +#include <fcntl.h> + +extern "C" { +#include <hicn/base/loop.h> +} + +class LoopTest : public ::testing::Test { + static constexpr uint16_t BUFFER_SIZE = 1024; + + protected: + LoopTest() + : server_port_(9191), + loop_(nullptr), + timer_tick_(2000), + connection_socket_(-1), + event_(nullptr), + timer_(nullptr) {} + + virtual ~LoopTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { + // Code here will be called immediately after the constructor (right + // before each test). + } + + virtual void TearDown() { + // Code here will be called immediately after each test (right + // before the destructor). + } + + static int onFirstTimerExpiration(void *owner, int fd, void *arg) { + std::cout << "This function should never be called" << std::endl; + EXPECT_TRUE(false); + return -1; + } + + static int onSecondTimerExpiration(void *owner, int fd, void *arg) { + std::cout << "First timer expired. Cancel second timer." << std::endl; + LoopTest *test = (LoopTest *)(arg); + loop_event_unregister(test->timer_); + return 0; + } + + static int onTimerExpiration(void *owner, int fd, void *arg) { + // Create client socket + struct sockaddr_in addr; + int client_socket; + LoopTest *test = (LoopTest *)(arg); + + client_socket = socket(AF_INET, SOCK_STREAM, 0); + if (client_socket == -1) { + perror("socket"); + return -1; + } + + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_family = AF_INET; + addr.sin_port = htons(test->server_port_); + + if (connect(client_socket, (struct sockaddr *)&addr, + sizeof(struct sockaddr)) == -1) { + perror("connect"); + return -1; + } + + if (send(client_socket, "Hello, world!\n", 14, 0) == -1) { + perror("send"); + return -1; + } + + close(client_socket); + loop_event_unregister(test->timer_); + + return 0; + } + + static int onNewConnection(void *owner, int fd, void *arg) { + LoopTest *test = (LoopTest *)arg; + struct sockaddr_in addr; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = AF_INET; + + socklen_t addr_len = sizeof(struct sockaddr_in); + int ret; + + int client_fd = + accept(test->connection_socket_, (struct sockaddr *)(&addr), &addr_len); + if (client_fd == -1) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "accept failed"); + } + + perror("accept"); + return -1; + } + + // Read whatever data available and close connection. + ret = read(client_fd, test->buffer, BUFFER_SIZE); + if (ret < 0) { + perror("read"); + return -1; + } + + test->buffer[ret] = '\0'; + std::cout << "Received: " << (char *)test->buffer << std::endl; + + close(client_fd); + loop_event_unregister(test->event_); + + return 0; + } + + void createTcpSocketServer() { + struct sockaddr_in addr; + int ret; + + /* Create local socket. */ + + connection_socket_ = socket(AF_INET, SOCK_STREAM, 0); + if (connection_socket_ == -1) { + perror("socket"); + return; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(server_port_); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(connection_socket_, (const struct sockaddr *)&addr, + sizeof(struct sockaddr_in)); + if (ret == -1) { + perror("bind"); + return; + } + + ret = listen(connection_socket_, 20); + if (ret == -1) { + perror("listen"); + return; + } + } + + uint16_t server_port_; + loop_t *loop_; + unsigned timer_tick_; + int connection_socket_; + event_t *event_; + event_t *timer_; + char buffer[BUFFER_SIZE]; +}; + +TEST_F(LoopTest, LoopCreateAndFree) { + loop_ = loop_create(); + EXPECT_TRUE(loop_ != NULL); + loop_free(loop_); + EXPECT_TRUE(loop_ != NULL); +} + +TEST_F(LoopTest, EventCreateAndFree) { + int ret; + + // Fake fd + int fd = socket(AF_INET, SOCK_STREAM, 0); + loop_ = loop_create(); + + ret = loop_fd_event_create(&event_, loop_, fd, nullptr, + &LoopTest::onNewConnection, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(event_); + + // Register the event + ret = loop_fd_event_register(event_); + EXPECT_TRUE(ret >= 0); + + // Unregister the event + ret = loop_event_free(event_); + EXPECT_TRUE(ret >= 0); + + // close fd + ret = close(fd); + EXPECT_EQ(ret, 0); + + // Free event loop + loop_free(loop_); +} + +TEST_F(LoopTest, TimerCreateAndCancel) { + int ret; + event_t *timer2; + loop_ = loop_create(); + + ret = loop_timer_create(&timer_, loop_, nullptr, + &LoopTest::onFirstTimerExpiration, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer_); + + ret = loop_timer_create(&timer2, loop_, nullptr, + &LoopTest::onSecondTimerExpiration, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer2); + + // Register the 1st timer + ret = loop_timer_register(timer_, timer_tick_); + EXPECT_TRUE(ret >= 0); + + // Register the 2nd timer + ret = loop_timer_register(timer2, timer_tick_ / 2); + EXPECT_TRUE(ret >= 0); + + _loop_dispatch(loop_, 0); + + loop_undispatch(loop_); + + // Unregister the events + ret = loop_event_free(timer_); + ret += loop_event_free(timer2); + EXPECT_TRUE(ret >= 0); + + // Free event loop + loop_free(loop_); +} + +TEST_F(LoopTest, LoopDispatch) { + int ret; + + // Create new unix socket + createTcpSocketServer(); + loop_ = loop_create(); + + ret = loop_fd_event_create(&event_, loop_, connection_socket_, nullptr, + &LoopTest::onNewConnection, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(event_); + + ret = loop_fd_event_register(event_); + EXPECT_TRUE(ret >= 0); + + // Create timer. + ret = loop_timer_create(&timer_, loop_, nullptr, &LoopTest::onTimerExpiration, + this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer_); + + ret = loop_timer_register(timer_, timer_tick_); + EXPECT_TRUE(ret >= 0); + + // Start event dispatching + _loop_dispatch(loop_, 0); + + // Stop dispatching + loop_undispatch(loop_); + + // Free events + loop_event_free(timer_); + loop_event_free(event_); + + // Free event loop + loop_free(loop_); +} diff --git a/hicn-light/src/hicn/test/test-msgbuf_pool.cc b/hicn-light/src/hicn/test/test-msgbuf_pool.cc new file mode 100644 index 000000000..5537aa216 --- /dev/null +++ b/hicn-light/src/hicn/test/test-msgbuf_pool.cc @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/msgbuf_pool.h> +#include <hicn/base/pool.h> +} + +class MsgbufPoolTest : public ::testing::Test { + protected: + MsgbufPoolTest() { msgbuf_pool = msgbuf_pool_create(); } + virtual ~MsgbufPoolTest() { msgbuf_pool_free(msgbuf_pool); } + + msgbuf_pool_t *msgbuf_pool; +}; + +TEST_F(MsgbufPoolTest, Create) { + /* Check msgbuf_pool allocation */ + EXPECT_NE(msgbuf_pool, nullptr); + + /* Check msgbuf_pool size */ + size_t msgbuf_pool_size = pool_hdr(msgbuf_pool->buffers)->alloc_size; + EXPECT_EQ(msgbuf_pool_size, (size_t)PACKET_POOL_DEFAULT_INIT_SIZE); +} + +TEST_F(MsgbufPoolTest, GetMsgbuf) { + msgbuf_t *msgbuf = NULL; + + /* Get valid msgbuf from msgbuf_pool */ + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + /* Check if the returned id is correct */ + off_t id = msgbuf_pool_get_id(msgbuf_pool, msgbuf); + EXPECT_EQ(id, msgbuf_id); + + /* Check if the returned msgbuf is correct */ + msgbuf_t *msgbuf_retrieved = msgbuf_pool_at(msgbuf_pool, id); + EXPECT_EQ(msgbuf_retrieved, msgbuf); +} + +TEST_F(MsgbufPoolTest, PutMsgbuf) { + /* Check that asking a msgbuf right after releasing another one + returns the same msgbuf */ + + msgbuf_t *msgbuf = NULL; + + off_t id1 = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + + msgbuf_pool_put(msgbuf_pool, msgbuf); + + off_t id2 = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + + EXPECT_EQ(id2, id1); +} + +TEST_F(MsgbufPoolTest, GetMultipleMsgbufs) { + const int NUM_MSG = 3; + msgbuf_t *msgbufs[NUM_MSG]; + + /* Check if successful allocation */ + int ret = msgbuf_pool_getn(msgbuf_pool, msgbufs, NUM_MSG); + EXPECT_EQ(ret, 0); + + /* Check if all msgbufs are valid */ + for (unsigned i = 0; i < NUM_MSG; i++) { + msgbuf_pool_get_id(msgbuf_pool, msgbufs[i]); + EXPECT_NE(msgbufs[i], nullptr) << "Invalid index: " << i; + } +} + +TEST_F(MsgbufPoolTest, AcquireMsgbuf) { + msgbuf_t *msgbuf = NULL; + + // Get msgbuf from msgbuf_pool + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + // Acquire the msgbuf + msgbuf_pool_acquire(msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_EQ(msgbuf->refs, 1u); + + msgbuf_pool_acquire(msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_EQ(msgbuf->refs, 2u); +} + +TEST_F(MsgbufPoolTest, ReleaseMsgbuf) { + msgbuf_t *msgbuf = NULL; + + // Get msgbuf from msgbuf_pool + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + // Acquire the msgbuf + msgbuf_pool_acquire(msgbuf); + EXPECT_EQ(msgbuf->refs, 1u); + + // Release the msgbuf + msgbuf_pool_release(msgbuf_pool, &msgbuf); + EXPECT_EQ(msgbuf, nullptr); +} + +TEST_F(MsgbufPoolTest, ReleaseNotAcquiredMsgbuf) { + msgbuf_t *msgbuf = NULL; + + // Get valid msgbuf from msgbuf_pool + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + +#ifndef NDEBUG + // Release the msgbuf even if it is not been acquired + ASSERT_DEATH( + { + msgbuf_pool_release(msgbuf_pool, &msgbuf); + ; + }, + ".*Assertion.*"); +#endif +} + +TEST_F(MsgbufPoolTest, MultipleAcquireAndReleaseMsgbuf) { + msgbuf_t *msgbuf = NULL; + + // Get msgbuf from msgbuf_pool + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + // Acquire the msgbuf multiple times + msgbuf_pool_acquire(msgbuf); + msgbuf_pool_acquire(msgbuf); + EXPECT_EQ(msgbuf->refs, 2u); + + // Release the msgbuf + msgbuf_pool_release(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_EQ(msgbuf->refs, 1u); + msgbuf_pool_release(msgbuf_pool, &msgbuf); + EXPECT_EQ(msgbuf, nullptr); +} + +TEST_F(MsgbufPoolTest, CloneMsgbuf) { + msgbuf_t *msgbuf = NULL; + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + msgbuf_t *new_msgbuf; + off_t new_msg_id = msgbuf_pool_clone(msgbuf_pool, &new_msgbuf, msgbuf_id); + + EXPECT_EQ(new_msgbuf, msgbuf_pool_at(msgbuf_pool, new_msg_id)); + EXPECT_NE(new_msgbuf, msgbuf_pool_at(msgbuf_pool, msgbuf_id)); + EXPECT_NE(new_msgbuf, msgbuf); + EXPECT_TRUE(memcmp(msgbuf, new_msgbuf, sizeof(msgbuf_t)) == 0); +} diff --git a/hicn-light/src/hicn/test/test-nexthops.cc b/hicn-light/src/hicn/test/test-nexthops.cc new file mode 100644 index 000000000..9063298fd --- /dev/null +++ b/hicn-light/src/hicn/test/test-nexthops.cc @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/nexthops.h> +#include <hicn/core/strategy.h> +} + +#define NEXTHOP1 50 +#define NEXTHOP2 51 +#define NEXTHOP3 52 + +class NexthopsTest : public ::testing::Test { + protected: + NexthopsTest() {} + + virtual ~NexthopsTest() {} + + nexthops_t nexthops; +}; + +TEST_F(NexthopsTest, NexthopsAdd) { + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 1); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsRemove) { + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_remove(&nexthops, NEXTHOP2); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 2); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_remove(&nexthops, NEXTHOP3); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 1); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_remove(&nexthops, NEXTHOP3); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 1); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_remove(&nexthops, NEXTHOP1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 0); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsClear) { + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_clear(&nexthops); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 0); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsGetOne) { + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + unsigned nexthop = nexthops_get_one(&nexthops); + + EXPECT_TRUE(nexthops_contains(&nexthops, nexthop)); +} + +TEST_F(NexthopsTest, NexthopsSelect) { + int ret; + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + ret = nexthops_select(&nexthops, 2); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 1); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_select(&nexthops, 0); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 1); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_reset(&nexthops); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_select(&nexthops, 4); + + EXPECT_TRUE(ret == -1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_select(&nexthops, 3); + + EXPECT_TRUE(ret == -1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsDisable) { + int ret; + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + ret = nexthops_disable(&nexthops, 0); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 2); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_disable(&nexthops, 2); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 1); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_disable(&nexthops, 3); + EXPECT_TRUE(ret == -1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 1); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsState) { + strategy_nexthop_state_t state; + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + nexthops.state[0].load_balancer.pi = 100; + nexthops.state[1].load_balancer.pi = 200; + nexthops.state[2].load_balancer.pi = 300; + + state = nexthops_state(&nexthops, 0); + EXPECT_TRUE(state.load_balancer.pi == 100); + + state = nexthops_state(&nexthops, 1); + EXPECT_TRUE(state.load_balancer.pi == 200); + + state = nexthops_state(&nexthops, 2); + EXPECT_TRUE(state.load_balancer.pi == 300); + + nexthops_remove(&nexthops, NEXTHOP1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 2); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + state = nexthops_state(&nexthops, 0); + EXPECT_TRUE(state.load_balancer.pi == 300); + + state = nexthops_state(&nexthops, 1); + EXPECT_TRUE(state.load_balancer.pi == 200); +} + +TEST_F(NexthopsTest, NexthopsEqual) { + nexthops = NEXTHOPS_EMPTY; + nexthops_t nexthops_eq = NEXTHOPS_EMPTY; + nexthops_t nexthops_not_eq = NEXTHOPS_EMPTY; + + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP3); + nexthops_add(&nexthops_eq, NEXTHOP1); + nexthops_add(&nexthops_eq, NEXTHOP3); + nexthops_add(&nexthops_not_eq, NEXTHOP2); + + bool ret = nexthops_equal(&nexthops, &nexthops_eq); + EXPECT_TRUE(ret); + + ret = nexthops_equal(&nexthops, &nexthops_not_eq); + EXPECT_FALSE(ret); +} + +TEST_F(NexthopsTest, NexthopsCopy) { + nexthops = NEXTHOPS_EMPTY; + nexthops_t nexthops_eq = NEXTHOPS_EMPTY; + + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP3); + nexthops_copy(&nexthops, &nexthops_eq); + + bool ret = nexthops_equal(&nexthops, &nexthops_eq); + EXPECT_TRUE(ret); +} diff --git a/hicn-light/src/hicn/test/test-packet_cache.cc b/hicn-light/src/hicn/test/test-packet_cache.cc new file mode 100644 index 000000000..bb24daeb8 --- /dev/null +++ b/hicn-light/src/hicn/test/test-packet_cache.cc @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <thread> +#include <optional> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/packet_cache.h> +} + +const unsigned CS_SIZE = 100; +const unsigned CONN_ID = 0; +const unsigned CONN_ID_2 = 1; +const unsigned MSGBUF_ID = 0; +const unsigned MSGBUF_ID_2 = 1; +const unsigned MSGBUF_ID_3 = 2; +const unsigned FIVE_SECONDS = 5000; +const unsigned IPV4_LEN = 32; +const unsigned IPV6_LEN = 128; + +class PacketCacheTest : public ::testing::Test { + protected: + PacketCacheTest() { + pkt_cache = pkt_cache_create(CS_SIZE); + name = (Name *)malloc(sizeof(Name)); + name_CreateFromAddress(name, AF_INET, IPV4_ANY, IPV4_LEN); + msgbuf_pool = msgbuf_pool_create(); + } + virtual ~PacketCacheTest() { + pkt_cache_free(pkt_cache); + msgbuf_pool_free(msgbuf_pool); + } + + pkt_cache_t *pkt_cache; + pkt_cache_entry_t *entry = nullptr; + msgbuf_pool_t *msgbuf_pool; + Name *name; +}; + +msgbuf_t *msgbuf_factory(msgbuf_pool_t *msgbuf_pool, unsigned conn_id, + Name *name, + std::optional<Ticks> lifetime = FIVE_SECONDS) { + msgbuf_t *msgbuf; + msgbuf_pool_get(msgbuf_pool, &msgbuf); + + msgbuf->connection_id = conn_id; + name_Copy(name, msgbuf_get_name(msgbuf)); + hicn_packet_init_header(HF_INET6_TCP, + (hicn_header_t *)msgbuf_get_packet(msgbuf)); + // Same as 'msgbuf_set_data_expiry_time', + // it would write in the same field + msgbuf_set_interest_lifetime(msgbuf, *lifetime); + + return msgbuf; +} + +TEST_F(PacketCacheTest, CreatePacketCache) { + // Check packet cache allocation + EXPECT_NE(pkt_cache, nullptr); + pit_t *pit = pkt_cache_get_pit(pkt_cache); + ASSERT_NE(pit, nullptr); + cs_t *cs = pkt_cache_get_cs(pkt_cache); + ASSERT_NE(cs, nullptr); + + // Check sizes + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); +} + +TEST_F(PacketCacheTest, AddPacketCacheEntry) { + // Add entry to the packet cache + entry = pkt_cache_allocate(pkt_cache, name); + EXPECT_NE(entry, nullptr); + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 1u); + + // // Get entry by name + Name name_key = name_key_factory(name); + khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); + EXPECT_NE(k, kh_end(pkt_cache->index_by_name)); +} + +TEST_F(PacketCacheTest, GetCS) { + cs_t *cs = pkt_cache_get_cs(pkt_cache); + ASSERT_NE(cs, nullptr); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + EXPECT_EQ(cs->type, CS_TYPE_LRU); + EXPECT_EQ(cs->num_entries, 0); + EXPECT_EQ(cs->lru.head, (off_t)INVALID_ENTRY_ID); + EXPECT_EQ(cs->lru.tail, (off_t)INVALID_ENTRY_ID); +} + +TEST_F(PacketCacheTest, GetPIT) { + pit_t *pit = pkt_cache_get_pit(pkt_cache); + ASSERT_NE(pit, nullptr); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); +} + +TEST_F(PacketCacheTest, LookupEmpty) { + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *entry = pkt_cache_lookup(pkt_cache, name, msgbuf_pool, + &lookup_result, &entry_id, true); + + EXPECT_EQ(lookup_result, PKT_CACHE_LU_NONE); + EXPECT_EQ(entry, nullptr); +} + +TEST_F(PacketCacheTest, AddEntryAndLookup) { + // Add entry to the packet cache + entry = pkt_cache_allocate(pkt_cache, name); + entry->entry_type = PKT_CACHE_PIT_TYPE; + ASSERT_NE(entry, nullptr); + + // Perform lookup + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + + EXPECT_TRUE(lookup_result == PKT_CACHE_LU_INTEREST_NOT_EXPIRED || + lookup_result == PKT_CACHE_LU_INTEREST_EXPIRED); + EXPECT_NE(lu_entry, nullptr); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, AddToPIT) { + // Prepare msgbuf + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + + // Check if entry properly created + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID), true); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, AddToCS) { + // Prepare msgbuf + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + + // Check if entry properly created + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + cs_entry_t *cs_entry = &entry->u.cs_entry; + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_CS_TYPE); + EXPECT_EQ(cs_entry->msgbuf_id, MSGBUF_ID); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + // Check if CS properly updated + cs_t *cs = pkt_cache_get_cs(pkt_cache); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + EXPECT_EQ(cs->num_entries, 1); + EXPECT_EQ(cs->lru.head, entry_id); + EXPECT_EQ(cs->lru.tail, entry_id); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_DATA_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, PitToCS) { + // Prepare msgbuf and PIT entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if entry properly updated + pkt_cache_pit_to_cs(pkt_cache, entry, msgbuf_pool, msgbuf, MSGBUF_ID, + entry_id); + cs_entry_t *cs_entry = &entry->u.cs_entry; + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_CS_TYPE); + EXPECT_EQ(cs_entry->msgbuf_id, MSGBUF_ID); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + // Check if CS properly updated + cs_t *cs = pkt_cache_get_cs(pkt_cache); + entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + EXPECT_EQ(cs->num_entries, 1); + EXPECT_EQ(cs->lru.head, entry_id); + EXPECT_EQ(cs->lru.tail, entry_id); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_DATA_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, CsToPIT) { + // Prepare msgbuf and CS entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + // Check if entry properly updated + pkt_cache_cs_to_pit(pkt_cache, entry, msgbuf_pool, msgbuf, MSGBUF_ID, + entry_id); + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID), true); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, UpdateInPIT) { + // Prepare msgbuf and PIT entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + + // Check if entry properly updated + pkt_cache_update_pit(pkt_cache, entry, new_msgbuf); + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID_2), true); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, UpdateInCS) { + // Prepare msgbuf and CS entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + + // Check if entry properly updated + pkt_cache_update_cs(pkt_cache, msgbuf_pool, entry, new_msgbuf, MSGBUF_ID_2); + cs_entry_t *cs_entry = &entry->u.cs_entry; + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_CS_TYPE); + EXPECT_EQ(cs_entry->msgbuf_id, MSGBUF_ID_2); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_DATA_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, RemoveFromPIT) { + // Prepare msgbuf and PIT entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + pkt_cache_pit_remove_entry(pkt_cache, entry, name); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_NONE); + EXPECT_EQ(lu_entry, nullptr); +} + +TEST_F(PacketCacheTest, RemoveFromCS) { + // Prepare msgbuf and CS entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + pkt_cache_cs_remove_entry(pkt_cache, entry, msgbuf_pool, false); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if CS properly updated + cs_t *cs = pkt_cache_get_cs(pkt_cache); + EXPECT_EQ(cs->num_entries, 0); + EXPECT_EQ(cs->lru.head, (off_t)INVALID_ENTRY_ID); + EXPECT_EQ(cs->lru.tail, (off_t)INVALID_ENTRY_ID); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_NONE); + EXPECT_EQ(lu_entry, nullptr); +} + +TEST_F(PacketCacheTest, AddTwoEntriesToCS) { + // Prepare msgbufs + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + + pkt_cache_entry_t *entry_1 = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + pkt_cache_entry_t *entry_2 = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, new_msgbuf, MSGBUF_ID_2); + off_t entry_id_1 = pkt_cache_get_entry_id(pkt_cache, entry_1); + off_t entry_id_2 = pkt_cache_get_entry_id(pkt_cache, entry_2); + + // Check if the CS and LRU cache are properly updated + cs_t *cs = pkt_cache_get_cs(pkt_cache); + EXPECT_EQ(cs->num_entries, 2); + EXPECT_EQ(cs->lru.head, entry_id_2); + EXPECT_EQ(cs->lru.tail, entry_id_1); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 2u); +} + +TEST_F(PacketCacheTest, AggregateInPIT) { + // Prepare msgbufs + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + + // Check if entry properly created (use sleep to get an updated ts) + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + Ticks old_lifetime = entry->expire_ts; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + bool is_aggregated = + pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf); + Ticks new_lifetime = entry->expire_ts; + + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_GT(new_lifetime, old_lifetime); + ASSERT_EQ(is_aggregated, true); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, RetransmissionInPIT) { + // Prepare msgbufs (using same connection ID) + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, &new_name); + + // Check if entry properly created (use sleep to get an updated ts) + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + Ticks old_lifetime = entry->expire_ts; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + bool is_aggregated = + pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf); + Ticks new_lifetime = entry->expire_ts; + + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_GT(new_lifetime, old_lifetime); + ASSERT_EQ(is_aggregated, false); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, LookupExpiredInterest) { + // Prepare msgbuf with 0 as interest lifetime + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + + // Add to PIT + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + ASSERT_NE(entry, nullptr); + + // Wait to make the interest expire + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_lookup(pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, + true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_EXPIRED); +} + +TEST_F(PacketCacheTest, LookupExpiredData) { + // Prepare msgbuf with 0 as data expiry time + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + + // Add to CS + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + ASSERT_NE(entry, nullptr); + + // Wait to make the interest expire + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_lookup(pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, + true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_DATA_EXPIRED); +} + +TEST_F(PacketCacheTest, GetStaleEntries) { + // Add to CS a msgbuf with immediate expiration (i.e. stale) + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + + // Add to CS another msgbuf with immediate expiration (i.e. stale) + Name name_2; + name_CreateFromAddress(&name_2, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *msgbuf_2 = msgbuf_factory(msgbuf_pool, CONN_ID, &name_2, 0); + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf_2, MSGBUF_ID_2); + + // Add to CS a msgbuf with 5-seconds expiration (i.e. not stale) + Name name_3; + name_CreateFromAddress(&name_3, AF_INET6, IPV6_LOOPBACK, IPV6_LEN); + msgbuf_t *msgbuf_3 = + msgbuf_factory(msgbuf_pool, CONN_ID, &name_3, FIVE_SECONDS); + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf_3, MSGBUF_ID_3); + + size_t num_stale_entries = pkt_cache_get_num_cs_stale_entries(pkt_cache); + EXPECT_EQ(num_stale_entries, 2u); +} + +TEST_F(PacketCacheTest, GetMultipleStaleEntries) { + ip_address_t addr; + char name[30]; + const int NUM_STALES = 10; + + // Add to CS multiple msgbufs with immediate expiration (i.e. 0 seconds), + // resulting in stale entries + for (int i = 0; i < NUM_STALES; i++) { + snprintf(name, 30, "b001::%d", i); + inet_pton(AF_INET6, name, (struct in6_addr *)&addr); + Name name; + name_CreateFromAddress(&name, AF_INET6, addr, IPV6_LEN); + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, i, &name, 0); + + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, i); + } + + // Add to CS multiple msgbufs with 5-seconds expiration, + // resulting in non-stale entries + for (int i = NUM_STALES; i < 15; i++) { + snprintf(name, 30, "b001::%d", i); + inet_pton(AF_INET6, name, (struct in6_addr *)&addr); + Name name; + name_CreateFromAddress(&name, AF_INET6, addr, IPV6_LEN); + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, i, &name, FIVE_SECONDS); + + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, i); + } + + size_t num_stale_entries = pkt_cache_get_num_cs_stale_entries(pkt_cache); + EXPECT_EQ(num_stale_entries, (size_t)NUM_STALES); +} diff --git a/hicn-light/src/hicn/test/test-parser.cc b/hicn-light/src/hicn/test/test-parser.cc new file mode 100644 index 000000000..3a8d2cdb2 --- /dev/null +++ b/hicn-light/src/hicn/test/test-parser.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +extern "C" { +#include <hicn/util/log.h> +#include <hicn/config/parse.h> +} + +class ParserTest : public ::testing::Test { + protected: + ParserTest() { log_conf.log_level = LOG_INFO; } + virtual ~ParserTest() {} + + hc_command_t command_ = {}; +}; + +TEST_F(ParserTest, AddValidListener) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + EXPECT_EQ(command_.object.listener.type, FACE_TYPE_UDP_LISTENER); + EXPECT_EQ(std::string(command_.object.listener.name), "udp0"); + EXPECT_EQ(command_.object.listener.family, AF_INET); + EXPECT_EQ(command_.object.listener.local_port, 9695); + EXPECT_EQ(std::string(command_.object.listener.interface_name), "eth0"); +} + +TEST_F(ParserTest, AddListenerSymbolicOverflow) { + std::string cmd = + "add listener udp super-long-symbolic-name 10.0.0.1 9696 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, AddListenerInvalidAddress) { + std::string cmd = "add listener udp udp0 10.0.0.0.1 9696 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, AddListenerInvalidAddressString) { + std::string cmd = "add listener udp udp0 invalid-addr 9696 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, AddListenerInvalidPortOutsideRange) { + std::string cmd = "add listener udp udp0 10.0.0.1 0 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, AddListenerInvalidPortString) { + std::string cmd = "add listener udp udp0 10.0.0.1 invalid-port eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, UnknownCommnad) { + std::string cmd = "add face"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-pool.cc b/hicn-light/src/hicn/test/test-pool.cc new file mode 100644 index 000000000..c631415ca --- /dev/null +++ b/hicn-light/src/hicn/test/test-pool.cc @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/pool.h> +} + +/* + * TODO + * - test max_size + */ + +#define DEFAULT_SIZE 10 + +class PoolTest : public ::testing::Test { + protected: + PoolTest() {} + virtual ~PoolTest() {} + + int *pool; +}; + +TEST_F(PoolTest, PoolAllocation) { + int rc; + + pool_init(pool, DEFAULT_SIZE, 0); + + size_t pool_size = next_pow2(DEFAULT_SIZE); + + EXPECT_EQ(pool_get_alloc_size(pool), pool_size); + + /* Check that free indices and bitmaps are correctly initialize */ + off_t *fi = pool_get_free_indices(pool); + EXPECT_EQ(vector_len(fi), pool_size); + EXPECT_EQ(fi[0], (long)(pool_size - 1)); + EXPECT_EQ(fi[pool_size - 1], 0); + + /* The allocated size of the underlying vector should be the next power of two + */ + EXPECT_EQ(vector_get_alloc_size(fi), pool_size); + + bitmap_t *fb = pool_get_free_bitmap(pool); + EXPECT_TRUE(bitmap_is_set(fb, 0)); + EXPECT_TRUE(bitmap_is_set(fb, pool_size - 2)); + EXPECT_TRUE(bitmap_is_set(fb, pool_size - 1)); + EXPECT_TRUE(bitmap_is_unset(fb, pool_size)); + + /* Getting elements from the pool should correctly update the free indices + * and bitmap */ + int *elt; + + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + EXPECT_EQ(vector_len(fi), pool_size - 1); + EXPECT_TRUE(bitmap_is_unset(fb, 0)); + + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + EXPECT_EQ(vector_len(fi), pool_size - 2); + EXPECT_TRUE(bitmap_is_unset(fb, 1)); + + for (unsigned i = 0; i < pool_size - 4; i++) { + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + } + + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + EXPECT_EQ(vector_len(fi), 1UL); + EXPECT_TRUE(bitmap_is_unset(fb, pool_size - 2)); + + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + EXPECT_EQ(vector_len(fi), 0UL); + EXPECT_TRUE(bitmap_is_unset(fb, pool_size - 1)); + + /* + * Getting elements within the allocated range should not have triggered a + * resize + */ + EXPECT_EQ(pool_len(pool), pool_size); + + /* + * Getting elements once the allocated range has been exceeded should + * trigger a resize + */ + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + + EXPECT_EQ(pool_get_alloc_size(pool), pool_size * 2); + + EXPECT_EQ(pool_len(pool), pool_size + 1); + + /* + * Doubling the size, we should have again pool_size elements free, minus 1 + */ + EXPECT_EQ(pool_get_free_indices_size(pool), pool_size - 1); + + /* + * NOTE: this is wrong as there has been a realloc and the old fi + * pointer is now invalid + */ + // EXPECT_EQ(vector_len(fi), pool_size - 1); + + /* And the bitmap should also be correctly modified */ + fb = pool_get_free_bitmap(pool); + EXPECT_TRUE(bitmap_is_unset(fb, pool_size)); + + /* Check that surrounding values are also correct */ + EXPECT_TRUE(bitmap_is_unset(fb, pool_size - 1)); + EXPECT_TRUE(bitmap_is_set(fb, pool_size + 1)); + + /* Setting elements after should through */ + + /* Check that free indices and bitmaps are correctly updated */ + + pool_free(pool); +} + +TEST_F(PoolTest, PoolPut) { + pool_init(pool, DEFAULT_SIZE, 0); + + int *elt; + pool_get(pool, elt); + *elt = 10; + pool_put(pool, elt); + + pool_free(pool); +} + +TEST_F(PoolTest, PoolGetForceBitmapRealloc) { + const int N = 64; + int *elts[N]; + int *elt = NULL; + pool_init(pool, N, 0); + + for (int i = 0; i < N; i++) pool_get(pool, elts[i]); + pool_get(pool, elt); + + pool_free(pool); +} + +TEST_F(PoolTest, PoolGetAfterReleasing) { + int *elt1 = NULL, *elt2 = NULL, *tmp = NULL; + pool_init(pool, DEFAULT_SIZE, 0); + + // If two elements are requested... + off_t id1 = pool_get(pool, elt1); + pool_get(pool, tmp); + + // ...and the first one is released... + pool_put(pool, elt1); + + // ...requesting a new one should return + // the first one (that was freed) + off_t id2 = pool_get(pool, elt2); + EXPECT_EQ(id1, id2); + EXPECT_EQ(elt1, elt2); + + pool_free(pool); +} + +TEST_F(PoolTest, PoolGetMultipleElementsAfterReleasing) { + const int N = 2; + int *elts[N]; + pool_init(pool, N, 0); + + for (int i = 0; i < N; i++) pool_get(pool, elts[i]); + for (int i = 0; i < N; i++) pool_put(pool, elts[i]); + for (int i = 0; i < N; i++) pool_get(pool, elts[i]); + + pool_free(pool); +} diff --git a/hicn-light/src/hicn/test/test-probe_generator.cc b/hicn-light/src/hicn/test/test-probe_generator.cc new file mode 100644 index 000000000..4d6cfa8f7 --- /dev/null +++ b/hicn-light/src/hicn/test/test-probe_generator.cc @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <arpa/inet.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/strategies/probe_generator.h> +} + +class ProbeGeneratorTest : public ::testing::Test { + protected: + ProbeGeneratorTest() {} + + virtual ~ProbeGeneratorTest() {} +}; + +TEST_F(ProbeGeneratorTest, ProbeGeneratorRegisterProbe) { + probe_generator_t *pg = create_probe_generator(); + EXPECT_FALSE(pg == nullptr); + + register_probe(pg, 1); + register_probe(pg, 2); + register_probe(pg, 3); + register_probe(pg, 4); + + Ticks t = get_probe_send_time(pg, 1); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 2); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 4); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 5); + EXPECT_FALSE(t != 0); + + destroy_probe_generator(pg); +} + +TEST_F(ProbeGeneratorTest, ProbeGeneratorTime) { + probe_generator_t *pg = create_probe_generator(); + EXPECT_FALSE(pg == nullptr); + + Ticks t1 = register_probe(pg, 1); + Ticks t2 = get_probe_send_time(pg, 1); + + EXPECT_TRUE(t2 != 0); + EXPECT_TRUE(t1 == t2); + + destroy_probe_generator(pg); +} + +TEST_F(ProbeGeneratorTest, ProbeGeneratorDeleteProbe) { + probe_generator_t *pg = create_probe_generator(); + EXPECT_FALSE(pg == nullptr); + + register_probe(pg, 1); + register_probe(pg, 2); + register_probe(pg, 3); + register_probe(pg, 4); + + Ticks t = get_probe_send_time(pg, 1); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 2); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 4); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 5); + EXPECT_FALSE(t != 0); + + delete_probe(pg, 1); + delete_probe(pg, 3); + + t = get_probe_send_time(pg, 1); + EXPECT_FALSE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_FALSE(t != 0); + + destroy_probe_generator(pg); +} + +TEST_F(ProbeGeneratorTest, ProbeGeneratorDeleteAll) { + probe_generator_t *pg = create_probe_generator(); + EXPECT_FALSE(pg == nullptr); + + register_probe(pg, 1); + register_probe(pg, 2); + register_probe(pg, 3); + register_probe(pg, 4); + + Ticks t = get_probe_send_time(pg, 1); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 2); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 4); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 5); + EXPECT_FALSE(t != 0); + + delete_all_probes(pg); + + t = get_probe_send_time(pg, 1); + EXPECT_FALSE(t != 0); + + t = get_probe_send_time(pg, 2); + EXPECT_FALSE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_FALSE(t != 0); + + t = get_probe_send_time(pg, 4); + EXPECT_FALSE(t != 0); + + destroy_probe_generator(pg); +} diff --git a/hicn-light/src/hicn/test/test-ring.cc b/hicn-light/src/hicn/test/test-ring.cc new file mode 100644 index 000000000..51f1f5327 --- /dev/null +++ b/hicn-light/src/hicn/test/test-ring.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/ring.h> +} + +#define DEFAULT_SIZE 10UL + +class RingTest : public ::testing::Test { + protected: + RingTest() { ring_init(ring, DEFAULT_SIZE); } + virtual ~RingTest() { ring_free(ring); } + + int *ring = NULL; +}; + +/* TEST: Ring allocation and initialization */ +TEST_F(RingTest, RingAddOne) { + int val = -1; + /* Allocated size should be the next power of two */ + EXPECT_EQ(ring_get_size(ring), 0UL); + ring_add_value(ring, 1); + EXPECT_EQ(ring_get_size(ring), 1UL); + ring_get(ring, 0, &val); + EXPECT_EQ(val, 1); + EXPECT_EQ(ring_get_size(ring), 1UL); + ring_advance(ring, 1); + EXPECT_EQ(ring_get_size(ring), 0UL); +} + +TEST_F(RingTest, RingAddMany) { + size_t i = 0; + int val = -1; + size_t count = 0; + + /* Allocated size should be the next power of two */ + EXPECT_EQ(ring_get_size(ring), 0UL); + for (unsigned i = 0; i < DEFAULT_SIZE; i++) ring_add_value(ring, i); + EXPECT_EQ(ring_get_size(ring), DEFAULT_SIZE); + + count = 0; + ring_enumerate_n(ring, i, &val, 1, { + EXPECT_EQ(val, (int)(i)); + count++; + }); + EXPECT_EQ(count, 1UL); + + count = 0; + ring_enumerate_n(ring, i, &val, DEFAULT_SIZE, { + EXPECT_EQ(val, (int)(i)); + count++; + }); + EXPECT_EQ(count, DEFAULT_SIZE); + + count = 0; + ring_enumerate_n(ring, i, &val, DEFAULT_SIZE + 1, { + EXPECT_EQ(val, (int)(i)); + count++; + }); + EXPECT_EQ(count, DEFAULT_SIZE); + + // Drop one + ring_add_value(ring, DEFAULT_SIZE); + EXPECT_EQ(ring_get_size(ring), DEFAULT_SIZE); + + count = 0; + ring_enumerate_n(ring, i, &val, DEFAULT_SIZE, { + EXPECT_EQ(val, (int)(i + 1)); // all values shoud be shifted + count++; + }); + EXPECT_EQ(count, DEFAULT_SIZE); + + ring_advance(ring, DEFAULT_SIZE); + EXPECT_EQ(ring_get_size(ring), 0UL); +} diff --git a/hicn-light/src/hicn/test/test-strategy-best-path.cc b/hicn-light/src/hicn/test/test-strategy-best-path.cc new file mode 100644 index 000000000..327c47144 --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-best-path.cc @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/strategy.h> +#include <hicn/strategies/best_path.h> +} + +#define MAX_TESTS 10 + +#define NEXTHOP_ID1 NEXTHOP(28) +#define NEXTHOP_ID2 NEXTHOP(29) +#define UNKNOWN_ID1 NEXTHOP(0) +#define UNKNOWN_ID2 NEXTHOP(1) + +class StrategyBestpathTest : public ::testing::Test { + protected: + StrategyBestpathTest() { + /* Strategy and strategy entry */ + entry = { + .type = STRATEGY_TYPE_BESTPATH, + .options = + { + .bestpath = {}, + }, + .state = {.bestpath = {}}, + }; + + strategy_initialize(&entry, nullptr); + + // test init + EXPECT_EQ(entry.forwarder, nullptr); + EXPECT_EQ(entry.state.bestpath.best_nexthop, (unsigned)~0); + EXPECT_EQ(entry.state.bestpath.probing_state, PROBING_OFF); + + /* Available nexthops */ + available_nexthops_ = NEXTHOPS_EMPTY; + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)0); + + /* Message buffer */ + msgbuf_ = NULL; + ticks_ = ticks_now(); + } + + virtual ~StrategyBestpathTest() {} + + strategy_entry_t entry; + nexthops_t available_nexthops_; + msgbuf_t *msgbuf_; + Ticks ticks_; +}; + +TEST_F(StrategyBestpathTest, emptyNexthop) { + nexthops_t *nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)0); +} + +TEST_F(StrategyBestpathTest, faceExists) { + nexthops_t *nexthops; + + nexthops_add(&available_nexthops_, NEXTHOP_ID1); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + nexthops_add(&available_nexthops_, NEXTHOP_ID2); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + entry.state.bestpath.probing_state = PROBING_OFF; + entry.state.bestpath.best_nexthop = NEXTHOP_ID2; + + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID2)); + EXPECT_FALSE(nexthops_contains(nexthops, NEXTHOP_ID1)); + + EXPECT_TRUE(entry.state.bestpath.probing_state == PROBING_OFF); + EXPECT_EQ(entry.state.bestpath.best_nexthop, NEXTHOP_ID2); +} diff --git a/hicn-light/src/hicn/test/test-strategy-load-balancing.cc b/hicn-light/src/hicn/test/test-strategy-load-balancing.cc new file mode 100644 index 000000000..edac5669f --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-load-balancing.cc @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/strategy.h> +#include <hicn/strategies/random.h> +} + +#define MAX_TESTS 10 + +#define NEXTHOP_ID NEXTHOP(28) +#define NEXTHOP_ID2 NEXTHOP(29) +#define UNKNOWN_ID1 NEXTHOP(0) +#define UNKNOWN_ID2 NEXTHOP(1) + +class StrategyLoadBalancing : public ::testing::Test { + protected: + StrategyLoadBalancing() { + /* Strategy and strategy entry */ + entry = { + .type = STRATEGY_TYPE_LOADBALANCER, + .options = + { + .random = {}, + }, + .state = {.random = {}}, + }; + + strategy_initialize(&entry, nullptr); + + /* Available nexthops */ + available_nexthops_ = NEXTHOPS_EMPTY; + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)0); + + /* Message buffer */ + msgbuf_ = NULL; + ticks_ = ticks_now(); + } + virtual ~StrategyLoadBalancing() {} + + strategy_entry_t entry; + nexthops_t available_nexthops_; + msgbuf_t* msgbuf_; + Ticks ticks_; +}; + +TEST_F(StrategyLoadBalancing, SingleNexthop) { + /* Add a single nexthop */ + off_t id; + id = nexthops_add(&available_nexthops_, NEXTHOP_ID); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, NEXTHOP_ID); + } + + /* Disable (move to nexthop unit tests) */ + nexthops_disable(nexthops, 0); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)0); + + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, INVALID_NEXTHOP); +} + +TEST_F(StrategyLoadBalancing, MultipleNexthops) { + off_t id, id2; + /* Add a single nexthop */ + id = nexthops_add(&available_nexthops_, NEXTHOP_ID); + id2 = nexthops_add(&available_nexthops_, NEXTHOP_ID2); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + strategy_add_nexthop(&entry, &available_nexthops_, id2); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID)); + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID2)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE((nexthops_contains(nexthops, NEXTHOP_ID)) || + (nexthops_contains(nexthops, NEXTHOP_ID2))); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_TRUE((nexthop == NEXTHOP_ID) || (nexthop == NEXTHOP_ID2)); + } +} diff --git a/hicn-light/src/hicn/test/test-strategy-random.cc b/hicn-light/src/hicn/test/test-strategy-random.cc new file mode 100644 index 000000000..bd9b70120 --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-random.cc @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/strategy.h> +#include <hicn/core/strategy_vft.h> +#include <hicn/strategies/random.h> +} + +#define MAX_TESTS 10 + +#define NEXTHOP_ID NEXTHOP(28) +#define UNKNOWN_ID1 NEXTHOP(0) +#define UNKNOWN_ID2 NEXTHOP(1) + +class StrategyRandomTest : public ::testing::Test { + protected: + StrategyRandomTest() { + /* Strategy and strategy entry */ + entry = { + .type = STRATEGY_TYPE_RANDOM, + .options = + { + .random = {}, + }, + .state = {.random = {}}, + }; + + strategy_initialize(&entry, nullptr); + + /* Available nexthops */ + available_nexthops_ = NEXTHOPS_EMPTY; + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)0); + + /* Message buffer */ + msgbuf_ = NULL; + ticks_ = ticks_now(); + } + virtual ~StrategyRandomTest() {} + + strategy_entry_t entry; + nexthops_t available_nexthops_; + msgbuf_t* msgbuf_; + Ticks ticks_; +}; + +TEST_F(StrategyRandomTest, SingleNexthop) { + off_t id; + + /* Add a single nexthop */ + id = nexthops_add(&available_nexthops_, NEXTHOP_ID); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, NEXTHOP_ID); + } + + /* Disable (move to nexthop unit tests) */ + nexthops_disable(nexthops, 0); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)0); + + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, INVALID_NEXTHOP); +} + +TEST_F(StrategyRandomTest, MultipleNexthops) { + off_t id; + + /* Add a single nexthop */ + id = nexthops_add(&available_nexthops_, NEXTHOP_ID); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, NEXTHOP_ID); + } +} diff --git a/hicn-light/src/hicn/test/test-strategy-replication.cc b/hicn-light/src/hicn/test/test-strategy-replication.cc new file mode 100644 index 000000000..ab7dae1f7 --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-replication.cc @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/strategy.h> +#include <hicn/strategies/random.h> +} + +#define MAX_TESTS 10 + +#define NEXTHOP_ID1 NEXTHOP(28) +#define NEXTHOP_ID2 NEXTHOP(29) +#define UNKNOWN_ID1 NEXTHOP(0) +#define UNKNOWN_ID2 NEXTHOP(1) + +class StrategyReplicationTest : public ::testing::Test { + protected: + StrategyReplicationTest() { + /* Strategy and strategy entry */ + entry = { + .type = STRATEGY_TYPE_REPLICATION, + .options = + { + .replication = {}, + }, + .state = {.replication = {}}, + }; + + strategy_initialize(&entry, nullptr); + + /* Available nexthops */ + available_nexthops_ = NEXTHOPS_EMPTY; + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)0); + + /* Message buffer */ + msgbuf_ = NULL; + ticks_ = ticks_now(); + } + + virtual ~StrategyReplicationTest() {} + + strategy_entry_t entry; + nexthops_t available_nexthops_; + msgbuf_t* msgbuf_; + Ticks ticks_; +}; + +TEST_F(StrategyReplicationTest, SingleNexthop) { + off_t id; + + /* Add a single nexthop */ + id = nexthops_add(&available_nexthops_, NEXTHOP_ID1); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, NEXTHOP_ID1); + } + + /* Disable (move to nexthop unit tests) */ + nexthops_disable(nexthops, 0); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)0); + + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, INVALID_NEXTHOP); +} + +TEST_F(StrategyReplicationTest, MultipleNexthops) { + off_t id; + + id = nexthops_add(&available_nexthops_, NEXTHOP_ID1); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + id = nexthops_add(&available_nexthops_, NEXTHOP_ID2); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID1)); + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID2)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)2); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID1)); + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID2)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + unsigned tests = 0; + nexthops_foreach(nexthops, nexthop, { + EXPECT_TRUE(nexthop == NEXTHOP_ID1 || nexthop == NEXTHOP_ID2); + tests++; + }); + + EXPECT_EQ(tests, (unsigned)2); +} diff --git a/hicn-light/src/hicn/test/test-subscription.cc b/hicn-light/src/hicn/test/test-subscription.cc new file mode 100644 index 000000000..18ef60c0d --- /dev/null +++ b/hicn-light/src/hicn/test/test-subscription.cc @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + */ + +#include <gtest/gtest.h> + +extern "C" { +#include <hicn/core/subscription.h> +#include <hicn/base/vector.h> +} + +static inline unsigned CONN_ID = 1; +static inline unsigned CONN_ID_2 = 2; + +class SubscriptionTest : public ::testing::Test { + protected: + SubscriptionTest() { subscriptions = subscription_table_create(); } + virtual ~SubscriptionTest() { subscription_table_free(subscriptions); } + + subscription_table_t *subscriptions; +}; + +TEST_F(SubscriptionTest, CreateSubscriptionTable) { + // Check subscription table allocation + ASSERT_NE(subscriptions, nullptr); +} + +TEST_F(SubscriptionTest, SetTopic) { + hc_topics_t topics = TOPIC_STRATEGY; + + // Check that only the topic desired has been subscribed to + for (int topic = TOPIC_UNDEFINED; topic < TOPIC_N; topic <<= 1) { + if (topic == TOPIC_STRATEGY) { + EXPECT_TRUE(topics_contains(topics, (hc_topic_t)topic)); + continue; + } + EXPECT_FALSE(topics_contains(topics, (hc_topic_t)topic)); + } +} + +TEST_F(SubscriptionTest, GetObjectFromTopic) { + hc_object_type_t object_type = object_from_topic(TOPIC_STRATEGY); + EXPECT_EQ(object_type, OBJECT_STRATEGY); + + object_type = object_from_topic(TOPIC_FACE); + EXPECT_EQ(object_type, OBJECT_FACE); +} + +TEST_F(SubscriptionTest, AddSubscription) { + hc_topics_t topics = TOPIC_STRATEGY; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics); +} + +TEST_F(SubscriptionTest, AddAndRemoveSubscriptionForAllTopics) { + hc_topics_t topics = ALL_TOPICS; + int ret = subscription_table_add_topics_for_connection(subscriptions, + ALL_TOPICS, CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + int num_subscriptions_removed = + subscription_table_remove_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(num_subscriptions_removed, NUM_TOPICS); + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, 0u); +} + +// Failure while adding subscription cannot be tested since it depends on vector +// reallocation + +TEST_F(SubscriptionTest, AddSubscriptionAlreadyAdded) { + hc_topics_t topics = TOPIC_STRATEGY; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + // Subscribe again to same topic + ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, -2); // -2 = already-added subscription + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics); +} + +TEST_F(SubscriptionTest, GetSubscriptionsForConnectionWithoutSubscriptions) { + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, (hc_topics_t)0); +} + +TEST_F(SubscriptionTest, GetSubscriptionsForConnectionWithMultipleSubs) { + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics); + + // Add another subscription + ret = subscription_table_add_topics_for_connection(subscriptions, TOPIC_PROBE, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics |= TOPIC_PROBE); +} + +TEST_F(SubscriptionTest, RemoveSubscription) { + // Add subscriptions + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + // Remove one of the previously added subscriptions + int num_subscriptions_removed = + subscription_table_remove_topics_for_connection(subscriptions, + TOPIC_STRATEGY, CONN_ID); + EXPECT_EQ(num_subscriptions_removed, 1); + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, TOPIC_FACE); +} + +TEST_F(SubscriptionTest, RemoveMultipleSubscriptions) { + // Add subscriptions + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE | TOPIC_PROBE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + // Remove two of the previously added subscriptions + int num_subscriptions_removed = + subscription_table_remove_topics_for_connection( + subscriptions, TOPIC_STRATEGY | TOPIC_FACE, CONN_ID); + EXPECT_EQ(num_subscriptions_removed, 2); + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, TOPIC_PROBE); +} + +TEST_F(SubscriptionTest, RemoveNonRegistredSubscription) { + // Remove a subscription that is not present + int num_subscriptions_removed = + subscription_table_remove_topics_for_connection(subscriptions, + TOPIC_PROBE, CONN_ID); + EXPECT_EQ(num_subscriptions_removed, 0); + + // Add two new subscriptions + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + // Remove subscription that was not registred previously + num_subscriptions_removed = subscription_table_remove_topics_for_connection( + subscriptions, TOPIC_PROBE, CONN_ID); + EXPECT_EQ(num_subscriptions_removed, 0); + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics); +} + +TEST_F(SubscriptionTest, GetConnectionsForSubscription) { + // Add subscriptions for two connections + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + topics = TOPIC_STRATEGY; + ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID_2); + EXPECT_EQ(ret, 0); // 0 = success + + // Check the connections associated with the strategy topic + unsigned *conn_ids = subscription_table_get_connections_for_topic( + subscriptions, TOPIC_STRATEGY); + EXPECT_EQ(vector_len(conn_ids), 2u); + EXPECT_TRUE(conn_ids[0] == CONN_ID || conn_ids[0] == CONN_ID_2); + EXPECT_TRUE(conn_ids[1] == CONN_ID || conn_ids[1] == CONN_ID_2); + + // Check the connections associated with the face topic + conn_ids = + subscription_table_get_connections_for_topic(subscriptions, TOPIC_FACE); + EXPECT_EQ(vector_len(conn_ids), 1u); + EXPECT_EQ(conn_ids[0], (unsigned)CONN_ID); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-vector.cc b/hicn-light/src/hicn/test/test-vector.cc new file mode 100644 index 000000000..fb30a8228 --- /dev/null +++ b/hicn-light/src/hicn/test/test-vector.cc @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2021 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. + */ + +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/vector.h> +} + +/* + * TODO + * - test max_size + */ + +#define DEFAULT_SIZE 10 +const size_t N_ELEMENTS = 5; + +class VectorTest : public ::testing::Test { + protected: + VectorTest() { vector_init(vector, DEFAULT_SIZE, 0); } + virtual ~VectorTest() { vector_free(vector); } + + int *vector = NULL; +}; + +/* TEST: Vector allocation and initialization */ +TEST_F(VectorTest, VectorAllocate) { + /* Allocated size should be the next power of two */ + EXPECT_EQ(vector_get_alloc_size(vector), 16UL); + + /* Setting elements within the allocated size should not trigger a resize */ + vector_ensure_pos(vector, 15); + EXPECT_EQ(vector_get_alloc_size(vector), 16UL); + + /* Setting elements after should through */ + vector_ensure_pos(vector, 16); + EXPECT_EQ(vector_get_alloc_size(vector), 32UL); + + /* Check that free indices and bitmaps are correctly updated */ +} + +TEST_F(VectorTest, VectorSize) { + vector_push(vector, 109); + int size = vector_len(vector); + EXPECT_EQ(size, 1); + vector_push(vector, 109); + size = vector_len(vector); + EXPECT_EQ(size, 2); + vector_push(vector, 109); + size = vector_len(vector); + EXPECT_EQ(size, 3); +} + +TEST_F(VectorTest, VectorCheckValue) { + vector_push(vector, 109); + vector_push(vector, 200); + EXPECT_EQ(vector[0], 109); + EXPECT_EQ(vector[1], 200); +} + +TEST_F(VectorTest, VectorEnsurePos) { + printf(" %p\n", vector); + vector_ensure_pos(vector, 1025); + for (int i = 0; i < 1025; i++) { + // printf("i %d\n", i); + // printf (" %p\n", vector); + vector_push(vector, i); + } + int size = vector_len(vector); + EXPECT_EQ(size, 1025); +} + +TEST_F(VectorTest, RemoveElement) { + // Populate vector + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); + EXPECT_EQ(vector_len(vector), N_ELEMENTS); + for (size_t i = 0; i < vector_len(vector); i++) EXPECT_EQ(vector[i], (int)i); + + // Remove element + int value_to_remove = 3; + int num_removed = vector_remove_unordered(vector, value_to_remove); + + EXPECT_EQ(vector_len(vector), N_ELEMENTS - 1); + EXPECT_EQ(num_removed, 1); + for (size_t i = 0; i < vector_len(vector); i++) + EXPECT_NE(vector[i], value_to_remove); +} + +TEST_F(VectorTest, RemoveDuplicatedElement) { + // Populate vector + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); + EXPECT_EQ(vector_len(vector), N_ELEMENTS); + for (size_t i = 0; i < vector_len(vector); i++) EXPECT_EQ(vector[i], (int)i); + vector[0] = 3; // Duplicate element + + // Remove (duplicated) elements + int value_to_remove = 3; + int num_removed = vector_remove_unordered(vector, value_to_remove); + + EXPECT_EQ(vector_len(vector), N_ELEMENTS - 2); + EXPECT_EQ(num_removed, 2); + for (size_t i = 0; i < vector_len(vector); i++) + EXPECT_NE(vector[i], value_to_remove); +} + +TEST_F(VectorTest, Iterate) { + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); + + int count = 0; + int *elem; + vector_foreach(vector, elem, { EXPECT_EQ(*elem, count++); }); +} + +TEST_F(VectorTest, MultipleResize) { + // Use small vector (size=1) to force multiple realloc operations + int *small_vector; + vector_init(small_vector, 1, 0); + + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(small_vector, i); + + for (size_t i = 0; i < N_ELEMENTS; i++) EXPECT_EQ(small_vector[i], (int)i); + + EXPECT_EQ(vector_len(small_vector), 5UL); + EXPECT_EQ(vector_get_alloc_size(small_vector), 8UL); + + vector_free(small_vector); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/utils/CMakeLists.txt b/hicn-light/src/hicn/utils/CMakeLists.txt index c8c9b8487..72a918cac 100644 --- a/hicn-light/src/hicn/utils/CMakeLists.txt +++ b/hicn-light/src/hicn/utils/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 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: @@ -11,30 +11,19 @@ # See the License for the specific language governing permissions and # limitations under the License. +# XXX This is installed in hicn/utils... list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/address.h - ${CMAKE_CURRENT_SOURCE_DIR}/addressList.h - ${CMAKE_CURRENT_SOURCE_DIR}/commands.h - ${CMAKE_CURRENT_SOURCE_DIR}/interface.h - ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.h +# ${CMAKE_CURRENT_SOURCE_DIR}/commands.h +# ${CMAKE_CURRENT_SOURCE_DIR}/interface.h +# ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.h ${CMAKE_CURRENT_SOURCE_DIR}/punting.h ${CMAKE_CURRENT_SOURCE_DIR}/token.h - ${CMAKE_CURRENT_SOURCE_DIR}/utils.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/address.c - ${CMAKE_CURRENT_SOURCE_DIR}/addressList.c - ${CMAKE_CURRENT_SOURCE_DIR}/interface.c - ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.c +# ${CMAKE_CURRENT_SOURCE_DIR}/interface.c +# ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.c ${CMAKE_CURRENT_SOURCE_DIR}/punting.c - ${CMAKE_CURRENT_SOURCE_DIR}/utils.c -) - -set(TO_INSTALL_HEADER_FILES - ${TO_INSTALL_HEADER_FILES} - ${HEADER_FILES} - PARENT_SCOPE ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/utils/address.c b/hicn-light/src/hicn/utils/address.c deleted file mode 100644 index 619097e1d..000000000 --- a/hicn-light/src/hicn/utils/address.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 _WIN32 -#include <arpa/inet.h> -#include <unistd.h> -#endif -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <hicn/utils/address.h> - -#include <parc/algol/parc_Base64.h> -#include <parc/algol/parc_BufferComposer.h> -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/algol/parc_Object.h> - -#include <parc/assert/parc_Assert.h> - -struct address { - address_type addressType; - PARCBuffer *blob; -}; - -static struct address_type_str { - address_type type; - const char *str; -} addressTypeString[] = { - {.type = ADDR_INET, .str = "INET"}, {.type = ADDR_INET6, .str = "INET6"}, - {.type = ADDR_LINK, .str = "LINK"}, {.type = ADDR_IFACE, .str = "IFACE"}, - {.type = ADDR_UNIX, .str = "UNIX"}, {.type = 0, .str = NULL}}; - -void addressDestroy(Address **addressPtr) { - parcAssertNotNull(addressPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*addressPtr, - "Parameter must dereference to non-null pointer"); - - Address *address = *addressPtr; - parcBuffer_Release(&address->blob); - parcMemory_Deallocate((void **)&address); - *addressPtr = NULL; -} - -void addressAssertValid(const Address *address) { - parcAssertNotNull(address, "Parameter must be non-null Address *"); -} - -const char *addressTypeToString(address_type type) { - for (int i = 0; addressTypeString[i].str != NULL; i++) { - if (addressTypeString[i].type == type) { - return addressTypeString[i].str; - } - } - parcTrapIllegalValue(type, "Unknown value: %d", type); - const char *result = NULL; - return result; -} - -address_type addressStringToType(const char *str) { - for (int i = 0; addressTypeString[i].str != NULL; i++) { - if (strcasecmp(addressTypeString[i].str, str) == 0) { - return addressTypeString[i].type; - } - } - parcTrapIllegalValue(str, "Unknown type '%s'", str); - return 0; -} - -static Address *_addressCreate(address_type addressType, PARCBuffer *buffer) { - Address *result = parcMemory_AllocateAndClear(sizeof(Address)); - - parcAssertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(Address)); - if (result != NULL) { - result->addressType = addressType; - result->blob = buffer; - } - return result; -} - -Address *addressCreateFromInet(struct sockaddr_in *addr_in) { - parcAssertNotNull(addr_in, "Parameter must be non-null"); - - addr_in->sin_family = AF_INET; - - PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in)); - parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in), (uint8_t *)addr_in); - parcBuffer_Flip(buffer); - - Address *result = _addressCreate(ADDR_INET, buffer); - - return result; -} - -Address *addressCreateFromInet6(struct sockaddr_in6 *addr_in6) { - parcAssertNotNull(addr_in6, "Parameter must be non-null"); - - PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6)); - parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in6), (uint8_t *)addr_in6); - parcBuffer_Flip(buffer); - - Address *result = _addressCreate(ADDR_INET6, buffer); - - return result; -} - -Address *addressFromInaddr4Port(in_addr_t *addr4, in_port_t *port) { - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - - // We assume address and port are already written in memory in network byte - // order - addr.sin_family = AF_INET; - addr.sin_port = *port; - addr.sin_addr.s_addr = *addr4; - - Address *result = addressCreateFromInet(&addr); - return result; -} - -Address *addressFromInaddr6Port(struct in6_addr *addr6, in_port_t *port) { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - - // We assume address and port are already written in memory in network byte - // order - addr.sin6_port = *port; - addr.sin6_addr = *addr6; - addr.sin6_scope_id = 0; - // Other 2 fields: scope_id and flowinfo, do not know what to put inside. - - Address *result = addressCreateFromInet6(&addr); - return result; -} - -Address *addressCreateFromLink(const uint8_t *linkaddr, size_t length) { - parcAssertNotNull(linkaddr, "Parameter must be non-null"); - - PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6)); - parcBuffer_PutArray(buffer, length, linkaddr); - parcBuffer_Flip(buffer); - - Address *result = _addressCreate(ADDR_LINK, buffer); - return result; -} - -Address *addressCreateFromInterface(unsigned interfaceIndex) { - unsigned netbyteorder = htonl(interfaceIndex); - - PARCBuffer *buffer = parcBuffer_Allocate(sizeof(netbyteorder)); - parcBuffer_PutArray(buffer, sizeof(netbyteorder), (uint8_t *)&netbyteorder); - parcBuffer_Flip(buffer); - - Address *result = _addressCreate(ADDR_IFACE, buffer); - return result; -} - -Address *addressCreateFromUnix(struct sockaddr_un *addr_un) { - parcAssertNotNull(addr_un, "Parameter must be non-null"); - - PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_un)); - parcBuffer_PutArray(buffer, sizeof(struct sockaddr_un), (uint8_t *)addr_un); - parcBuffer_Flip(buffer); - - Address *result = _addressCreate(ADDR_UNIX, buffer); - return result; -} - -Address *addressCopy(const Address *original) { - addressAssertValid(original); - - Address *result = - _addressCreate(original->addressType, parcBuffer_Copy(original->blob)); - return result; -} - -bool addressEquals(const Address *a, const Address *b) { - if (a == b) { - return true; - } - - if (a == NULL || b == NULL) { - return false; - } - - if (a->addressType == b->addressType) { - if (parcBuffer_Equals(a->blob, b->blob)) { - return true; - } - } - - return false; -} - -address_type addressGetType(const Address *address) { - addressAssertValid(address); - - return address->addressType; -} - -// The Get functions need better names, what they do (Get from what? Put to -// what?) is not clear from their names. Case 1028 -bool addressGetInet(const Address *address, struct sockaddr_in *addr_in) { - addressAssertValid(address); - parcAssertNotNull(addr_in, "Parameter addr_in must be non-null"); - - if (address->addressType == ADDR_INET) { - parcAssertTrue( - parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in), - "Address corrupted. Expected length %zu, actual length %zu", - sizeof(struct sockaddr_in), parcBuffer_Remaining(address->blob)); - - memcpy(addr_in, parcBuffer_Overlay(address->blob, 0), - sizeof(struct sockaddr_in)); - return true; - } - return false; -} - -bool addressGetInet6(const Address *address, struct sockaddr_in6 *addr_in6) { - addressAssertValid(address); - parcAssertNotNull(addr_in6, "Parameter addr_in6 must be non-null"); - - if (address->addressType == ADDR_INET6) { - parcAssertTrue( - parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in6), - "Address corrupted. Expected length %zu, actual length %zu", - sizeof(struct sockaddr_in6), parcBuffer_Remaining(address->blob)); - - memcpy(addr_in6, parcBuffer_Overlay(address->blob, 0), - sizeof(struct sockaddr_in6)); - return true; - } - return false; -} - -bool addressGetUnix(const Address *address, struct sockaddr_un *addr_un) { - addressAssertValid(address); - parcAssertNotNull(addr_un, "Parameter addr_in6 must be non-null"); - - if (address->addressType == ADDR_UNIX) { - parcAssertTrue( - parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_un), - "Address corrupted. Expected length %zu, actual length %zu", - sizeof(struct sockaddr_un), parcBuffer_Remaining(address->blob)); - - memcpy(addr_un, parcBuffer_Overlay(address->blob, 0), - sizeof(struct sockaddr_un)); - return true; - } - return false; -} - -bool addressGetInterfaceIndex(const Address *address, uint32_t *ifidx) { - addressAssertValid(address); - parcAssertNotNull(ifidx, "Parameter ifidx must be non-null"); - - if (address->addressType == ADDR_IFACE) { - parcAssertTrue(parcBuffer_Remaining(address->blob) == sizeof(uint32_t), - "Address corrupted. Expected length %zu, actual length %zu", - sizeof(uint32_t), parcBuffer_Remaining(address->blob)); - - uint32_t netbyteorder; - memcpy(&netbyteorder, parcBuffer_Overlay(address->blob, 0), - sizeof(uint32_t)); - *ifidx = ntohl(netbyteorder); - return true; - } - return false; -} - -PARCBuffer *addressGetLinkAddress(const Address *address) { - addressAssertValid(address); - if (address->addressType == ADDR_LINK) { - return address->blob; - } - return NULL; -} - -static PARCBufferComposer *_Inet_BuildString(const Address *address, - PARCBufferComposer *composer) { - addressAssertValid(address); - - struct sockaddr_in *saddr = - (struct sockaddr_in *)parcBuffer_Overlay(address->blob, 0); - return parcNetwork_SockInet4Address_BuildString(saddr, composer); -} - -static PARCBufferComposer *_Inet6_BuildString(const Address *address, - PARCBufferComposer *composer) { - addressAssertValid(address); - - struct sockaddr_in6 *saddr = - (struct sockaddr_in6 *)parcBuffer_Overlay(address->blob, 0); - return parcNetwork_SockInet6Address_BuildString(saddr, composer); -} - -static PARCBufferComposer *_Link_BuildString(const Address *address, - PARCBufferComposer *composer) { - addressAssertValid(address); - - const unsigned char *addr = parcBuffer_Overlay(address->blob, 0); - - size_t length = parcBuffer_Remaining(address->blob); - - return parcNetwork_LinkAddress_BuildString(addr, length, composer); -} - -static ssize_t _UnixToString(char *output, size_t remaining_size, - const PARCBuffer *addr) { - parcAssertNotNull(output, "parameter output must be non-null"); - parcBuffer_AssertValid(addr); - - parcAssertTrue(parcBuffer_Remaining(addr) == sizeof(struct sockaddr_un), - "Address corrupted. Expected %zu actual %zu", - sizeof(struct sockaddr_un), parcBuffer_Remaining(addr)); - - // sockaddr length for the path, 16 for the ascii stuff, 3 for the length - // number - struct sockaddr_un *saddr = - (struct sockaddr_un *)parcBuffer_Overlay((PARCBuffer *)addr, 0); - size_t min_remaining = strlen(saddr->sun_path) + 16 + 3; - parcAssertTrue(remaining_size >= min_remaining, - "Remaining size too small, need at least %zu", min_remaining); - - ssize_t output_length = sprintf(output, "{ .path=%s, .len=%zu }", - saddr->sun_path, strlen(saddr->sun_path)); - return output_length; -} - -static ssize_t _IfaceToString(char *output, size_t remaining_size, - const PARCBuffer *addr) { - parcAssertNotNull(output, "parameter output must be non-null"); - parcBuffer_AssertValid(addr); - - parcAssertTrue(parcBuffer_Remaining(addr) == sizeof(uint32_t), - "Address corrupted. Expected %zu actual %zu", sizeof(uint32_t), - parcBuffer_Remaining(addr)); - - uint32_t *ifidx = (uint32_t *)parcBuffer_Overlay((PARCBuffer *)addr, 0); - - ssize_t output_length = sprintf(output, "{ .ifidx=%u }", ntohl(*ifidx)); - - return output_length; -} - -PARCBufferComposer *addressBuildString(const Address *address, - PARCBufferComposer *composer) { - if (address != NULL) { - char *str = addressToString(address); - parcBufferComposer_PutString(composer, str); - parcMemory_Deallocate((void **)&str); - } - return composer; -} - -char *addressToString(const Address *address) { - addressAssertValid(address); - - char addrstr[256]; - - switch (address->addressType) { - case ADDR_INET: { - PARCBufferComposer *composer = parcBufferComposer_Create(); - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer( - _Inet_BuildString(address, composer)); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - parcBufferComposer_Release(&composer); - return result; - } break; - - case ADDR_INET6: { - PARCBufferComposer *composer = parcBufferComposer_Create(); - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer( - _Inet6_BuildString(address, composer)); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - - parcBufferComposer_Release(&composer); - return result; - } break; - - case ADDR_LINK: - _UnixToString(addrstr, 256, address->blob); - break; - - case ADDR_IFACE: { - PARCBufferComposer *composer = parcBufferComposer_Create(); - - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer( - _Link_BuildString(address, composer)); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - - parcBufferComposer_Release(&composer); - return result; - } break; - - case ADDR_UNIX: - _IfaceToString(addrstr, 256, address->blob); - break; - - default: - sprintf(addrstr, "UNKNOWN type = %d", address->addressType); - break; - } - - ssize_t alloc_size = 1024; - char *output = parcMemory_Allocate(alloc_size); - parcAssertNotNull(output, "parcMemory_Allocate(%zu) returned NULL", - alloc_size); - ssize_t output_length = - snprintf(output, alloc_size, "{ .type=%s, .data=%s }", - addressTypeToString(address->addressType), addrstr); - - parcAssertTrue(output_length < alloc_size, - "allocated size too small, needed %zd", output_length); - parcAssertFalse(output_length < 0, "snprintf error: (%d) %s", errno, - strerror(errno)); - - return output; -} - -PARCHashCode addressHashCode(const Address *address) { - addressAssertValid(address); - - PARCHashCode hash = parcBuffer_HashCode(address->blob); - hash = parcHashCode_HashImpl((uint8_t *)&address->addressType, - sizeof(address->addressType), hash); - - return hash; -} diff --git a/hicn-light/src/hicn/utils/address.h b/hicn-light/src/hicn/utils/address.h deleted file mode 100644 index 6ca98347a..000000000 --- a/hicn-light/src/hicn/utils/address.h +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @brief Represents an endpoint address. - * - * Represents an endpoint address. May be INET, INET6, or a multi-byte LINK, - * or an Interface Index. - * - * INET and INET6 must contain the .sa_addr member, and other members as needed - * by the use of the address. - * - * The Interface Index address is essentially a pointer to a device. - * - * - * Example: - * @code - * <#example#> - * @endcode - */ -#ifndef address_h -#define address_h - -#ifndef _WIN32 -#include <netinet/in.h> -#include <sys/un.h> -#endif -#include <stdbool.h> - -#include <parc/algol/parc_Buffer.h> -#include <parc/algol/parc_BufferComposer.h> -#include <hicn/utils/commands.h> - -/** - * Return a string representation of the given `address_type` - * - * @param [in] type A valid address_type value. - * - * @return NULL An error occurred - * @return non-NULL A pointer to a static string representation of the - * `address_type`. - * - * Example: - * @code - * { - * const char *typeAsString = addressTypeToString(commandAddrType_INET); - * } - * @endcode - * - * @see addressStringToType - */ -const char *addressTypeToString(address_type type); - -/** - * Return a `address_type` from the given nul-terminated C string. - * - * @param [in] typeAsString A nul-terminated, C string representation of a - * `address_type`. - * - * @return A address_type - * - * Example: - * @code - * { - * address_type type = addressTypeToString("INET"); - * } - * @endcode - * - * @see addressTypeToString - */ -address_type addressStringToType(const char *typeAsString); - -struct address; -typedef struct address Address; - -/** - * Create a new `Address` instance from an IPv4 IP address, the port is - * optional. - * - * The sockaddr_in should be filled in network byte order. The newly created - * instance must eventually be destroyed by calling {@link addressDestroy}(). - * - * @param [in] addr_in The `sockaddr_in` representing the IPv4 IP address with - * which to initialize the new `Address` instance. - * @return A new instance of `Address` that must eventually be destroyed by - * calling {@link addressDestroy}(). - * - * Example: - * @code - * { - * Address *dest = addressCreateFromInet( - * &(struct sockaddr_in) { - * .sa_addr = - * inet_addr("foo.bar.com"), .sa_port = htons(9695) } ); addressDestroy(&dest); - * } - * @endcode - * @see addressDestroy - */ -Address *addressCreateFromInet(struct sockaddr_in *addr_in); - -/** - * Create a new `Address` instance from an IPv6 IP address, the port is - * optional. - * - * - * The sockaddr_in should be filled in network byte order. The newly created - * instance must eventually be destroyed by calling {@link addressDestroy}(). - * - * @param [in] addr_in6 A `sockaddr_in6` from which to initialize a new instance - * of Address - * @return A new instance of `Address` that must eventually be destroyed by - * calling {@link addressDestroy}() - * - * Example: - * @code - * { - * struct sockaddr_in6 addr_in6; - * memset(&addr_in6, 0, sizeof(struct sockaddr_in6)); - * - * inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr)); - * addr_in6.sin6_family = AF_INET6; - * addr_in6.sin6_port = 0x0A0B; - * addr_in6.sin6_flowinfo = 0x01020304; - * - * Address *address = addressCreateFromInet6(&addr_in6); - * - * addressDestroy(&address); - * } - * @endcode - * @see addressDestroy - */ -Address *addressCreateFromInet6(struct sockaddr_in6 *addr_in6); - -/** - * Convert an internet address family (IPv4) to the address format used by the - * Fwd. - * - * @param [in] addr4 IPV4 address in *Network byte order* - * @param [in] port Port number in *Network byte order* - * - * @return A new instance of `Address` that must eventually be destroyed by - * calling {@link addressDestroy}() - */ -Address *addressFromInaddr4Port(in_addr_t *addr4, in_port_t *port); - -/** - * Convert an internet address family (IPv6) to the address format used by the - * Fwd - * - * @param [in] addr6 IPV4 address in *Network byte order* - * @param [in] port Port number in *Network byte order* - * - * @return A new instance of `Address` that must eventually be destroyed by - * calling {@link addressDestroy}() - */ -Address *addressFromInaddr6Port(struct in6_addr *addr6, in_port_t *port); - -/** - * Create a new `Address` instance, initialized from a Link address. - * - * User must know the link address format (i.e. token ring vs ethernet) and have - * the address in a byte array. The array is encoded in left-to-right order. The - * newly created instance must eventually be destroyed by calling {@link - * addressDestroy}(). - * - * @param [in] linkaddr A byte array containing the link address - * @param [in] length The length of the link address byte array - * @return A new instance of `Address` that must eventually be destroyed by - * calling {@link addressDestroy}() - * - * Example: - * @code - * { - * uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 }; - * Address *address = addressCreateFromLink(mac, sizeof(mac)); - * - * addressDestroy(&address); - * } - * @endcode - * @see addressDestroy - */ -Address *addressCreateFromLink(const uint8_t *linkaddr, size_t length); - -/** - * Create a new `Address` instance from a network interface index. - * - * The interfaceIndex should be in host byte order. The newly created instance - * must eventually be destroyed by calling {@link addressDestroy}(). - * - * @param [in] interfaceIndex The index of the interface to encode - * @return A new instance of `Address` that must eventually be destroyed by - * calling {@link addressDestroy}() - * - * Example: - * @code - * { - * Address *address = addressCreateFromInterface(2); - * - * addressDestroy(&address); - * } - * @endcode - * @see addressDestroy - */ -Address *addressCreateFromInterface(uint32_t interfaceIndex); - -/** - * Create a new Address instance from a PF_UNIX address domain. - * - * The newly created instance must eventually be destroyed by calling {@link - * addressDestroy}(). - * - * @param [in] addr_un The `struct sockaddr_un` specifying the local PF_UNIX - * socket address - * @return A new instance of `Address` that must eventually be destroyed by - * calling {@link addressDestroy}() - * - * Example: - * @code - * { - * struct sockaddr_un addr_unix; - * memset(&addr_unix, 0, sizeof(struct sockaddr_un)); - * char path[] = "/Hello/Cruel/World"; - * strcpy(addr_un.sun_path, path); - * addr_un.sun_family = AF_UNIX; - * - * Address *address = addressCreateFromUnix(&addr_un); - * - * addressDestroy(&address); - * } - * @endcode - * @see addressDestroy - */ -Address *addressCreateFromUnix(struct sockaddr_un *addr_un); - -/** - * Create a deep copy of an instance of a `Address`. A completely new, - * indedependent instance is created. - * - * The newly created instance must eventually be destroyed by calling {@link - * addressDestroy}(). - * - * @param [in] original A pointer to a `Address` instance to be copied. - * @return A new instance of a Address, deep copied from the `original` - * instance. - * - * Example: - * @code - * { - * Address *address = addressCreateFromInterface(2); - * - * Address *copy = addressCopy(address); - * - * addressDestroy(&address); - * addressDestroy(©); - * } - * @endcode - * @see addressDestroy - */ -Address *addressCopy(const Address *original); - -/** - * Deallocate an instance of a Address. - * - * The Address instance is deallocated, and any referenced data is also - * deallocated. The referenced pointer is set to NULL upon return. - * - * @param [in] addressPtr A pointer to a pointer to an instance of Address. - * - * Example: - * @code - * { - * Address *address = addressCreateFromInterface(2); - * - * addressDestroy(&address); - * } - * @endcode - */ -void addressDestroy(Address **addressPtr); - -/** - * Determine if two Address instances are equal. - * - * - * The following equivalence relations on non-null `Address` instances are - * maintained: - * - * * It is reflexive: for any non-null reference value x, `addressEquals(x, x)` - * must return true. - * - * * It is symmetric: for any non-null reference values x and y, - * `addressEquals(x, y)` must return true if and only if - * `addressEquals(y, x)` returns true. - * - * * It is transitive: for any non-null reference values x, y, and z, if - * `addressEquals(x, y)` returns true and - * `addressEquals(y, z)` returns true, - * then `addressEquals(x, z)` must return true. - * - * * It is consistent: for any non-null reference values x and y, multiple - * invocations of `addressEquals(x, y)` consistently return true or - * consistently return false. - * - * * For any non-null reference value x, `addressEquals(x, NULL)` must - * return false. - * - * If one address specifies more information than other, - * e.g. a is INET with a port and b is not, they are not equal. - * - * `a` and `b` may be NULL, and NULL == NULL. - * - * @param a A pointer to a Address instance - * @param b A pointer to a Address instance - * @return true if the two instances are equal - * @return false if the two instances are not equal - * - * Example: - * @code - * { - * Address *address = addressCreateFromInterface(2); - * Address *copy = addressCopy(address); - * - * if (addressEquals(address, copy)) { - * // true - * } else { - * // false - * } - * - * addressDestroy(&address); - * addressDestroy(©); - * } - * @endcode - */ -bool addressEquals(const Address *a, const Address *b); - -/** - * Return the {@link address_type} from a specified Address. - * - * @param [in] A pointer to a Address instance - * - * @return the {@link address_type} of the specified Address instance - * - * Example: - * @code - * { - * Address *address = addressCreateFromInterface(2); - * - * address_type type = addressGetType(address); - * - * addressDestroy(&address); - * } - * @endcode - * - * @see address_type - */ -address_type addressGetType(const Address *address); - -/** - * Fills in the output parameter with an INET address. - * - * @param addr_in must be non-NULL - * @return true if INET address and output filled in, false otherwise. - * - */ -bool addressGetInet(const Address *address, struct sockaddr_in *addr_in); - -/** - * Retrieve the INET6 address associated with a `Address` instance. - * - * If the specified Address instance is of type {@link commandAddrType_INET6}, - * then populate the supplied `struct sockaddr_in6` from the Address and return - * true. If the Address is not of type `commandAddrType_INET6`, this function - * returns false. - * - * @param [in] address A pointer to a `Address` instance of type {@link - * commandAddrType_INET6}. - * @param [in] addr_in6 A pointer to a `struct sockaddr_in6`. Must be non-NULL. - * @return true If the Address instance is of type `commandAddrType_INET6` and - * `addr_in6` was filled in - * @return false If the Address instance was not of type `commandAddrType_INET6` - * or `addr_in6` could not be filled in. - * - * @see addressGetType - */ -bool addressGetInet6(const Address *address, struct sockaddr_in6 *addr_in6); - -/** - * Retrieve the interface index associated with a `Address` instance. - * - * If the specified `Address` instance is of type {@link commandAddrType_IFACE}, - * then populate the supplied `uint32_t` from the Address and return true. If - * the `Address` is not of type `commandAddrType_INET6`, this function returns - * false. - * - * @param [in] address A pointer to a `Address` instance of type {@link - * commandAddrType_IFACE}. - * @param [in] interfaceIndex A pointer to a `uint32_t` to fill in. Must be - * non-NULL. - * @return true If the Address instance is of type `commandAddrType_IFACE` and - * `interfaceIndex` was filled in. - * @return false If the Address instance was not of type `commandAddrType_IFACE` - * or `interfaceIndex` could not be filled in. - * - * @see addressGetType - */ -bool addressGetInterfaceIndex(const Address *address, uint32_t *interfaceIndex); - -/** - * Retrieve the link address associated with a `Address` instance. - * - * If the specified `Address` instance is of type {@link commandAddrType_LINK}, - * then return a pointer to the {@link PARCBuffer} containing the link address. - * If the `Address` is not of type {@link commandAddrType_LINK}, then return - * NULL. The returned PARCBuffer pointer points to memory managed by the Address - * instance, and does not need to be destroyed or released on its own. - * - * @param [in] address A pointer to a `Address` instance of type {@link - * commandAddrType_LINK}. - * @return A pointer to the {@link PARCBuffer} containing the link address. - * - * Example: - * @code - * { - * uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 }; - * Address *address = addressCreateFromLink(mac, sizeof(mac)); - * - * PARCBuffer *macBuffer = addressGetLinkAddress(address); - * - * addressDestroy(&address); - * } - * @endcode - * @see addressGetType - */ -PARCBuffer *addressGetLinkAddress(const Address *address); - -/** - * Append the string representation of a `Address` to a specified - * `PARCBufferComposer`. - * - * @param [in] address A pointer to a `Address` instance. - * @param [in] composer A pointer to a `PARCBufferComposer` instance to which to - * append the string. - * - * @return The `PARCBufferComposer` instance that was passed in. - * - * Example: - * @code - * { - * Address *address = addressCreateFromInterface(1); - * PARCBufferComposer *composer = addressBuildString(address, - * parcBufferComposer_Create()); parcBufferComposer_Release(&composer); - * addressDestroy(&address); - * } - * @endcode - * - * @see PARCBufferComposer - */ -PARCBufferComposer *addressBuildString(const Address *address, - PARCBufferComposer *composer); - -/** - * Produce a nil-terminated string representation of the specified instance. - * - * The result must be freed by the caller via {@link parcMemory_Deallocate}. - * - * @param [in] interest A pointer to the instance. - * - * @return NULL Cannot allocate memory. - * @return non-NULL A pointer to an allocated, nul-terminated C string that must - * be deallocated via {@link parcMemory_Deallocate}(). - * - * Example: - * @code - * { - * Address *address = addressCreateFromInterface(1); - * - * char *string = addressToString(address); - * - * if (string != NULL) { - * printf("Address looks like: %s\n", string); - * parcMemory_Deallocate(string); - * } else { - * printf("Cannot allocate memory\n"); - * } - * - * addressDestroy(&address); - * } - * @endcode - * @see parcMemory_Deallocate - * @see addressBuildString - */ -char *addressToString(const Address *address); - -/** - * Return a non-cryptographic hash code consistent with Equals - * - * If commandAddrA == commandAddrB, then addressHashCode(commandAddrA) == - * addressHashCode(commandAddrB) - * - * @param [in] address A pointer to a Address instance. - * @return A 32-bit hashcode for the specified Address instance. - * - * Example: - * @code - * Address *address = addressCreateFromInterface(1); - * - * uint32_t hashCode = addressHashCode(address); - * - * addressDestroy(&address); - * @endcode - */ -PARCHashCode addressHashCode(const Address *address); -#endif // address_h diff --git a/hicn-light/src/hicn/utils/addressList.c b/hicn-light/src/hicn/utils/addressList.c deleted file mode 100644 index a64fd6f9e..000000000 --- a/hicn-light/src/hicn/utils/addressList.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/assert/parc_Assert.h> - -#include <hicn/utils/addressList.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Buffer.h> -#include <parc/algol/parc_Memory.h> - -struct address_list { - PARCArrayList *listOfAddress; -}; - -static void _addressListFreeAddress(void **addressVoidPtr) { - Address **addressPtr = (Address **)addressVoidPtr; - addressDestroy(addressPtr); -} - -AddressList *addressListCreate() { - AddressList *list = parcMemory_AllocateAndClear(sizeof(AddressList)); - parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(AddressList)); - list->listOfAddress = parcArrayList_Create(_addressListFreeAddress); - parcAssertNotNull(list->listOfAddress, "Got null from parcArrayList_Create"); - - return list; -} - -void addressListDestroy(AddressList **addressListPtr) { - parcAssertNotNull(addressListPtr, - "Parameter must be non-null double pointer"); - parcAssertNotNull(*addressListPtr, - "Parameter must dereference to non-null pointer"); - AddressList *list = *addressListPtr; - - parcArrayList_Destroy(&list->listOfAddress); - parcMemory_Deallocate((void **)&list); - *addressListPtr = NULL; -} - -AddressList *addressListAppend(AddressList *list, Address *address) { - parcAssertNotNull(list, "Parameter list must be non-null"); - parcAssertNotNull(address, "Parameter address must be non-null"); - - parcArrayList_Add(list->listOfAddress, (PARCObject *)address); - return list; -} - -AddressList *addressListCopy(const AddressList *original) { - parcAssertNotNull(original, "Parameter must be non-null"); - - AddressList *copy = addressListCreate(); - for (int i = 0; i < parcArrayList_Size(original->listOfAddress); i++) { - Address *address = (Address *)parcArrayList_Get(original->listOfAddress, i); - parcArrayList_Add(copy->listOfAddress, (PARCObject *)addressCopy(address)); - } - - return copy; -} - -bool addressListEquals(const AddressList *a, const AddressList *b) { - parcAssertNotNull(a, "Parameter a must be non-null"); - parcAssertNotNull(b, "Parameter b must be non-null"); - - if (a == b) { - return true; - } - - if (parcArrayList_Size(a->listOfAddress) != - parcArrayList_Size(b->listOfAddress)) { - return false; - } - - for (size_t i = 0; i < parcArrayList_Size(a->listOfAddress); i++) { - const Address *addr_a = (Address *)parcArrayList_Get(a->listOfAddress, i); - const Address *addr_b = (Address *)parcArrayList_Get(b->listOfAddress, i); - if (!addressEquals(addr_a, addr_b)) { - return false; - } - } - return true; -} - -size_t addressListLength(const AddressList *list) { - parcAssertNotNull(list, "Parameter must be non-null"); - return parcArrayList_Size(list->listOfAddress); -} - -const Address *addressListGetItem(const AddressList *list, size_t item) { - parcAssertNotNull(list, "Parameter must be non-null"); - parcAssertTrue(item < addressListLength(list), - "Asked for item %zu beyond end of list %zu", item, - addressListLength(list)); - - return (Address *)parcArrayList_Get(list->listOfAddress, item); -} - -char *addressListToString(const AddressList *list) { - PARCBufferComposer *composer = parcBufferComposer_Create(); - - for (size_t i = 0; i < addressListLength(list); i++) { - char *addressString = addressToString(addressListGetItem(list, i)); - parcBufferComposer_PutString(composer, addressString); - if (i < (addressListLength(list) - 1)) { - parcBufferComposer_PutString(composer, " "); - } - parcMemory_Deallocate((void **)&addressString); - } - - PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(buffer); - parcBuffer_Release(&buffer); - parcBufferComposer_Release(&composer); - - return result; -} diff --git a/hicn-light/src/hicn/utils/addressList.h b/hicn-light/src/hicn/utils/addressList.h deleted file mode 100644 index 823b0c8cb..000000000 --- a/hicn-light/src/hicn/utils/addressList.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/** - * @brief A list of Address instances. - * - * An AddressList is a list of addresses. - * It wraps a PARCLinkedList for type saftey with Address. - * - */ -#ifndef address_list_h -#define address_list_h - -#include <hicn/utils/address.h> - -struct address_list; -/** - * @typedef AddressList - * @abstract A list of Address instance pointers. - */ -typedef struct address_list AddressList; - -/** - * Create an instance of {@link AddressList} - * - * @return NULL An error occurred - * @return non-NULL A pointer to a valid AddressList instance. - * - * Example: - * @code - * { - * AddressList *list = addressListCreate(); - * - * } - * @endcode - * - * @see addressListDestroy - */ -AddressList *addressListCreate(void); - -/** - * Dellocate and destroy a AddressList instance. - * - * @param [in] addressListPtr A pointer to a pointer to a valid {@link - * AddressList}. - * - * - * Example: - * @code - * { - * AddressList *list = addressListCreate(void); - * addressListDestroy(&list); - * } - * @endcode - * - * @see addressListCreate - */ -void addressListDestroy(AddressList **addressListPtr); - -/** - * Appends the address, taking ownership of the memory - * - * @param list A pointer to a AddressList. - * @param address must be non-null - * @return The input list - * - * Example: - * @code - * <#example#> - * @endcode - */ -AddressList *addressListAppend(AddressList *list, Address *address); - -/** - * Creates a reference counted copy - * - * @param list A pointer to a valid {@link AddressList}. - * - * @return An allocated list, you must destroy it. - * - * Example: - * @code - * <#example#> - * @endcode - */ -AddressList *addressListCopy(const AddressList *list); - -/** - * Determine if two AddressList instances are equal. - * - * Two AddressList instances are equal if, and only if, they have the same - * length, with the same elements in the same order. - * - * - * The following equivalence relations on non-null `AddressList` instances are - * maintained: - * - * * It is reflexive: for any non-null reference value x, - * `AddressList_Equals(x, x)` must return true. - * - * * It is symmetric: for any non-null reference values x and y, - * `AddressList_Equals(x, y)` must return true if and only if - * `addressListEquals(y, x)` returns true. - * - * * It is transitive: for any non-null reference values x, y, and z, if - * `addressListEquals(x, y)` returns true and - * `addressListEquals(y, z)` returns true, - * then `addressListEquals(x, z)` must return true. - * - * * It is consistent: for any non-null reference values x and y, multiple - * invocations of `addressListEquals(x, y)` consistently return true or - * consistently return false. - * - * * For any non-null reference value x, `addressListEquals(x, NULL)` must - * return false. - * - * @param a A pointer to a `AddressList` instance. - * @param b A pointer to a `AddressList` instance. - * @return true if the two `AddressList` instances are equal. - * - * Example: - * @code - * { - * AddressList *a = addressListCreate(); - * AddressList *b = addressListCreate(); - * - * if (addressListEquals(a, b)) { - * // true - * } else { - * // false - * } - * } - * @endcode - */ -bool addressListEquals(const AddressList *a, const AddressList *b); - -/** - * Get the number of items in the list - * - * @param list A pointer to a {@link AddressList}. - * @return The number of items in the list. - * - * Example: - * @code - * <#example#> - * @endcode - */ -size_t addressListLength(const AddressList *list); - -/** - * Returns a const reference to an item. - * Use addressCopy if needed. - * - * Do not free or modify the returned value. - * Use addressCopy if you need a mutable instance. - * - * @param list A pointer to a AddressList. - * @param item A value less than the number of items in the given {@link - * AddressList}. - * @return Asserts if item off end of list. - * - * Example: - * @code - * <#example#> - * @endcode - */ -const Address *addressListGetItem(const AddressList *list, size_t item); - -/** - * Get a nul-terminated, C-string representation of the given {@link - * AddressList}. - * - * @param list A pointer to a valid {@link AddressList} instance. - * - * @return An allocate string representation of the {@link AddressList} that - * must be freed via `parcMemory_Deallocate()`. - * - * Example: - * @code - * <#example#> - * @endcode - */ -char *addressListToString(const AddressList *list); -#endif // address_list_h diff --git a/hicn-light/src/hicn/utils/commands.h b/hicn-light/src/hicn/utils/commands.h deleted file mode 100644 index 3758f0f41..000000000 --- a/hicn-light/src/hicn/utils/commands.h +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (c) 2017-2019 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. - */ - -/* - * @file commands.h - * @brief All hicn-light commands: 14 in total. - * - * Header and payload in binary format. - */ - -#ifndef commands_h -#define commands_h - -#ifndef _WIN32 -#include <netinet/in.h> -#include <sys/socket.h> -#endif - -#include <stdint.h> -#include <stdlib.h> - -#include <hicn/util/ip_address.h> -#ifdef WITH_POLICY -#include <hicn/policy.h> -#endif /* WITH_POLICY */ - -#define SYMBOLIC_NAME_LEN 16 -#define MAX_FWD_STRATEGY_RELATED_PREFIXES 10 - -typedef struct in6_addr ipv6_addr_t; -typedef uint32_t ipv4_addr_t; - -typedef enum { - REQUEST_LIGHT = 0xc0, // this is a command - RESPONSE_LIGHT, - ACK_LIGHT, - NACK_LIGHT, - LAST_MSG_TYPE_VALUE -} message_type; - -typedef enum { - ADD_LISTENER = 0, - ADD_CONNECTION, - LIST_CONNECTIONS, - ADD_ROUTE, - LIST_ROUTES, - REMOVE_CONNECTION, - REMOVE_LISTENER, - REMOVE_ROUTE, - CACHE_STORE, - CACHE_SERVE, - CACHE_CLEAR, - SET_STRATEGY, - SET_WLDR, - ADD_PUNTING, - LIST_LISTENERS, - MAPME_ENABLE, - MAPME_DISCOVERY, - MAPME_TIMESCALE, - MAPME_RETX, - MAPME_SEND_UPDATE, - CONNECTION_SET_ADMIN_STATE, -#ifdef WITH_POLICY - ADD_POLICY, - LIST_POLICIES, - REMOVE_POLICY, - UPDATE_CONNECTION, - CONNECTION_SET_PRIORITY, - CONNECTION_SET_TAGS, -#endif /* WITH_POLICY */ - LAST_COMMAND_VALUE -} command_id; - -typedef enum { - ADDR_INET = 1, - ADDR_INET6, - ADDR_LINK, - ADDR_IFACE, - ADDR_UNIX /* PF_UNIX */ -} address_type; - -typedef enum { - UDP_CONN, - TCP_CONN, - GRE_CONN, // not implemented - HICN_CONN -} connection_type; - -typedef enum { ACTIVATE_ON, ACTIVATE_OFF } activate_type; - -//========== HEADER ========== - -typedef struct { - uint8_t messageType; - uint8_t commandID; - uint16_t length; // tells the number of structures in the payload - uint32_t seqNum; -} header_control_message; -// for the moment has to be at least 8 bytes - -// SIZE=8 - -//========== [00] ADD LISTENER ========== - -typedef enum { ETHER_MODE, IP_MODE, HICN_MODE } listener_mode; - -typedef struct { - char symbolic[SYMBOLIC_NAME_LEN]; - char interfaceName[SYMBOLIC_NAME_LEN]; - ip_address_t address; - uint16_t port; - // uint16_t etherType; - uint8_t addressType; - uint8_t listenerMode; - uint8_t connectionType; -} add_listener_command; - -// SIZE=56 - -//========== [01] ADD CONNECTION ========== - -typedef struct { - char symbolic[SYMBOLIC_NAME_LEN]; - //char interfaceName[SYMBOLIC_NAME_LEN]; - ip_address_t remoteIp; - ip_address_t localIp; - uint16_t remotePort; - uint16_t localPort; - uint8_t ipType; - uint8_t connectionType; - uint8_t admin_state; -#ifdef WITH_POLICY - uint32_t priority; - policy_tags_t tags; -#endif /* WITH_POLICY */ -} add_connection_command; - -// SIZE=56 - -//========== [02] LIST CONNECTIONS ========== - -typedef enum { - CONN_GRE, - CONN_TCP, - CONN_UDP, - CONN_MULTICAST, - CONN_L2, - CONN_HICN -} list_connections_type; - -typedef enum { - IFACE_UP = 0, - IFACE_DOWN = 1, - IFACE_UNKNOWN = 2 // not used actually -} connection_state; - -typedef struct { - add_connection_command connectionData; - uint32_t connid; - uint8_t state; - char interfaceName[SYMBOLIC_NAME_LEN]; - char connectionName[SYMBOLIC_NAME_LEN]; -} list_connections_command; - -// SIZE=80 - -//========== [03] ADD ROUTE ========== - -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - ip_address_t address; - uint16_t cost; - uint8_t addressType; - uint8_t len; -} add_route_command; - -// SIZE=36 - -//========== [04] LIST ROUTE ========== - -typedef struct { - ip_address_t address; - uint32_t connid; - uint16_t cost; - uint8_t addressType; - uint8_t len; -} list_routes_command; - -// SIZE=24 - -//========== [05] REMOVE CONNECTION ========== -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; -} remove_connection_command; - -//========== [06] REMOVE LISTENER ========== -typedef struct { - char symbolicOrListenerid[SYMBOLIC_NAME_LEN]; -} remove_listener_command; - -// SIZE=16 - -//========== [07] REMOVE ROUTE ========== - -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - ip_address_t address; - uint8_t addressType; - uint8_t len; -} remove_route_command; - -// SIZE=36 - -//========== [08] CACHE STORE ========== - -typedef struct { - uint8_t activate; -} cache_store_command; - -// SIZE=1 - -//========== [09] CACHE SERVE ========== - -typedef struct { - uint8_t activate; -} cache_serve_command; - -// SIZE=1 - -//========== [10] SET STRATEGY ========== - -typedef enum { - SET_STRATEGY_LOADBALANCER, - SET_STRATEGY_RANDOM, - SET_STRATEGY_LOW_LATENCY, - LAST_STRATEGY_VALUE -} strategy_type; - -typedef struct { - ip_address_t address; - uint8_t strategyType; - uint8_t addressType; - uint8_t len; - uint8_t related_prefixes; - ip_address_t addresses[MAX_FWD_STRATEGY_RELATED_PREFIXES]; - uint8_t lens[MAX_FWD_STRATEGY_RELATED_PREFIXES]; - uint8_t addresses_type[MAX_FWD_STRATEGY_RELATED_PREFIXES]; -} set_strategy_command; - -// SIZE=208 - -//========== [11] SET WLDR ========== - -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - uint8_t activate; -} set_wldr_command; - -// SIZE=17 - -//========== [12] ADD PUNTING ========== - -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - ip_address_t address; - uint8_t addressType; - uint8_t len; -} add_punting_command; - -// SIZE=36 - -//========== [13] LIST LISTENER ========== - -typedef struct { - ip_address_t address; - char listenerName[SYMBOLIC_NAME_LEN]; - char interfaceName[SYMBOLIC_NAME_LEN]; - uint32_t connid; - uint16_t port; - uint8_t addressType; - uint8_t encapType; -} list_listeners_command; - -// SIZE=56 - -//========== [14] MAPME ========== - -// (enable/discovery/timescale/retx) - -typedef struct { - uint8_t activate; -} mapme_activator_command; - -// SIZE=1 - -typedef struct { - uint32_t timePeriod; -} mapme_timing_command; - -typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; -} mapme_send_update_command; - -// SIZE=1 - -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - uint8_t admin_state; - uint8_t pad8[3]; -} connection_set_admin_state_command; - -#ifdef WITH_POLICY - -typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; - hicn_policy_t policy; -} add_policy_command; - -typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; - hicn_policy_t policy; -} list_policies_command; - -typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; -} remove_policy_command; - -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - uint8_t admin_state; - uint32_t priority; - policy_tags_t tags; -} update_connection_command; - -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - uint32_t priority; -} connection_set_priority_command; - -typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - policy_tags_t tags; -} connection_set_tags_command; - -#endif /* WITH_POLICY */ - -//===== size of commands ====== -// REMINDER: when a new_command is added, the following switch has to be -// updated. -static inline int payloadLengthDaemon(command_id id) { - switch (id) { - case ADD_LISTENER: - return sizeof(add_listener_command); - case ADD_CONNECTION: - return sizeof(add_connection_command); - case LIST_CONNECTIONS: - return 0; // list connections: payload always 0 - case ADD_ROUTE: - return sizeof(add_route_command); - case LIST_ROUTES: - return 0; // list routes: payload always 0 - case REMOVE_CONNECTION: - return sizeof(remove_connection_command); - case REMOVE_LISTENER: - return sizeof(remove_listener_command); - case REMOVE_ROUTE: - return sizeof(remove_route_command); - case CACHE_STORE: - return sizeof(cache_store_command); - case CACHE_SERVE: - return sizeof(cache_serve_command); - case CACHE_CLEAR: - return 0; // cache clear - case SET_STRATEGY: - return sizeof(set_strategy_command); - case SET_WLDR: - return sizeof(set_wldr_command); - case ADD_PUNTING: - return sizeof(add_punting_command); - case LIST_LISTENERS: - return 0; // list listeners: payload always 0 - case MAPME_ENABLE: - return sizeof(mapme_activator_command); - case MAPME_DISCOVERY: - return sizeof(mapme_activator_command); - case MAPME_TIMESCALE: - return sizeof(mapme_timing_command); - case MAPME_RETX: - return sizeof(mapme_timing_command); - case MAPME_SEND_UPDATE: - return sizeof(mapme_send_update_command); - case CONNECTION_SET_ADMIN_STATE: - return sizeof(connection_set_admin_state_command); -#ifdef WITH_POLICY - case ADD_POLICY: - return sizeof(add_policy_command); - case LIST_POLICIES: - return 0; // list policies: payload always 0 - case REMOVE_POLICY: - return sizeof(remove_policy_command); - case UPDATE_CONNECTION: - return sizeof(update_connection_command); - case CONNECTION_SET_PRIORITY: - return sizeof(connection_set_priority_command); - case CONNECTION_SET_TAGS: - return sizeof(connection_set_tags_command); -#endif /* WITH_POLICY */ - case LAST_COMMAND_VALUE: - return 0; - default: - return 0; - } -} -#endif diff --git a/hicn-light/src/hicn/utils/interface.c b/hicn-light/src/hicn/utils/interface.c index d8597f3ed..c3f8793a4 100644 --- a/hicn-light/src/hicn/utils/interface.c +++ b/hicn-light/src/hicn/utils/interface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -22,12 +22,14 @@ #include <parc/algol/parc_BufferComposer.h> #include <parc/algol/parc_Memory.h> #include <parc/algol/parc_Object.h> -#include <hicn/utils/addressList.h> +//#include <hicn/utils/addressList.h> #include <hicn/utils/interface.h> #include <parc/assert/parc_Assert.h> #include <hicn/utils/commands.h> +#if 0 + struct interface { char *name; unsigned interfaceIndex; @@ -166,3 +168,5 @@ unsigned interfaceGetMTU(const Interface *iface) { parcAssertNotNull(iface, "Parameter iface must be non-null"); return iface->mtu; } + +#endif diff --git a/hicn-light/src/hicn/utils/interface.h b/hicn-light/src/hicn/utils/interface.h index fd91edb1d..365624e4a 100644 --- a/hicn-light/src/hicn/utils/interface.h +++ b/hicn-light/src/hicn/utils/interface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -22,8 +22,7 @@ #ifndef interface_h #define interface_h -#include <hicn/utils/address.h> -#include <hicn/utils/addressList.h> +#include <hicn/core/address.h> struct interface; typedef struct interface Interface; @@ -59,7 +58,7 @@ void interfaceDestroy(Interface **interfacePtr); * <#example#> * @endcode */ -void interfaceAddAddress(Interface *iface, Address *address); +void interfaceAddAddress(Interface *iface, address_t *address); /** * Retrieves a list of interface addresses @@ -74,7 +73,7 @@ void interfaceAddAddress(Interface *iface, Address *address); * <#example#> * @endcode */ -const AddressList *interfaceGetAddresses(const Interface *iface); +const address_t **interfaceGetAddresses(const Interface *iface); /** * The interface index diff --git a/hicn-light/src/hicn/utils/interfaceSet.c b/hicn-light/src/hicn/utils/interfaceSet.c index 3ae52bb80..e06643fc7 100644 --- a/hicn-light/src/hicn/utils/interfaceSet.c +++ b/hicn-light/src/hicn/utils/interfaceSet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: diff --git a/hicn-light/src/hicn/utils/interfaceSet.h b/hicn-light/src/hicn/utils/interfaceSet.h index e43f985fe..6723bc493 100644 --- a/hicn-light/src/hicn/utils/interfaceSet.h +++ b/hicn-light/src/hicn/utils/interfaceSet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: diff --git a/hicn-light/src/hicn/utils/punting.c b/hicn-light/src/hicn/utils/punting.c index 8f33cf763..60a8d2355 100644 --- a/hicn-light/src/hicn/utils/punting.c +++ b/hicn-light/src/hicn/utils/punting.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -13,6 +13,7 @@ * limitations under the License. */ +#if 0 #include <hicn/hicn-light/config.h> #include <stdio.h> @@ -23,11 +24,11 @@ struct punting { char *symbolic; - Address *prefix; + address_t *prefix; uint32_t len; }; -Punting *puntingCreate(const char *listenerName, Address *prefix, +Punting *puntingCreate(const char *listenerName, address_t *prefix, uint32_t len) { parcAssertNotNull(listenerName, "Parameter listenerName must be non-null"); parcAssertNotNull(prefix, "Parameter prefix must be non-null"); @@ -87,7 +88,7 @@ const char *puntingGetSymbolicName(const Punting *punting) { return punting->symbolic; } -Address *puntingGetAddress(const Punting *punting) { +address_t * puntingGetAddress(const Punting *punting) { parcAssertNotNull(punting, "Parameter listener must be non-null"); return punting->prefix; } @@ -96,3 +97,4 @@ uint32_t puntingPrefixLen(const Punting *punting) { parcAssertNotNull(punting, "Parameter listener must be non-null"); return punting->len; } +#endif diff --git a/hicn-light/src/hicn/utils/punting.h b/hicn-light/src/hicn/utils/punting.h index 9be1baed4..46cec8a91 100644 --- a/hicn-light/src/hicn/utils/punting.h +++ b/hicn-light/src/hicn/utils/punting.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -16,10 +16,21 @@ #ifndef punting_h #define punting_h +#include <hicn/core/address.h> + +typedef struct { + char *symbolic; + address_t prefix; + uint32_t len; +} punting_t; + +#define punting_address(punting) (&((punting)->prefix)) +#define punting_len(punting) ((punting)->len) + +#if 0 struct punting; typedef struct punting Punting; -#include <hicn/utils/address.h> /** * Creates a Punting object @@ -36,7 +47,7 @@ typedef struct punting Punting; * @return null An error * */ -Punting *puntingCreate(const char *symbolic, Address *prefix, uint32_t len); +Punting *puntingCreate(const char *symbolic, address_t *prefix, uint32_t len); /** * Releases a reference count to the object @@ -66,7 +77,9 @@ const char *puntingGetSymbolicName(const Punting *punting); * Returns the address (INET or INET6 ip address) * */ -Address *puntingGetAddress(const Punting *punting); +address_t * puntingGetAddress(const Punting *punting); uint32_t puntingPrefixLen(const Punting *punting); +#endif + #endif // punting_h diff --git a/hicn-light/src/hicn/utils/token.h b/hicn-light/src/hicn/utils/token.h index 43e0a77b2..138916f31 100644 --- a/hicn-light/src/hicn/utils/token.h +++ b/hicn-light/src/hicn/utils/token.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -19,7 +19,7 @@ * Concatenate preprocessor tokens A and B without expanding macro definitions * (however, if invoked from a macro, macro arguments are expanded). */ -#define PPCAT_NX(A, B) A ## B +#define PPCAT_NX(A, B) A##B /* * Concatenate preprocessor tokens A and B after macro-expanding them. diff --git a/hicn-light/src/hicn/utils/utils.c b/hicn-light/src/hicn/utils/utils.c deleted file mode 100644 index 36596f943..000000000 --- a/hicn-light/src/hicn/utils/utils.c +++ /dev/null @@ -1,235 +0,0 @@ -// Utility function for commands - -#ifndef _WIN32 -#include <netinet/in.h> -#endif - -#include <ctype.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> -#include <pthread.h> -#include <hicn/utils/utils.h> - -// This is the unique sequence number used by all messages and its thread locks -static pthread_mutex_t nextSequenceNumberMutex = PTHREAD_MUTEX_INITIALIZER; -static uint32_t nextSequenceNumber = 1; - -uint32_t utils_GetNextSequenceNumber(void) { - uint32_t seqnum; - - int result = pthread_mutex_lock(&nextSequenceNumberMutex); - parcAssertTrue(result == 0, "Got error from pthread_mutex_lock: %d", result); - - seqnum = nextSequenceNumber++; - - result = pthread_mutex_unlock(&nextSequenceNumberMutex); - parcAssertTrue(result == 0, "Got error from pthread_mutex_unlock: %d", - result); - - return seqnum; -} - -/** - * Return true if string is purely an integer - */ -bool utils_IsNumber(const char *string) { - size_t len = strlen(string); - for (size_t i = 0; i < len; i++) { - if (!isdigit(string[i])) { - return false; - } - } - return true; -} - -/** - * A symbolic name must be at least 1 character and must begin with an alpha. - * The remainder must be an alphanum. - */ -bool utils_ValidateSymbolicName(const char *symbolic) { - bool success = false; - size_t len = strlen(symbolic); - if (len > 0) { - if (isalpha(symbolic[0])) { - success = true; - for (size_t i = 1; i < len; i++) { - if (!isalnum(symbolic[i])) { - success = false; - break; - } - } - } - } - return success; -} - -struct iovec *utils_CreateAck(header_control_message *header, void *payload, - size_t payloadLen) { - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); - - header->messageType = ACK_LIGHT; - - response[0].iov_base = header; - response[0].iov_len = sizeof(header_control_message); - response[1].iov_base = payload; - response[1].iov_len = payloadLen; - - return response; -} - -struct iovec *utils_CreateNack(header_control_message *header, void *payload, - size_t payloadLen) { - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); - - header->messageType = NACK_LIGHT; - response[0].iov_base = header; - response[0].iov_len = sizeof(header_control_message); - response[1].iov_base = payload; - response[1].iov_len = payloadLen; - - return response; -} - -char *utils_BuildStringFromInet(in_addr_t *addr4, in_port_t *port) { - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = *port; - addr.sin_addr.s_addr = *addr4; - - PARCBufferComposer *composer = parcBufferComposer_Create(); - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer( - parcNetwork_SockInet4Address_BuildString(&addr, composer)); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - parcBufferComposer_Release(&composer); - return result; -} - -char *utils_BuildStringFromInet6(struct in6_addr *addr6, in_port_t *port) { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = *port; - addr.sin6_addr = *addr6; - - PARCBufferComposer *composer = parcBufferComposer_Create(); - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer( - parcNetwork_SockInet6Address_BuildString(&addr, composer)); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - parcBufferComposer_Release(&composer); - return result; -} - -char *utils_CommandAddressToString(address_type addressType, - ip_address_t *address, - in_port_t *port) { - char *result; - - switch (addressType) { - case ADDR_INET: { - result = utils_BuildStringFromInet(&address->v4.as_u32, port); - break; - } - - case ADDR_INET6: { - result = utils_BuildStringFromInet6(&address->v6.as_in6addr, port); - break; - } - - default: { - char *addrStr = (char *)parcMemory_Allocate(sizeof(char) * 32); - sprintf(addrStr, "Error: UNKNOWN address type = %d", addressType); - result = addrStr; - break; - } - } - return result; -} - -struct iovec *utils_SendRequest(ControlState *state, command_id command, - void *payload, size_t payloadLen) { - bool success = false; - - // get sequence number for the header - uint32_t currentSeqNum = utils_GetNextSequenceNumber(); - - // Allocate and fill the header - header_control_message *headerControlMessage = - parcMemory_AllocateAndClear(sizeof(header_control_message)); - headerControlMessage->messageType = REQUEST_LIGHT; - headerControlMessage->commandID = command; - headerControlMessage->seqNum = currentSeqNum; - if (payloadLen > 0) { - headerControlMessage->length = 1; - } - - struct iovec msg[2]; - msg[0].iov_base = headerControlMessage; - msg[0].iov_len = sizeof(header_control_message); - msg[1].iov_base = payload; - msg[1].iov_len = payloadLen; - - struct iovec *response = controlState_WriteRead(state, msg); - - header_control_message *receivedHeader = - (header_control_message *)response[0].iov_base; - if (receivedHeader->seqNum != currentSeqNum) { - printf("Seq number is NOT correct: expected %d got %d \n", currentSeqNum, - receivedHeader->seqNum); - // failure - } else { - if (receivedHeader->messageType == RESPONSE_LIGHT) { - return response; // command needs both payload and header - } else { - if (receivedHeader->messageType == ACK_LIGHT) { - success = true; - } else if (receivedHeader->messageType == NACK_LIGHT) { - success = true; - } else { - printf("Error: unrecognized message type"); // failure - } - } - } - - // deallocate when payload & header of the response are not needed - if (receivedHeader->length > 0) { - parcMemory_Deallocate(&response[1].iov_base); // free received payload - } - parcMemory_Deallocate(&response[0].iov_base); // free receivedHeader - - // return response - if (success) { - return response; - } else { - parcMemory_Deallocate(&response); // free iovec pointer - return NULL; // will generate a failure - } -} - -const char *utils_PrefixLenToString(address_type addressType, - ip_address_t *address, - uint8_t *prefixLen) { - char len[4]; // max size + 1 - sprintf(len, "%u", (unsigned)*prefixLen); - in_port_t port = htons(1234); // this is a random port number that is ignored - - char *prefix = utils_CommandAddressToString(addressType, address, &port); - char *prefixStr = malloc(strlen(prefix) + strlen(len) + 2); - strcpy(prefixStr, prefix); - strcat(prefixStr, "/"); - strcat(prefixStr, len); - - free(prefix); - - return prefixStr; -} diff --git a/hicn-light/src/hicn/utils/utils.h b/hicn-light/src/hicn/utils/utils.h deleted file mode 100644 index 1fe88e62c..000000000 --- a/hicn-light/src/hicn/utils/utils.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2017-2019 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 utils_h -#define utils_h - -#include <hicn/config/controlState.h> -#include <hicn/utils/address.h> -#include <hicn/utils/commands.h> - -/** - * Return true if string is purely an integer - */ -bool utils_IsNumber(const char *string); - -/** - * A symbolic name must be at least 1 character and must begin with an alpha. - * The remainder must be an alphanum. - */ -bool utils_ValidateSymbolicName(const char *symbolic); - -/** - *Create an Ack message instance as a response of a control successfully - *completed. - */ -struct iovec *utils_CreateAck(header_control_message *header, void *payload, - size_t payloadLen); - -/** - *Create a Nack message instance as a response of a control unsuccessfully - *completed. - */ -struct iovec *utils_CreateNack(header_control_message *header, void *payload, - size_t payloadLen); - -/** - *Convert IPv4/IPv6 address from binary to text string. `uint8_t *ipAddress` has - *to be a `in_addr_t * or `a struct in6_addr *. - */ -char *utils_CommandAddressToString(address_type addressType, - ip_address_t *address, in_port_t *port); - -/** - *Given a command payload, it generates the header and send the request to the - *deamon. - */ -struct iovec *utils_SendRequest(ControlState *state, command_id command, - void *payload, size_t payloadLen); - -/** - *Convert a IPv4/IPv6 address plus Netmask len from binary to text string in the - *form [add]:[port]/[len]. - */ -const char *utils_PrefixLenToString(address_type addressType, - ip_address_t *address, - uint8_t *prefixLen); - -#endif |